1. 程式人生 > >android 桌面小部件(App Widgets)如何顯示自定義的view

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

寫過 桌面小部件的同學都知道,由於小部件是在在部件載入的,所以支援的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 , 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://

但是FileProvider有個問題,他需要臨時授權後,其他應用才能使用,但是AppWidgets的方式造成它無法臨時授權桌面應用。

這個問題我找了半天,終於找到了一個方法,見:


最終的效果如圖:下面2條奇怪的V線就是畫的:


老樣子,完整程式碼請訪問

程式碼在utils.bobo.com.boboutils.App.appwidget包內

歡迎大家提出意見。大家可以通過QQ群,或者微信公眾號交流: