本文介绍Widget的显示过程
Widget 就是我们常用的桌面小部件,它常常被显示在桌面上去完成一些功能,那么是如何显示的呢?主要相关的类:
AppWidgetHost:是用来容纳AppWidget的地方,主要有两个功能
(1).用来处理AppWidgetService事件,通过updata、provider_change事件来处理和更新Widget。
(2).创建AppWidgetHostView,用来装AppWidget的容器。
AppWidgetManager:和PackageManager一样,AppWidgetManager用来处理Widget。
AppWidgetProviderInfo:AppWidget 模型类。
示例demo,点击弹出对话框显示所有widget,选择widget显示到界面
MyWidgetHost.java
重写ViewGroup,用来显示AppWidget和计算widget的大小,位置
public class MyWidgetHost extends ViewGroup {
private int[] cellInfo = new int[2];
private OnLongClickListener mLongClickListener;
public MyWidgetHost(Context context) {
this(context, null);
}
public MyWidgetHost(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyWidgetHost(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// @1:当长按的时候触发该动作,记录长按的位置
public boolean dispatchTouchEvent(MotionEvent event) {
cellInfo[0] = (int) event.getX();
cellInfo[1] = (int) event.getY();
Log.e("event:", cellInfo[0] + "," + cellInfo[1]);
return super.dispatchTouchEvent(event);
}
//当用户选择了某个widget时,触发这个动作,将其所选的widget(child)添加到桌面上
public void addInScreen(View child, int width, int height) {
LayoutParams params = new LayoutParams(width, height);
params.x = cellInfo[0];
params.y = cellInfo[1];
// params.width = width
child.setOnLongClickListener(mLongClickListener);
Log.e("size", "x,y,width,height" + params.x + "," + params.y + ","
+ params.width + "," + params.height);
addView(child, params);
}
//测量每个孩子的宽度和高度
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int count = getChildCount();
LayoutParams lp = null;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
lp = (LayoutParams) child.getLayoutParams();
Log.e("onMeasure:w,h", lp.width + "," + lp.height);
child.measure(
MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY));
}
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
//将每个孩子按照其layoutparams中定义的进行布局
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
LayoutParams lp = null;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
lp = (LayoutParams) child.getLayoutParams();
child.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);
this.width = width;
this.height = height;
}
}
}
MainActivity中使用:
设置刚刚我们这自定义的ViewGroup为Activity的ContentView
点击ViewGroup通过发送一个Intent的方式来查询所有的Widget,带上Intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
在onActivityResult中根据返回的Widget 的ID再发一个Intent,通过刚在的ID得到AppWidgetProviderInfo的对象,HostView的WidgetHost.create(Context,id,widgetinfo)创建,然后添加到ViewGroup。
public class MainActivity extends Activity {
List<AppWidgetProviderInfo> list;
private static final int APPWIDGET_HOST_ID = 0x200;
private static final int REQUEST_ADD_WIDGET = 1;
private static final int REQUEST_CREATE_WIDGET = 2;
AppWidgetHost mAppWidgetHost;
AppWidgetManager manager;
MyWidgetHost myWidgetHostView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mAppWidgetHost = new AppWidgetHost(getApplication(), APPWIDGET_HOST_ID);
manager = AppWidgetManager.getInstance(getBaseContext());
myWidgetHostView = new MyWidgetHost(this);
myWidgetHostView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
selectWidgets();
}
});
setContentView(myWidgetHostView);
mAppWidgetHost.startListening();
}
protected void selectWidgets() {
int widgetId = mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
startActivityForResult(pickIntent, REQUEST_ADD_WIDGET);
}
private void createWidget(Intent data) {
// 获取选择的widget的id
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
// 获取所选的Widget的AppWidgetProviderInfo信息
AppWidgetProviderInfo appWidget = manager.getAppWidgetInfo(appWidgetId);
// 根据AppWidgetProviderInfo信息,创建HostView
View hostView = mAppWidgetHost.createView(this, appWidgetId, appWidget);
// View view = hostView.findViewById(appWidget.autoAdvanceViewId);
// ((Advanceable)view).fyiWillBeAdvancedByHostKThx();
// 将HostView添加到桌面
myWidgetHostView.addInScreen(hostView, appWidget.minWidth + 100,
appWidget.minHeight + 200);
myWidgetHostView.requestLayout();
}
// 添加选择的widget。需要判断其是否含有配置,如果有,需要首先进入配置
private void addWidget(Intent data) {
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
-1);
AppWidgetProviderInfo appWidget = manager.getAppWidgetInfo(appWidgetId);
Log.d("AppWidget", "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_WIDGET);
} else {
// 没有配置,直接添加
onActivityResult(REQUEST_CREATE_WIDGET, RESULT_OK, data);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_ADD_WIDGET:
addWidget(data);
break;
case REQUEST_CREATE_WIDGET:
createWidget(data);
break;
default:
break;
}
} else if (requestCode == REQUEST_CREATE_WIDGET
&& resultCode == RESULT_CANCELED && data != null) {
int appWidgetId = data.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (appWidgetId != -1) {
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
}
}
}
}
这仅仅是一个简单的创建和显示,在桌面程序中显示Widget的业务逻辑远远要比这复杂。