让自己的Android应用支持appwidget

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

你可能感兴趣的:(让自己的Android应用支持appwidget)