控件
widget支持的控件有限
根布局
A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:
FrameLayout
LinearLayout
RelativeLayout
控件
And the following widget classes:
AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper
WidgetOptions
res/xml/widget_desktop_options.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="110dp"
android:minHeight="40dp"
android:previewImage="@mipmap/zg_widget"
android:initialLayout="@layout/widget_desktop"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen">
</appwidget-provider>
minHeight、minWidth 定义Widget的最小高度和最小宽度(Widget可以通过拉伸来调整尺寸大小)
-
尺寸大小最终以单元格数据来显示,但定义时为 dp
-
单元格数转换基本工式 size = 70 x cells - 30
-
如:1格 = 70 x 1 - 30 = 40dp
-
最小尺寸定义时最好不要超过 4 个单元格就是 250dp
previewImage 定义添加小部件时显示的图标
updatePeriodMillis 定义小部件自动更新的周期,单位为毫秒,即间隔多少时间呼叫一次 onUpdate() 方法
initialLayout 定义了小部件使用的布局
resizeMode 指定了 widget 的调整尺寸的规则。可取的值有: “horizontal”, “vertical”, “none”。“horizontal"意味着widget可以水平拉伸,“vertical”意味着widget可以竖值拉伸,“none”意味着widget不能拉伸;默认值是"none”
widgetCategory 指定了 widget 能显示的地方:能否显示在 home Screen 或 lock screen 或 两者都可以。它的取值包括:“home_screen” 和 “keyguard”。Android 4.2 引入
AndroidManifest.xml
Receiver
<receiver android:name=".desktop.DesktopWidget">
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_desktop_options" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
Service
如果小部件中使用到了列表项如 ListView,GridView 等,在绑定数据时需要使用 RemoteViewsService 并提供一个 RemoteViewsFactory 实例来填充数据 而非 Adapter
注意权限
<service
android:name=".desktop.DesktopViewsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
AppWidgetProvider
常用方法
-
onReceive
当接收到广播的时候会被调用。
-
onUpdate()
当Widget被添加或者被更新时会调用该方法。上边我们提到通过配置updatePeriodMillis可以定期更新Widget。但是当我们在widget的配置文件中声明了android:configure的时候,添加Widget时则不会调用onUpdate方法。
-
onAppWidgetOptionsChanged()
这个方法会在添加Widget或者改变Widget的大小时候被调用。在这个方法中我们还可以根据Widget的大小来选择性的显示或隐藏某些控件。
-
onDeleted
当控件被删除的时候调用该方法
-
onEnabled
当第一个Widget被添加的时候调用。如果用户添加了两个这个小部件,那么只有第一个添加时才会调用onEnabled.
-
onDisabled
当最后一个Widget实例被移除的时候调用这个方法。在这个方法中我们可以做一些清除工作,例如删掉临时的数据库等。
PendingIntent.FLAG
- 0 代表该 PendingIntent 不带数据
- PendingIntent.FLAG_CANCEL_CURRENT 则只有最后一次PendingIntent有效,之前的都无效了
- PendingIntent.FLAG_UPDATE_CURRENT 对于FLAG_UPDATE_CURRENT,如果上面的requestCode为常量, 则所有对应的Intent里面的extra被更新为最新的, 就是全部为最后一次的。 相反,如果requestCode每次不一样,则里面的Inent的数据没被更新
所以要通过extra数据来区分intent,应采用PendingIntent.FLAG_UPDATE_CURRENT),且每次requestCode不一样
常用事件
设定TextView值
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_appfolder_custom);
views.setTextViewText(R.id.tv_widget_title, "ZGTools");
设定控件点击事件
Intent setIntent = new Intent(context, AppCustomActivity.class);
setIntent.putExtra("appWidgetId", appWidgetId);
PendingIntent setPendingIntent = PendingIntent.getActivity(context, appWidgetId, setIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.tv_appcustom_set, setPendingIntent);
设定列表数据并绑定item点击事件
设定列表数据
Intent intent = new Intent(context, AppFolderViewsService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
//setRemoteAdapter设定Listivew,Gridview等复杂布局的adapter
//第一个参数为要绑定的widget的Gridview的id,第二个参数为RemoteViewsService的intent
views.setRemoteAdapter(R.id.gv_appfolder_custom_app, intent);
绑定item点击事件
//绑定 item 的定点事件
//Activity方式测试不成功,改用广播的方式进行发送并执行事件
//此处不能是空的Intent 否则广播无法发送
//定义Intent事件模板,相当于公用设定,再在fillIntent里面设定具体的 extra 值
Intent templateIntent = new Intent(context, AppFolderWidget.class);
templateIntent.setAction(ACTION_START_ACTIVITY);
templateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
templateIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, templateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setPendingIntentTemplate(R.id.gv_appfolder_custom_app, pendingIntent);
RemoteViewsFactory中getViewAt填充点击事件
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("app_package", lstApps.get(i).getAppPackage());
bundle.putInt("appWidgetId", mAppWidgetId);
intent.putExtras(bundle);
views.setOnClickFillInIntent(R.id.iv_widget_desktop_icon, intent);
views.setOnClickFillInIntent(R.id.tv_widget_desktop_label, intent);
AppWidgetProvider 中 onReceive 接收广播并执行事件
if (intent.getAction().equals(ACTION_START_ACTIVITY)) {
PackageManager pm = context.getPackageManager();
String strPackage = intent.getStringExtra("app_package");
int appWidgetId = intent.getIntExtra("appWidgetId", 0);
try {
Intent appIntent = pm.getLaunchIntentForPackage(strPackage);
context.startActivity(appIntent);
} catch (Exception e) {
log(e.getMessage());
}
}