I'm making an app widget for Android, which due to being composed of custom elements such as graphs, must be rendered as a bitmap.
However, I've run into a few snags in the process.
1) Is there any way to find the maximum available space for an app widget? (OR: Is it possible to calculate the dimensions correctly for the minimum space available in WVGA (or similar wide) cases?
I don't know how to calculate the maximum available space for an app widget. With a conventional app widget it is possible to fill_parent, and all the space will be used. However, when rendering the widget as a bitmap, and to avoid stretching, the correct dimensions must be calculated. The documentation outlines how to calculate the minimum dimensions, but for cases such as WVGA, there will be unused space in landscape mode - causing the widget to look shorter than other widgets which stretch naturally.
float density = getResources().getDisplayMetrics().density;
int cx = ((int)Math.ceil(appWidgetInfo.minWidth / density) + 2) / 74;
int cy = ((int)Math.ceil(appWidgetInfo.minHeight / density) + 2) / 74;
int portraitWidth = (int)Math.round((80.0f * cx - 2.0f) * density);
int portraitHeight = (int)Math.round((100.0f * cy - 2.0f) * density);
int landscapeWidth = (int)Math.round((106.0f * cx - 2.0f) * density);
int landscapeHeight = (int)Math.round((74.0f * cy - 2.0f) * density);
Calculating cx and cy gives the number of horizontal and vertical cells. Subtracting - 2 from the calculated dpi (e.g. 74 * cy - 2) is to avoid cases where the resulting number of pixels is 开发者_开发技巧rounded down. (For example in landscape mode on Nexus One, the height is 110, not 111 (74 * 1.5).
2) When assigning a bitmap to an ImageView which is used as part of the RemoteViews to view the image, there are 2 methods:
2.1) By using setImageViewUri, and saving the bitmap to a PNG file. The image is then served using an openFile() implementation in a ContentProvider:
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
// Code to set up imageFileName
File file = new File(getContext().getCacheDir(), imageFileName);
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
This works, and it's the approach I'm currently using. However, if I set the scaleType of the ImageView to "center", which by the documentation is supposed to "Center the image in the view, but perform no scaling.", the image is incorrectly scaled. Setting the density of the bitmap to DENSITY_NONE or getResources().getDisplayMetrics().densityDpi doesn't make any difference when saving the bitmap to PNG, it seems to be ignored when the file is loaded by the ImageView. The result is that the image is scaled down, due to some dpi issue. This seems to describe the case:
http://code.google.com/p/android/issues/detail?id=6957&can=1&q=widget%20size&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
Because it is not possible to use scaleType:center, the only way I've found to work is to set the layout_width and layout_height of the ImageView statically to a given number of dpis, then rendering the bitmap to the same dpi. This requires the use of scaleType:fitXY. This approach works, but it is a very static setup - and it will not work for resizable 3.1 app widgets (I haven't tested this yet, but unless onUpdate() is called on each resize, this is true).
Is there any way to load an image to an ImageView unscaled, or is this impossible due to a bug in the framework?
2.1) By using setImageViewBitmap directly. Using this method with the Bitmap.DENSITY_NONE setting on the bitmap, the image can be shown without scaling correctly. The problem with this approach is that there is a limitation to how large images can be set through the IPC mechanism:
http://groups.google.com/group/android-developers/browse_thread/thread/e8d84920b999291f/d12eb1d0eaca93ac#01d5c89e5e7b4060
(not allowed more links)http://groups.google.com/group/android-developers/browse_thread/thread/b11550601e6b1dd3#4bef4fa8908f7e6a
I attempting a bit of a hack to get past this issue, by splitting the widget into a matrix of images which could be set in 100x100 pixel blocks. This did allow for larger widgets to work, but ended up being very heavy and failed on large widgets (4x4).
Sorry for a very long post. I've tried to explain a few of the different issues when attempting to use a bitmap rendered app widget. If anyone has attempted the same and have found any more solutions to these issues, or have any helpful comments, this will be highly appreciated.
An approach that worked for us for a similar situation was to generate our graph as a 9-patch png, with the actual graph part as the scalable central rectangle, and the caption text and indication icons (which we did not want all stretched out of shape) and border effects, placed on the outer rectangles of the image.
精彩评论