桌面小部件的应用还是很多的,比如网易云音乐、微博等,虽然我们开发的APP并不一定需要开发这个,但简单了解学习一下还是可以的。
AppWidgetProvider是Android提供的开发小部件的类,所以我们开发小部件即只需要继承这个类,重写其中的某些方法。这是我们看到系统有自带的小部件,比如时钟、计算器等,这些小部件的类应该是被嵌入到自家定制的系统里了(个人猜测,不知道怎么证明,有人知道请告诉我)。
跟activity布局文件的放置位置一样,内容和命名都没要求,自己喜欢就好。我这里命名为widget.xml。
这里需要在res/xml下新建,名称任意,这里initialLayout就是指小部件使用的初始化布局,minHeight和minWidth定义小部件的最小尺寸,updatePeriodMillis定义小工具的自动更新周期,毫秒为单位,每隔一个周期,小工具的自动更新就会触发(我们前面说到的微博之类的是需要不断更新内容的)。
package learn.yfg.com.learnapplication;
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.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
/**
* @version: v1.0
* @description: 自定义小部件
* @package: learn.yfg.com.learnapplication
* @author: 酥小鱼
* @date :2018/10/16
*/
public class MyAppWidgetProvider extends AppWidgetProvider {
private static final String TAG = "MyAppWidgetProvider";
private static final String CLICK_ACTION = "learn.yfg.com.learnapplication.action.CLICK";
public MyAppWidgetProvider() {
super();
}
@Override
public void onReceive(final Context context, Intent intent) {
super.onReceive(context, intent);
Log.i(TAG, "onReceive: action" + intent.getAction());
//这里是判断自己的action,做自己的事情,比如小部件点击了要干什么,这里是做一个动画效果
if (intent.getAction().equals(CLICK_ACTION)){
// Toast.makeText(context, "Clicked it", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
Bitmap srcbBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.img_1);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
for (int i = 0; i < 37; i++) {
float degree = (i * 10) % 360;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
remoteViews.setImageViewBitmap(R.id.imageview1,rotateBitmap(context,srcbBitmap,degree));
Intent intentClick = new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0,intentClick,0);
remoteViews.setOnClickPendingIntent(R.id.imageview1,pendingIntent);
appWidgetManager.updateAppWidget(new ComponentName(context,MyAppWidgetProvider.class),remoteViews);
SystemClock.sleep(300);
}
}
}).start();
}
}
private Bitmap rotateBitmap(Context context, Bitmap srcbBitmap, float degree) {
Matrix matrix = new Matrix();
matrix.reset();
matrix.setRotate(degree);
Bitmap tmpBitmap = Bitmap.createBitmap(srcbBitmap,0,0,srcbBitmap.getWidth(),srcbBitmap.getHeight(),matrix,true);
return tmpBitmap;
}
/**
* 每次桌面小部件更新都调用一次该方法
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.i(TAG, "onUpdate: ");
final int counter = appWidgetIds.length;
Log.i(TAG, "counter = " + counter);
for (int i = 0; i < counter; i++) {
int appWidgetId = appWidgetIds[i];
onAppWidgetUpdate(context,appWidgetManager,appWidgetId);
}
}
/**
* 桌面小部件更新
* @param context
* @param appWidgetManager
* @param appWidgetId
*/
private void onAppWidgetUpdate(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
Log.i(TAG, "appWidgetId = " + appWidgetId);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
//“桌面小部件” 点击事件发送的intent广播
Intent intentClick = new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0,intentClick,0);
remoteViews.setOnClickPendingIntent(R.id.imageview1,pendingIntent);
appWidgetManager.updateAppWidget(new ComponentName(context,MyAppWidgetProvider.class),remoteViews);
}
}
看下这个类,继承父类,无参构造器,实现onReceive和onUpdate方法。
主要看下这两个方法,onReceive里判断了action,
这里用到了RemoteViews,这个说一下这个控件对应的布局(是有一定限制的),仅支持的类型如下
Layout:FrameLayout、LinearLayout、RealativeLayout、GridLayout
View:AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub
还用到了PendingIntent,这个解释一下,这个是指即将发生的intent,和intent不同,intent是立即发生,pendingIntent不确定性,典型的应用场景就是运用在remoteViews里面,这里支持三种意图,即活动、服务和广播,对应的getActivity、getService、getBroadcast,pendingIntent发生时效果相当于startActivity等方法了。
在onReceive里面主要分发具体的事件,关于事件分发我们有讲过,我们这里进行了动画旋转效果。即rotateBitmap方法。这里涉及的Matrix等,以后我会在自定义控件里面细说,这里不多说。
还有一个onUpadate方法,这里主要更新小部件。
另外还有几个方法,我这里并没有重写,分别为
onEnable:添加小部件第一次会被调用,添加多次也只会调用一次
onDelete:每删除一次桌面小部件就会调用一次
onDisabled:当最后一个该类型的桌面小部件被删除时调用
这里记得要注册这个广播,小部件的配置文件、小部件行为的识别、小部件的标志都不可少。即resource、action等。
这些完成后就可以运行我们的demo,然后直接打开手机的小工具列表,找到我们app下的小工具,添加到桌面,点击,就和效果图一致了(哈哈,比较魔性,这个小工具,没事点着转)
这里基本所有的代码都有贴上,至于这么灵性的图片,哈哈,可以进群找我要。