写过 桌面小部件的同学都知道,由于小部件是在在部件加载的,所以支持的view比较有限,用官方的原话说就是
Creating the App Widget layout is simple if you're familiar with Layouts. However, you must be aware that App Widget layouts are based on RemoteViews
, which do not support every kind of layout or view widget.
那怎么在小部件上显示一些比较复杂的view呢? 通过正统的路径肯定是不行了,除非你能改到rom,但是是通过改rom来实现,就会造成这个应用在其他机器上就无法正常运行了。
其实还有一个方法可以实现,就是。。。。。。。。。。一句话:
将要显示的view画在一张图片上,然后将图片设置给ImageView
废话不多说,用代码说话:
1:首先创建一个AppWidgets,这个网上代码很多。如果还不清楚的直接看
https://developer.android.com/guide/topics/appwidgets/index.html
2:修改AppWidgets布局文件,在合适的地方加入一个ImageView
2: 生成所需的图片
这边提供一个示例的方法,生成图片有很多种方法,只要能生成图片即可
private void handleActionUpdateAppWidget() {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
ComponentName thisWidget = new ComponentName(this, CustomViewAppWidget.class);
int ids[] = appWidgetManager.getAppWidgetIds(thisWidget);
if (ids == null || ids.length <= 0) {
return;
}
int width = this.getResources().getDimensionPixelSize(R.dimen.custom_app_widget_image_width);
int height = this.getResources().getDimensionPixelSize(R.dimen.custom_app_widget_image_height);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(getResources().getColor(R.color.custom_app_widget_line_color));
paint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.custom_app_widget_line_width));
canvas.drawLine(0, 0, width / 2, height, paint);
canvas.drawLine(width / 2, height, width, 0, paint);
String path = saveBitmapToPic(this, "customview.png", bitmap);
}
private String saveBitmapToPic(Context context, String name, Bitmap b) {
if (b == null) {
return null;
}
context.deleteFile(name);
FileOutputStream fos = null;
try {
fos = context.openFileOutput(name, Context.MODE_PRIVATE);
//fos = new FileOutputStream(screenShotFile,Context.MODE_WORLD_READABLE);
if (null != fos) {
b.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
return context.getFilesDir() + "/" + name;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3:将图片uri设置给imageview,然后更新appwidget
File newFile = new File(path);
Uri imageUri = CustomViewFileProvider.getUriForFile(this, CustomViewFileProvider.AUTHORITIES, newFile);
CharSequence widgetText = getString(R.string.appwidget_text);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(getPackageName(), R.layout.custom_view_app_widget);
views.setTextViewText(R.id.appwidget_text, widgetText);
views.setImageViewUri(R.id.appwidget_image, imageUri);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(thisWidget, views);
这边顺便说2个问题:
1:有的同学会问:为什么不将图片的bitmap直接设置给ImageView?
答:因为bitmap通常比较大,RemoteViews在传输过程中其实是要挂进程传输的,系统用来跨进程传输的内存空间有限。如果bitmap的大小大于剩余空间的话,会造成AppWidget更新失败。
2:Android 7.0后,跨应用传递 file://
的URI,会异常,官方推荐使用FileProvider
。
但是FileProvider有个问题,他需要临时授权后,其他应用才能使用,但是AppWidgets的方式造成它无法临时授权桌面应用。
这个问题我找了半天,终于找到了一个方法,见:
最终的效果如图:下面2条奇怪的V线就是画的:
老样子,完整代码请访问
https://github.com/bobohuang1985/android-utils-api
代码在utils.bobo.com.boboutils.App.appwidget包内