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
2: 生成所需的圖片<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>
這邊提供一個示例的方法,生成圖片有很多種方法,只要能生成圖片即可
3:將圖片uri設定給imageview,然後更新appwidgetprivate 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; }
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群,或者微信公眾號交流: