前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >让自己的Android应用支持appwidget 博客分类: Android AndroidOSAccessUP

让自己的Android应用支持appwidget 博客分类: Android AndroidOSAccessUP

作者头像
chroya
发布2018-10-31 17:46:47
1.1K0
发布2018-10-31 17:46:47
举报
文章被收录于专栏:封碎封碎

经常看到一些教程教你如何写appwidget,但是,你知道你的appwidget是如何被添加到桌面上的吗? 一般的,如果是做桌面的童鞋,基本上都会让自己的桌面支持appwidget。下面说说如何实现。 首先是得定义一个承载appwidget的容器,系统的Launcher里面是用的CellLayout,实现的很不错。我这里就用一个简单的自定义ViewGroup来搞定,它是以长按的坐标处为要添加的appwidget的起始位置,简单点说就是按到哪儿就添加到哪儿。

代码语言:javascript
复制
package chroya.demo.widget;

import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * 承载widget的容器
 * @author chroya
 */
public class WidgetLayout extends ViewGroup {
	//存放touch的坐标
	private int[] cellInfo = new int[2];
	private OnLongClickListener mLongClickListener;	

	public WidgetLayout(Context context) {
		super(context);
		mLongClickListener = new OnLongClickListener() {
			
			@Override
			public boolean onLongClick(View v) {
				
				return false;
			}
		};
	}
	
	public void addInScreen(View child, int width, int height) {
		LayoutParams lp = new LayoutParams(width, height);
		lp.x = cellInfo[0];
		lp.y = cellInfo[1];
		child.setOnLongClickListener(mLongClickListener);
		addView(child, lp);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		LayoutParams lp;
		for(int index=0; index<getChildCount(); index++) {
			lp = (LayoutParams) getChildAt(index).getLayoutParams();
			getChildAt(index).measure(
					MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY, lp.width), 
					MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY, lp.height));
		}
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		cellInfo[0] = (int)event.getX();
		cellInfo[1] = (int)event.getY();
		return super.dispatchTouchEvent(event);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		LayoutParams lp;
		for(int index=0; index<getChildCount(); index++) {
			lp = (LayoutParams) getChildAt(index).getLayoutParams();
			getChildAt(index).layout(lp.x, lp.y, lp.x+lp.width, lp.y+lp.height);
		}
	}
	
	public static class LayoutParams extends ViewGroup.LayoutParams {
		int x;
		int y;

		public LayoutParams(int width, int height) {
			super(width, height);
		}		
	}
}

然后是重点了。还记得系统默认的桌面上,长按的时候出现的上下文菜单吗?里面有好几个选项,选择widget之后,会弹出一个已经安装的widget列表,选择一个widget之后,就会添加到桌面。我们可以把第一步去掉,长按之后,直接弹出已安装的widget列表,这是一个activity,用AppWidgetManager.ACTION_APPWIDGET_PICK这个Intent来启动,必须带上Extras,下面给出代码中有,不详叙。

代码语言:javascript
复制
package chroya.demo.widget;

import static android.util.Log.d;

import java.util.ArrayList;

import android.app.Activity;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnLongClickListener;

/**
 * 添加appwidget
 * @author chroya
 *
 */
public class Main extends Activity {
	private AppWidgetHost mAppWidgetHost;
	private AppWidgetManager mAppWidgetManager;
	private WidgetLayout layout;	
	
	private static final int REQUEST_PICK_APPWIDGET = 1;
	private static final int REQUEST_CREATE_APPWIDGET = 2;	
	private static final int APPWIDGET_HOST_ID = 0x100;
	private static final String EXTRA_CUSTOM_WIDGET = "custom_widget";
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        mAppWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        mAppWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
        //开始监听widget的变化
        mAppWidgetHost.startListening();
        
        layout = new WidgetLayout(this);
        layout.setOnLongClickListener(new OnLongClickListener() {
			
			@Override
			public boolean onLongClick(View v) {
				
				addWidget();
				return false;
			}
		});
        setContentView(layout);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    	if (resultCode == RESULT_OK) {
    		switch (requestCode) {
    		case REQUEST_PICK_APPWIDGET:
                addAppWidget(data);
                break;
            case REQUEST_CREATE_APPWIDGET:
                completeAddAppWidget(data);
                break;
    		}
    	} else if (requestCode == REQUEST_PICK_APPWIDGET &&
                resultCode == RESULT_CANCELED && data != null) {
            // Clean up the appWidgetId if we canceled
            int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
            if (appWidgetId != -1) {
                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
            }
        }
    }
    
    /**
     * 选中了某个widget之后,根据是否有配置来决定直接添加还是弹出配置activity
     * @param data
     */
    private void addAppWidget(Intent data) {
        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

        String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET);
        d("addAppWidget", "data:"+ customWidget);
        if ("search_widget".equals(customWidget)) {
        	//这里直接将search_widget删掉了
            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
        } else {
            AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
            
            d("addAppWidget", "configure:"+ appWidget.configure);
            if (appWidget.configure != null) {
            	//有配置,弹出配置
                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
                intent.setComponent(appWidget.configure);
                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

                startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
            } else {
            	//没有配置,直接添加
                onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
            }
        }
    }
    
    /**
     * 请求添加一个新的widget
     */
    private void addWidget() {
    	int appWidgetId = mAppWidgetHost.allocateAppWidgetId();

        Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        // add the search widget
        ArrayList<AppWidgetProviderInfo> customInfo =
                new ArrayList<AppWidgetProviderInfo>();
        AppWidgetProviderInfo info = new AppWidgetProviderInfo();
        info.provider = new ComponentName(getPackageName(), "XXX.YYY");
        info.label = "Search";
        info.icon = R.drawable.ic_search_widget;
        customInfo.add(info);
        pickIntent.putParcelableArrayListExtra(
                AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
        ArrayList<Bundle> customExtras = new ArrayList<Bundle>();
        Bundle b = new Bundle();
        b.putString(EXTRA_CUSTOM_WIDGET, "search_widget");
        customExtras.add(b);
        pickIntent.putParcelableArrayListExtra(
                AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
        // start the pick activity
        startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
    }    
    
    /**
     * 添加widget
     * @param data
     */
    private void completeAddAppWidget(Intent data) {
        Bundle extras = data.getExtras();
        int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

        d("completeAddAppWidget", "dumping extras content="+extras.toString());
        d("completeAddAppWidget", "appWidgetId:"+ appWidgetId);
        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
        
        View hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
        
        layout.addInScreen(hostView, appWidgetInfo.minWidth, appWidgetInfo.minHeight);        
    }
}

        运行效果如下:

需要注意的几点: 1。 必须调用AppWidgetHost的startListening方法来监听appwidget的状态变化,否则添加上去的appwidget不会更新的。 2。 需要override一个onActivityResult方法,来接收添加appwidget和appwidget的配置activity的返回值。 3。 启动AppWidgetManager.ACTION_APPWIDGET_PICK这个Intent,必须要给列表中加上自己定义的一个选项,否则出错。如本例中是用的Search。

源码见附件。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2010-11-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档