Widget de escritorio de Android

Crear un widget de escritorio

  • Cree una clase AppWidgetProvider
    Cree una clase AppWidgetProvider para que los widgets de escritorio reciban transmisiones al actualizar, habilitar, deshabilitar y eliminar widgets de aplicaciones. Y AppWidgetProvider hereda BroadcastReceiver y, específicamente, realiza cierto filtrado de transmisión en los widgets, por lo que necesitamos crear una clase AppWidgetProvider personalizada para manejar las operaciones relacionadas con los widgets.
package com.example.widgetdemo

import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log

const val TAG = "MyWidgetProvider"

class MyWidgetProvider : AppWidgetProvider() {
    
    

   /**
    *  每次收到广播之后就会调用该函数,会在其他方法之前进行回调。一般可以不实现
    *  默认的 AppWidgetProvider 实现会过滤所有应用微件广播并视情况调用上述方法
    */
   override fun onReceive(context: Context?, intent: Intent?) {
    
    
       super.onReceive(context, intent)
       Log.d(TAG, "invoke onReceive......")
   }

   /**
    * 调用此方法可以按 AppWidgetProviderInfo 中的 updatePeriodMillis 属性定义的时间间隔来更新应用微件
    * 当用户添加应用微件时也会调用此方法,所以它应执行基本设置,如定义视图的事件处理脚本以及根据需要启动临时的 Service。
    * 不过,如果您已声明配置 Activity,则当用户添加应用微件时不会调用此方法,但会调用它来执行后续更新。
    * 由配置 Activity 负责在配置完成后执行首次更新。
    */
   override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) {
    
    
       super.onUpdate(context, appWidgetManager, appWidgetIds)
       Log.d(TAG, "invoke onUpdate......")
   }

   /**
    * 当首次放置微件时以及每当调整微件的大小时,会调用此方法。您可以使用此回调来根据微件的大小范围显示或隐藏内容
    */
   override fun onAppWidgetOptionsChanged(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetId: Int, newOptions: Bundle?) {
    
    
       super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
       Log.d(TAG, "invoke onAppWidgetOptionsChanged......")

   }

   /**
    * 每次从应用微件托管应用中删除应用微件时,都会调用此方法。
    */
   override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
    
    
       super.onDeleted(context, appWidgetIds)
       Log.d(TAG, "invoke onDeleted......")
   }

   /**
    * 首次创建应用微件的实例时,会调用此方法。例如,如果用户添加应用微件的两个实例,只有首次添加时会调用此方法。
    * 如果您需要打开一个新的数据库或执行只需要对所有应用微件实例执行一次的其他设置,则此方法非常合适。
    */
   override fun onEnabled(context: Context?) {
    
    
       super.onEnabled(context)
       Log.d(TAG, "invoke onEnabled......")
   }

   /**
    * 从应用微件托管应用中删除了应用微件的最后一个实例时,会调用此方法。
    * 您应使用此方法来清理在 onEnabled(Context) 中完成的所有工作,如删除临时数据库。
    */
   override fun onDisabled(context: Context?) {
    
    
       super.onDisabled(context)
       Log.d(TAG, "invoke onDisabled......")
   }

   override fun onRestored(context: Context?, oldWidgetIds: IntArray?, newWidgetIds: IntArray?) {
    
    
       super.onRestored(context, oldWidgetIds, newWidgetIds)
       Log.d(TAG, "invoke onRestored......")
   }
}
  • Registrar transmisión
    Registre el receptor en el archivo AndroidManifest.xml y especifique la clase de recepción de transmisión como la clase que definimos anteriormente, donde el valor del campo de etiqueta indica el nombre del widget que se puede mostrar en la lista de widgets y especifique el action como "android .appwidget.action.APPWIDGET_UPDATE", y agregue un archivo my_appwidget_info relacionado con la información de configuración del widget
  <receiver
            android:name=".MyWidgetProvider"
            android:exported="false"
            android:label="我的卡片">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/my_appwidget_info" />
        </receiver>
  • archivo my_appwidget_info.xml
    initialLayout: el diseño inicial del widget
    minWidth: el ancho mínimo del widget
    minHeight: el alto mínimo del widget
    previewImage: la imagen de vista previa del widget en la lista de componentes de la aplicación
    resizeMode: si se puede cambiar el tamaño, ninguno |horizontal|vertical; tamaño fijo |dirección horizontal|dirección vertical
    updatePeriodMillis: intervalo de actualización, frecuencia de actualización, unidad MS, límite oficial de 30 minutos, para reducir el consumo de energía
    widgetCategory: dónde se pueden mostrar los widgets, generalmente la interfaz principal
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/layout_my_card_widget"
    android:minWidth="80dp"
    android:minHeight="40dp"
    android:previewImage="@drawable/widget_icon"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="86400000"
    android:widgetCategory="home_screen">
