android widget详解,Android Widget详解(二)

前言

上一篇博客我们实现了自定义一个Widget的一些操作,但是没有再Widget中实现任何的点击操作和复杂布局,例如Listview的使用等等.本篇博客就来进行实现一些复杂布局

点击事件的处理

Widget是运行在桌面线程中的,所以我们不能用传统的方式来对Widget进行点击操作,需要用到pendingintent来传递点击事件广播,然后在广播中处理点击事件,对其做出响应.并且我们如果操控Widget中的布局,只能操控Remoteview来达到目的,Remoteview中规定了一些我们可以使用的方法,不提供的方法我们无法实现,只能通过存在的方法变相实现目的.

首先拿到RemoteView

RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_cw);

复制代码

实现点击之后打开系统时钟和日历(简单,发送Intent即可)

//设置打开系统日历

view.setOnClickPendingIntent(R.id.calendarlinear, PendingIntent.getActivity(context, 2, new Intent().setComponent(new ComponentName("com.android.calendar", "com.android.calendar.LaunchActivity")), PendingIntent.FLAG_UPDATE_CURRENT));

//设置打开系统时钟

view.setOnClickPendingIntent(R.id.clock_layout, PendingIntent.getActivity(context, 2, new Intent().setComponent(new ComponentName("com.android.deskclock", "com.android.deskclock.DeskClock")), PendingIntent.FLAG_UPDATE_CURRENT));

复制代码

第一个参数是需要设置的控件ID,第二个参数是一个PendingIntent,在Widget中设置监听无法直接用Intent传递,需要用PendingIntent来进行传递。

其格式大概为 set + (控件名) + 控件属性

格式不绝对,仅供参考,所以view中没有提供的方法,就无法进行修改。

实现上述操作十分的简单,我们只需要给view中的哪个"按钮"(这个按钮可以是任何控件)来绑定pendingintent就可以了.

下面实现一个点击在Widget中做出响应

//给两个按钮设置点击监听

view.setOnClickPendingIntent(R.id.btn_next, getClickIntent(context, appWidgetIds[0], R.id.btn_next, 0, "com.longlong.Widget.Button.Update"));

view.setOnClickPendingIntent(R.id.btn_previous, getClickIntent(context, appWidgetIds[0], R.id.btn_previous, 1, "com.longlong.Widget.Button.Update"));

复制代码

PendingIntent

使用这样一个方法来获取我们需要的一个基本的PendingIntent(这个方法我自己实现的,非官方)

//给按钮返回PendingIntent

private PendingIntent getClickIntent(Context context, int widgetId, int viewId, int requestCode, String action) {

//拿到管理对象

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

//pendingintent中需要的intent,绑定这个类和当前context

Intent i = new Intent(context, MyWidget.class);

//设置action

i.setAction(action); //设置更新动作

//设置bundle

Bundle bundle = new Bundle();

//将widgetId放进bundle

bundle.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);

//放进需要设置的viewId

bundle.putInt("Button", viewId);

i.putExtras(bundle);

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, i, PendingIntent.FLAG_UPDATE_CURRENT);

return pendingIntent;

}

复制代码

使用这样一个方法来获取我们需要的一个基本的PendingIntent(这个方法我自己实现的,非官方)

设置权限

这段代码很好理解,前文提到过,这里的点击是通过广播机制实现的,所以我们仍然需要再我们的Widget中设置权限,修改Mainifests

android:name=".MyWidget">

android:name="android.appwidget.action.APPWIDGET_UPDATE" />

android:name="com.longlong.Widget.Button.Update" />

android:name="com.longlong.COLLECTION_VIEW_ACTION" />

android:name="android.appwidget.provider"

android:resource="@xml/my_widget" />

复制代码

其中包括两个实现自定义按钮的点击权限还有下午你要实现的listview更新的点击权限(原理相同)

然后我们只需要重写我们的上下翻页实现,也就是重写onReceive方法

//这里用一个switch实现了

switch (choice) {

case "com.longlong.Widget.Button.Update":

//因为遥操作view所以拿到remotevie用来操作

RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.widget_cw);

