android 桌面小部件(App Widgets)如何显示自定义的view

来源:互联网 发布:mysql 查询语句 编辑:程序博客网 时间:2024/05/21 06:24

写过 桌面小部件的同学都知道,由于小部件是在在部件加载的,所以支持的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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#09C"    android:padding="@dimen/widget_margin">    <TextView        android:id="@+id/appwidget_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_margin="8dp"        android:background="#09C"        android:contentDescription="@string/appwidget_text"        android:text="@string/appwidget_text"        android:textColor="#ffffff"        android:textSize="14sp"        android:textStyle="bold|italic" />    <ImageView        android:id="@+id/appwidget_image"        android:layout_below="@+id/appwidget_text"        android:layout_centerHorizontal="true"        android:layout_margin="8dp"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></RelativeLayout>
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的方式造成它无法临时授权桌面应用。

这个问题我找了半天,终于找到了一个方法,见:

http://android.wekeepcoding.com/article/13447169/Android%3A+loading+bitmap+from+local+storage+into+app+widget+(RemoteViews)


最终的效果如图:下面2条奇怪的V线就是画的:



老样子,完整代码请访问

https://github.com/bobohuang1985/android-utils-api 

代码在utils.bobo.com.boboutils.App.appwidget包内


欢迎大家提出意见。大家可以通过QQ群,或者微信公众号交流: