经常看到一些教程教你如何写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);
}
}