//bundle中会由系统存好下面两个属性,下面是提取出来

Bundle bundle = intent.getExtras();

int widgetId = -1;

int viewId = -1;

try {

widgetId = bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);

Log.d("widgetId", String.valueOf(widgetId));

viewId = bundle.getInt("Button");

Log.d("viewId", String.valueOf(viewId));

} catch (NullPointerException e) {

return;

}

//根据获得到的viewid进行相应view的操作(这里我是用了一个flipper)

switch (viewId) {

case R.id.btn_next:

view.showNext(R.id.flipper);

break;

case R.id.btn_previous:

view.showPrevious(R.id.flipper);

break;

default:

return;

}

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

appWidgetManager.updateAppWidget(widgetId, view);

break;

复制代码

注释标注的很详细,我就不再多写了

在Widget中实现复杂布局

Widget这种神奇的东西要想实现ListView还是需要一番周折的.下面说明以下可以在Widget中实现的一些布局

官方有话这样说:

A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:

FrameLayout

LinearLayout

RelativeLayout

And the following widget classes:

AnalogClock

Button

Chronometer

ImageButton

ImageView

ProgressBar

TextView

ViewFlipper

ListView

GridView

StackView

AdapterViewFlipper

Descendants of these classes are not supported.不支持这些类的后代

也就是说,只有这些控件能在布局中使用,其他的控件无法再布局中使用,包括这些类的子类,也就是说Widget中的布局是有局限的,不能像再Activity那么为所欲为0.0 而且由于widget运行在桌面进程中,而不是程序主进程,所以对UI的一切操作需要用到RemoteView类来进行操作。

RemoteViewsService

这个是Service的子类,多用于对“GridView,ListView”等控件进行管理。

这么进行设置

view.setPendingIntentTemplate(R.id.data_list_view, getClickIntent(context, appWidgetIds[0], R.id.data_list_view, 3, "com.longlong.COLLECTION_VIEW_ACTION"));

复制代码

根据后面这个action来在onReceiver对其事件做出响应

view.setRemoteAdapter(R.id.data_list_view, new Intent(context, MyDataListService.class));

复制代码

在RemoteViewsService中可以实现控制

//首先我们需要继承RemoteviewService

public class MyDataListService extends RemoteViewsService {

@Override

public RemoteViewsFactory onGetViewFactory(Intent intent) {

//返回下文实现的类似Adapter的东东

return new ViewRemoteService(this, intent);

}

//实现一个ViewRemoteService再其中进行adapter的一些操作(官方规定= =)

private class ViewRemoteService implements RemoteViewsService.RemoteViewsFactory {

private Context mContext;

private Intent mIntent;

private ArrayList data = new ArrayList();

public ViewRemoteService(Context context, Intent intent) {

Log.d("构造函数", "执行");

mContext = context;

mIntent = intent;

}

@Override

public void onCreate() {

Log.d("onCreate", "执行");

for (int i = 0; i < 5; i++) {

data.add("这是新闻" + i);

}

}

@Override

public void onDataSetChanged() {

}

@Override

public void onDestroy() {

data.clear();

}

@Override

public int getCount() {

return data.size();

}

@Override

public RemoteViews getViewAt(int position) {

//这里就类似getView函数了,但是实现点击同样是需要remoteview的

RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.item_layout);

views.setTextViewText(R.id.text, data.get(position));

//设置点击监听,反应事件在Widget中的onReceived中实现

views.setOnClickFillInIntent(R.id.item_layout, new Intent().putExtra("POSITION", position));

return views;

}

@Override

public RemoteViews getLoadingView() {

return null;

}

@Override

public int getViewTypeCount() {

return 1;

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public boolean hasStableIds() {

return true;

}

}

}

复制代码

我们回到Widget类的onReceived函数

case "com.longlong.COLLECTION_VIEW_ACTION":

Toast.makeText(context, String.valueOf(intent.getIntExtra("POSITION", -1)), Toast.LENGTH_SHORT).show();

复制代码

这里实现的是点击之后弹出Toast,响应点击的是哪个

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值