Android小部件Widget的简单应用和常见问题

控件

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());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值