让自己的Android应用支持appwidget
<br />让自己的Android应用支持appwidget文章分类:移动开发<br /> 经常看到一些教程教你如何写appwidget,但是,你知道你的appwidget是如何被添加到桌面上的吗?<br /> 一般的,如果是做桌面的童鞋,基本上都会让自己的桌面支持appwidget。下面说说如何实现。<br /> 首先是得定义一个承载appwidget的
经常看到一些教程教你如何写appwidget,但是,你知道你的appwidget是如何被添加到桌面上的吗?
一般的,如果是做桌面的童鞋,基本上都会让自己的桌面支持appwidget。下面说说如何实现。
首先是得定义一个承载appwidget的容器,系统的Launcher里面是用的CellLayout,实现的很不错。我这里就用一个简单的自定义ViewGroup来搞定,它是以长按的坐标处为要添加的appwidget的起始位置,简单点说就是按到哪儿就添加到哪儿。
- 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,下面给出代码中有,不详叙。
- 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。
源码见附件。
更多推荐
所有评论(0)