安卓Widget组件复杂布局开发实现

文章介绍:

	实现一个多布局可滑动可点击的安卓widget组件;

知识点介绍:

  • AppWidgetProvider
  • AdapterViewFlipper
  • RemoteViews
  • RemoteViewsService
  • PendingIntent

开发步骤

1、新建类继承AppWidgetProvider,重写onUpdate()方法和onReceive()方法;

/**
     * 遍历所有的控件,然后更新
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.d(TAG,"onUpdate... appWidgetIds: "+appWidgetIds.length);
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }
@Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.d(TAG,"onReceive... ");
        if(intent == null) {
            return;
        }
        ...
   }
	/**
     * 控件的更新和操控
     */
    @SuppressLint("ResourceType")
    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        Log.d(TAG,"updateAppWidget...appWidgetId: "+appWidgetId);

        //获取Widget的组件名
        ComponentName componentName = new ComponentName(context, ImageTextWidget.class);
        // 创建一个RemoteView
        @SuppressLint("RemoteViewLayout") SkinRemoteViews remoteViews = new SkinRemoteViews(context.getPackageName(), R.layout.layout_widget);
//        remoteViews.setImageViewResource(R.id.iv_background,R.mipmap.icon_widget_bg);
        remoteViews.setImageViewResource(R.id.iv_default,R.mipmap.icon_widget_imagetext);
        // 把这个Widget绑定到RemoteViewsService
        Intent serviceIntent = new Intent(context, FilpperAdapterService.class);
        serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        // 设置适配器
        remoteViews.setRemoteAdapter(R.id.avfilpper, serviceIntent);
        // 设置当显示的widget_list为空显示的View
        remoteViews.setEmptyView(R.id.avfilpper, R.id.iv_default);
        // 点击列表触发事件
        Intent clickIntent = new Intent(context, ImageTextWidget.class);
        // 设置Action,方便在onReceive中区别点击事件
        clickIntent.setAction(Constant.ACTION_CLICK_FILPPER);
        clickIntent.setData(Uri.parse(clickIntent.toUri(Intent.URI_INTENT_SCHEME)));
        PendingIntent pendingIntentTemplate = PendingIntent.getBroadcast(
                MyApplication.myApp, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setPendingIntentTemplate(R.id.avfilpper,
                pendingIntentTemplate);

        //默认图点击事件,重新发起网络请求更新数据
        Intent reqIntent = new Intent(context, ImageTextWidget.class);
        reqIntent.setAction(Constant.ACTION_CLICK_DEFAULTVIEW);
        PendingIntent reqPanding = PendingIntent.getBroadcast(
                MyApplication.myApp,0,reqIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_default,reqPanding);

        //由AppWidgetManager处理Wiget。
        appWidgetManager.updateAppWidget(componentName, remoteViews);
    }

2、新建服务类继承RemoteViewsService

public class FilpperAdapterService extends RemoteViewsService {

    private static final String TAG = "FilpperAdapterService";
    private Gson gson = new Gson();


    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        Log.d(TAG,"onGetViewFactory... ");
        return new FilpperRemoteViewsFactory(this.getApplicationContext(),intent);
    }

新建factory类实现RemoteViewsFactory;

class  FilpperRemoteViewsFactory implements RemoteViewsFactory {
        private Context context;
        private List<BannerAttachParentBean> listBean2s;
        private Handler handler;
        //图片缓存
        private HashMap<String,Bitmap> imageMap;
        ...
}