</appwidget-provider>

Se crea el primer widget de escritorio y el efecto es el siguiente:
inserte la descripción de la imagen aquí

interacción de eventos

  • Actualizar widgets
    Se llamará al método onUpdate cuando el usuario agregue un widget al escritorio por primera vez, y el atributo appWidgetIds identifica varios widgets administrados por el AppWidgetProvider actual, por lo que el widget se actualiza por primera vez en este método, y nosotros Puede obtener los datos aquí y actualizar la información relevante del widget.
    Vista previa del diseño:
    inserte la descripción de la imagen aquí
    simulamos un escenario. Cuando el usuario desea agregar un widget al escritorio por primera vez, debe extraer datos de la red y actualizarlos en el widget, y configurar el evento de clic de dos botones. Dado que es una demostración, simplemente inicie una tarea programada para simular operaciones de red que consumen mucho tiempo.La situación real es más complicada y se deben considerar varios casos.
override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) {
    
    
        super.onUpdate(context, appWidgetManager, appWidgetIds)
        Log.d(TAG, "invoke onUpdate......")
        val timer = Timer()
        val timerTask: TimerTask = object : TimerTask() {
    
    
            override fun run() {
    
    //定时任务
                appWidgetIds?.forEach {
    
    
                    val pendingIntent: PendingIntent =
                        Intent(context, SecondActivity::class.java).let {
    
     intent ->
                            PendingIntent.getActivity(context, 0, intent, 0)
                        }
                    val views: RemoteViews =
                        RemoteViews(context?.packageName, R.layout.layout_my_card_widget).apply {
    
    
                            setTextViewText(R.id.name, "来自Code")//设置小组件TextView的值
                            //添加LeftButton的点击事件
                            setOnClickPendingIntent(R.id.btnLeft, getSelfPendingIntent(context, LEFT_BUTTON_CLICK))
                            //添加RightButton的点击事件
                            setOnClickPendingIntent(R.id.btnRight, getSelfPendingIntent(context, RIGHT_BUTTON_CLICK))
                        }
                        //执行更新
                    appWidgetManager?.updateAppWidget(appWidgetIds, views)
                }
            }
        }
        timer.schedule(timerTask, 1000)
    }

Debido a que la interacción entre el widget y la aplicación se basa en la transmisión, cuando definimos el evento de clic, debemos personalizar la intención y distinguir el evento de clic a través de la acción.

	private const val LEFT_BUTTON_CLICK = "widget_left_button"
	private const val RIGHT_BUTTON_CLICK = "widget_right_button"

    private fun getSelfPendingIntent(context: Context?, action: String): PendingIntent {
    
    
        val intent = Intent(context, javaClass)//javaClass = this.class
        intent.action = action
        return PendingIntent.getBroadcast(context, 0, intent, 0)
    }

El siguiente paso es cuando hacemos clic en el widget y luego volvemos a llamar al método onReceive para procesar el evento.

override fun onReceive(context: Context?, intent: Intent?) {
    
    
        super.onReceive(context, intent)
        Log.d(TAG, "invoke onReceive......")
        intent?.action?.let {
    
     action ->
            context?.let {
    
    
                val manager = AppWidgetManager.getInstance(context)
                val remoteViews = RemoteViews(context.packageName, R.layout.layout_my_card_widget)
                if (action == LEFT_BUTTON_CLICK) {
    
    
                	//设置一个颜色
                    remoteViews.setTextColor(R.id.name, Color.parseColor("#FF03DAC5"))
                    manager.updateAppWidget(ComponentName(context, MyWidgetProvider::class.java), remoteViews)
                } else if (action == RIGHT_BUTTON_CLICK) {
    
    
                	//将颜色改回来
                    remoteViews.setTextColor(R.id.name, Color.parseColor("#FF000000"))
                    manager.updateAppWidget(ComponentName(context, MyWidgetProvider::class.java), remoteViews)
                    Toast.makeText(context, "点击右边按钮", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

El archivo de diseño es relativamente simple, por lo que se ha completado el uso simple de widgets.

Supongo que te gusta

Origin blog.csdn.net/weixin_42643321/article/details/127533983
Recomendado
Clasificación