Android 桌面小组件 AppWidgetProvider(2)
1.生命周期
2.怎么处理点击事件
3.怎么创建集合
4.怎么处理动画效果
1.生命周期
1.1 添加小组件的生命周期
onEnabled:
onReceive:
onUpdate:
onReceive:
onAppWidgetOptionsChanged:
onReceive:
1.2 移除小组件的生命周期
onDeleted:
onReceive:
onDisabled:
onReceive:
2.怎么处理点击事件
这个问题解决方案的关键是 设置广播action
<receiver android:name=".listWidget.ListWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.zg.todesk.CLICK" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/listwidget" />
</receiver>
这里添加的是
<action android:name="com.zg.todesk.CLICK" />
然后再组件中,发送广播,就能在onReceive中收到消息,然后做相应的处理就好
val pendingIntent = PendingIntent.getBroadcast(
context,
0,
Intent(context, MuyuAppWidget::class.java).apply {
action = "com.zg.todesk.CLICK"
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.rl_muyu, pendingIntent)//这里选择最大的控件
然后onReceive处理消息
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
Log.e("zxd", "onReceive: ${intent!!.action}")
if (intent!!.action == "com.zg.zanglidemo.ANIM") {
...
}
}
3.怎么创建集合
这里简单的举一个例子。
1.声明AppWidgetProviderInfo XML
<?xml version="1.0" encoding="UTF-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/list_widget_layout"
android:minWidth="280dp"
android:minHeight="280dp"
android:updatePeriodMillis="0">
<!-- sdk1.5之后updatePeriodMillis已失效,置为0,循环执行自行在代码中实现 -->
</appwidget-provider>
2.使用 AppWidgetProvider 类处理 widget 广播
<!-- list widget -->
<receiver android:name=".listWidget.ListWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.zg.todesk.CLICK" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/listwidget" />
</receiver>
3.实现 AppWidgetProvider 类
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import com.zg.todesk.MainActivity;
import com.zg.todesk.R;
import java.util.ArrayList;
import java.util.List;
/***
* @Author: zxd
* @CreateDate: 2024/5/11 8:25:03
* @Description:
*/
public class ListWidget extends AppWidgetProvider {
private static List<String> sList;
static {
sList = new ArrayList<>();
sList.add("第一条新闻");
sList.add("第二条新闻");
sList.add("第三条新闻");
sList.add("第四条新闻");
sList.add("第五条新闻");
sList.add("第六条新闻");
}
private ComponentName thisWidget;
private RemoteViews remoteViews;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
thisWidget = new ComponentName(context, ListWidget.class);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.list_widget_layout);
Intent intent = new Intent(context, UpdateService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[0]);
//设置适配器
remoteViews.setRemoteAdapter(R.id.widget_list, intent);
Intent intent2 = new Intent(context, MainActivity.class);
//TODO
//intent2.setComponent(new ComponentName("包名", "类名"));
PendingIntent pendingIntentTemplate = PendingIntent.getActivity(context, 1, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
//拼接PendingIntent
remoteViews.setPendingIntentTemplate(R.id.widget_list, pendingIntentTemplate);
//更新RemoteViews
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.notifyAppWidgetViewDataChanged(appWidgetIds[0], R.id.widget_list);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
public static List<String> getList() {
return sList;
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
//在这里可以添加
if (intent.getAction().equals("com.zg.todesk.CLICK")) {
Log.i("zxd", "onReceive: " + intent.getStringExtra("val"));
}
}
}
4. widget 布局
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
<ListView
android:id="@+id/widget_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:cacheColorHint="#00000000"
android:scrollbars="none" />
<!-- android:divider="@drawable/widget_list_divider"
android:listSelector="@drawable/list_bg_selector"-->
</FrameLayout>
5.UpdateService中的处理**
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import com.zg.todesk.MainActivity;
import com.zg.todesk.R;
import java.util.List;
public class UpdateService extends RemoteViewsService {
@Override
public void onStart(Intent intent, int startId) {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new ListRemoteViewsFactory(this.getApplicationContext(), intent);
}
class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context mContext;
private final List<String> mList;
public ListRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mList = ListWidget.getList();
if (Looper.myLooper() == null) {
Looper.prepare();
}
}
@Override
public void onCreate() {
}
@Override
public void onDataSetChanged() {
}
@Override
public void onDestroy() {
mList.clear();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public RemoteViews getViewAt(int position) {
if (position < 0 || position >= mList.size())
return null;
String content = mList.get(position);
final RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_list_item);
Intent intent = new Intent();
//TODO
intent.putExtra("val", content);
//与CustomWidget中remoteViews.setPendingIntentTemplate配对使用
rv.setOnClickFillInIntent(R.id.widget_list_item_layout, intent);
rv.setTextViewText(R.id.widget_list_item_tv, content);
return rv;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean hasStableIds() {
return true;
}
}
}
6.AndroidManifest.xml中添加service
<service
android:name=".listWidget.UpdateService"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
4.怎么处理动画效果
要想小组件有动画效果,就需要点击配合layoutAnimation才能实现动画效果
小组件布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.ZangliDemo.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_raidus"
android:id="@+id/rl_muyu"
android:theme="@style/AppTheme.AppWidgetContainer">
<LinearLayout
android:id="@+id/ll_muyu"
android:layout_width="140dp"
android:layout_height="140dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/appwidget_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:contentDescription="测试桌面木鱼"
android:text="已敲0次"
android:textColor="@color/gray_8f"
android:textSize="18sp"
android:textStyle="bold" />
<RelativeLayout
android:id="@+id/muyu_rl"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/widget_muyu_iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
android:src="@mipmap/muyu" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
实现效果
private fun doAnimation(context: Context?, remoteViews: RemoteViews?) {
remoteViews?.removeAllViews(R.id.muyu_rl)
val remoteViews2 = RemoteViews(context?.packageName, R.layout.anim_layout)
remoteViews2.setImageViewResource(R.id.widget_muyu_iv, R.mipmap.muyu)
remoteViews?.addView(R.id.muyu_rl, remoteViews2)
clickNum++
Log.e("zxd", "doAnimation: $clickNum")
remoteViews?.setTextViewText(R.id.appwidget_text, "已敲${clickNum}次")
}
动画效果(anim_layout)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/muyu_anim">
<ImageView
android:id="@+id/widget_muyu_iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/muyu" />
</RelativeLayout>
muyu_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/scale_anim" />
scale_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="100"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1" />
5.参考链接
在widget实现复杂布局(Listview,GirdView)以及RemoteViewsService、RemoteViewsFactory的用法