3、重写factory类中的getViewAt方法

 		@Override
        public RemoteViews getViewAt(int position) {
            Log.d(TAG,"getViewAt...111...position: "+position);
            Constant.currentWidgetPage = position;
            if(position<0 || listBean2s == null || position>=listBean2s.size()) {
                return null;
            }
            BannerAttachParentBean parentBean = listBean2s.get(position);
            if(parentBean == null) {
                return null;
            }
            int type = parentBean.getType();
            RemoteViews rv = null;
            //多布局
            if(type == 0) { //图文类型
                rv = new RemoteViews(context.getPackageName(), R.layout.image_text_widget);
                imageTextLayout(rv,parentBean,position);
            } else if(type == 2){  //商铺类型
                rv = new RemoteViews(context.getPackageName(), R.layout.layout_miniprogram_recommend);
                miniProgramLayout(rv,parentBean,position);
            } else if(type == 100 && Constant.underTakeList != null) { //小程序兜底数据
                //fliper里面不能再嵌套gridview,只能使用基础view实现
                rv = new RemoteViews(context.getPackageName(), R.layout.layout_miniprogram_default4);
                miniProgramDefaultLayout(rv,position);
            }

            return rv;
        }
		/**
         * 图文板块
         */
        private void imageTextLayout(RemoteViews rv,BannerAttachParentBean parentBean,int position) {
            BannerAttachBean bannerAttachBean = parentBean.getBannerAttach();
            rv.setTextViewText(R.id.tv_desc, bannerAttachBean.getMainContent());
            // 填充Intent,填充在AppWdigetProvider中创建的PendingIntent
            Intent fillInIntent = new Intent();
            fillInIntent.putExtra("uri",gson.toJson(bannerAttachBean.getUri()));
            rv.setOnClickFillInIntent(R.id.iv_image,fillInIntent);

            if(imageMap.containsKey(parentBean.getBannerId())) {
                rv.setImageViewBitmap(R.id.iv_image, imageMap.get(parentBean.getBannerId()));
            } else {
                final boolean[] isWait = {true};
                Glide.with(MyApplication.myApp)
                        .asBitmap()
                        .skipMemoryCache(true)
                        .diskCacheStrategy(DiskCacheStrategy.NONE)  //禁用缓存
                        .load(bannerAttachBean.getBannerSourceURL())
                        .apply(RequestOptions.centerCropTransform().transform(new GlideRoundTransform(16)))
                        .into(new SimpleTarget<Bitmap>() {
                            @Override
                            public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                                Log.i(TAG, "onResourceReady...resource: " + resource);
                                if (!resource.isRecycled()) {
                                    rv.setImageViewBitmap(R.id.iv_image, resource);
                                    Log.i(TAG, "onResourceReady...resource222: ");
                                    isWait[0] = false;
                                    imageMap.put(parentBean.getBannerId(),resource);
                                }
                            }
                        });
                //2秒如果还没有回调,结束死循环;
                Runnable runnable = () -> isWait[0] = false;
                handler.postDelayed(runnable,2000);
                Log.d(TAG,"getViewAt...while...isWait...start: " + position);
                //必须要先接收到回调设置好图片,rv才能返回,无奈之举
                while(isWait[0]){
                    Log.d(TAG,"getViewAt...while...isWait ");
                }
                Log.d(TAG,"getViewAt...while...isWait...end: " + position);
                handler.removeCallbacks(runnable);
            }
        }

4、发送的点击pandingIntent消息在onReceive中接收处理;

	/**
     * 接收自定义的一些广播
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.d(TAG,"onReceive... ");
        if(intent == null) {
            return;
        }
        String intentAction = intent.getAction();
        Log.d(TAG,"onReceive...intentAction: "+intentAction);
        if("com.iflytek.autofly.skin".equals(intentAction)) {
            changeSkin(context,intent);
        } else if(Constant.ACTION_CLICK_FILPPER.equals(intentAction)) {
            turnToApp(context,intent);
        } else if(Constant.ACTION_CLICK_DEFAULTVIEW.equals(intentAction)) {
            EventBus.getDefault().post(new EventBusBean.ReqWidgetDataEvent());
        }
    }

5、更新数据

更新widget

/**
     * 更新widget
     */
    @SuppressLint("ResourceType")
    private void updateAppWidget() {
        Log.d(TAG, "updateAppWidget... ");
        //获取Widget的组件名
        ComponentName componentName = new ComponentName(WidgetService.this, ImageTextWidget.class);
        // 创建一个RemoteView
        SkinRemoteViews remoteViews = new SkinRemoteViews(getPackageName(), R.layout.layout_widget);
//        remoteViews.setImageViewResource(R.id.iv_background,R.mipmap.icon_widget_bg);
        remoteViews.setImageViewResource(R.id.iv_default, R.mipmap.icon_widget_imagetext);
        // 把这个Widget绑定到RemoteViewsService
        Intent serviceIntent = new Intent(WidgetService.this, FilpperAdapterService.class);
        serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
        // 设置适配器
        remoteViews.setRemoteAdapter(R.id.avfilpper, serviceIntent);
        // 设置当显示的widget_list为空显示的View
        remoteViews.setEmptyView(R.id.avfilpper, R.id.iv_default);
        // 点击列表触发事件
        Intent clickIntent = new Intent(WidgetService.this, ImageTextWidget.class);
        // 设置Action,方便在onReceive中区别点击事件
        clickIntent.setAction(Constant.ACTION_CLICK_FILPPER);
        clickIntent.setData(Uri.parse(clickIntent.toUri(Intent.URI_INTENT_SCHEME)));
        PendingIntent pendingIntentTemplate = PendingIntent.getBroadcast(
                MyApplication.myApp, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setPendingIntentTemplate(R.id.avfilpper,
                pendingIntentTemplate);
        //由AppWidgetManager处理Wiget。
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(MyApplication.myApp);
        appWidgetManager.updateAppWidget(componentName, remoteViews);
    }

更新数据

/**
     * 更新widget数据
     */
    private void updateWidget() {
        ComponentName componentName = new ComponentName(WidgetService.this, ImageTextWidget.class);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(WidgetService.this.getApplicationContext());
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.avfilpper);
    }

6、课后讨论

widget滑动组件如何实现手动滑动翻页?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值