当前位置:   article > 正文

AppWidget基础使用_requestpinappwidget

requestpinappwidget
AppWidget小组件的基础使用

添加属于自身app的小组件

对于制作的app,widget 就只是一个静态注册的广播,widget的UI使用xml进行配置。

说明,widget 用的 layout/layout_widget.xml 文件长这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">

 <TextView
     android:id="@+id/widget_text"
     android:layout_width="100dp"
     android:layout_height="30dp"
     android:text="widget test"
     android:textColor="#FF1100" />

 <Button
     android:id="@+id/widget_button"
     android:layout_width="20dp"
     android:layout_height="20dp"
     android:text="update" />
</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. 首先,创建一个class 继承 AppWidgetProvider
class WidgetOne : AppWidgetProvider() {
    override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
    ) {
        super.onUpdate(context, appWidgetManager, appWidgetIds)
        if (context != null && appWidgetManager != null) {
            appWidgetIds?.forEach {
               //操作 UI 需要通过 RemoteViews 来操作
                val date = Date()
                //创建 RemoteViews,绑定layout文件,layout文件需要和下文的xml同一个
                val views = RemoteViews(context.packageName, R.layout.layout_widget)
                //更新Text文本,传 View 的 id 和文言。
                views.setTextViewText(R.id.widget_text, date.time.toString())
                appWidgetManager.updateAppWidget(it, views)
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

几个主要方法说明:

onUpdate()发送更新广播时触发这个回调,没配置configure时添加widget触发,xml里配置的更新时长到了也会收到
onAppWidgetOptionsChanged()widget 大小变化的时候回调,包括第一次添加从零到有
onEnable(Context)第一个 widget 被添加到桌面时触发回调
onDisabled(Context)最后一个 widget 从桌面移除的时候回调
  1. 之后,在AndroidManifest.xml文件中,静态注册自定义的广播,action至少要指定一个名为 android.appwidget.action.APPWIDGET_UPDATE 的 Action,widget 和定义的广播交互便是通过这个 Action 进行的交互。
        <receiver android:name=".test.WidgetOne" android:exported="true"
            android:enabled="true" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
        </receiver>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  1. 使用 xml 定义 widget 的显示样式。在 res 的 xml 下创建 appwidget-provider 类型的 xml,其他位置也可以,只要类型是 appwidget-provider 即可,也就是外部的标签。
    文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minHeight="20dp"
    android:minWidth="100dp"
    android:initialLayout="@layout/layout_widget"
    android:previewLayout="@layout/layout_widget"
    android:updatePeriodMillis="1000">

</appwidget-provider>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

不好理解的属性说明:
android:previewLayout=“@layout/layout_widget”:预看的样式,也就是点击桌面的添加小组件时,所有的小组件中这个定义的小组件显示的样子,这里使用了 layout 文件显示

android:initialLayout=“@layout/layout_widget”:初始的显示样式,添加到桌面时,没有进行修改的前提下显示的样式。

android:updatePeriodMillis=“1000”:多少时间发一次更新广播,也就是我们注册的 .test.WidgetOne 广播会收到并回调 onUpdate 方法,这个值其实是没用的,它有个最小值要求,半小时(基本都是实时更新,所以没啥用感觉),不过更新 widget 的操作我们是可以随时做的,这个只是系统会自动发给你的而已。

android:configure:如果配置了这个属性,那 widget 首次显示不会发送 update 广播去触发 onUpdate 回调更新 widget,而是直接使用这个配置里的 Activity 进行配置显示。这里没用它。

android:resizeMode=“horizontal|vertical”:widget 可以在哪个方向上调大小,横还是竖,默认就是没有,none值。设成可以改大小的话,横竖上最小值是可以定义的,用 minResizeHeight 和 minResizeWidth 定义。

  1. 创建完 xml,在 AndroidManifest.xml 广播注册的地方,加上这个样式定义的 xml 就行了。
    加载 <meta-data>标签里,name 属性用 android.appwidget.provider。
        <receiver android:name=".test.WidgetOne" android:exported="true"
            android:enabled="true" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="widget-test" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_xml" />
        </receiver>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  1. 一般来说,如果有数据或者配置变更,widget 肯定是要跟着变的,随时更新 widget 的操作如下:

不能直接操作,用 RemoteViews 去操作。

        //在 Activity 里写的 code,所以传了 this,实际上就是传 Context 上下文
        val widgetManager = AppWidgetManager.getInstance(this)
        //绑定 layout 文件
        val remoteViews = RemoteViews(packageName, R.layout.layout_widget)
        //操作控件需要传具体控件的 id ,而不是像正常的操作 View
        remoteViews.setTextViewText(R.id.widget_text, "System.currentTimeMillis().toString()")
        //这个是表示更新所有的 widget
        val comName = ComponentName(this, WidgetOne::class.java)
        widgetManager.updateAppWidget(comName, remoteViews)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

  1. 给 widget 里的控件添加事件

说明:操作 View,都是用 RemoteViews 操作,事件也是,只是事件相当于一个回调,这里只用了广播方式的,意思就是,设置事件传递的 intent,在触发事件后,系统会用这个 intent 发一个广播出来,我们只要接收这个广播,然后做操作就行。
code:

        val intent = Intent("widget-test")
        //设置传递的 class,就是说,sendBroadCast用过吧,就是发给自己的广播,设置多个事件的时候只用Action
        intent.setClass(context, WidgetOne::class.java)
        //传触发事件控件的值,收到之后做判定,知道是点了啥
        intent.data = Uri.parse("id:" + 888)
        val pendIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
        val date = Date()
        val views = RemoteViews(context.packageName, R.layout.layout_widget)
        //这里就是设置文本
        views.setTextViewText(R.id.widget_text, date.time.toString())
        //这里就是设置事件,事件是点击,后面是事件后做的操作
        views.setOnClickPendingIntent(R.id.widget_button, getPendIntent(context,R.id.widget_button))
        appWidgetManager.updateAppWidget(appWidgetId, views)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

  1. 既然我们设置的事件之后,Action 设为了其他的,那 AndroidManifest.xml 里肯定得有个 Action 是 “widget-test” 的广播去收,然后做操作,这里懒得加新的,就直接在 Widget 广播里加了这个 Action 的过滤。
        <receiver android:name=".test.WidgetOne" android:exported="true"
            android:enabled="true" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="widget-test" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_xml" />
        </receiver>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  1. 收到广播后对 Action 判定,做想做的操作就行,拿之前保存的 View 的id,判定要具体做的操作如下:
    override fun onReceive(context: Context?, intent: Intent?) {

        val action = intent?.action
        if ("widget-test" == action) {
            val data = intent.data as Uri
            val viewId = data.schemeSpecificPart.toInt()
            //之前保存在 intent.data 的值
            if (viewId == 888) {
                //收到之后改下了UI
                val widgetManager = AppWidgetManager.getInstance(context)
                val remoteViews = RemoteViews(context?.packageName, R.layout.layout_widget)
                remoteViews.setTextViewText(R.id.widget_text, System.currentTimeMillis().toString())
                val comName = ComponentName(context!!, WidgetOne::class.java)
                widgetManager.updateAppWidget(comName, remoteViews)
            }
        }
        super.onReceive(context, intent)
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

tName(context!!, WidgetOne::class.java)
widgetManager.updateAppWidget(comName, remoteViews)
}
}
super.onReceive(context, intent)
}

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/313020
    推荐阅读
    相关标签
      

    闽ICP备14008679号