上一篇讲了如何用代码的方式把appwidget添加到桌面上,如果没看的话可以看一下http://blog.csdn.net/so_strange/article/details/51014151
前面我把appwidget添加到桌面上后,客户又提出了要添加左右滑动翻页的要求.我们知道,appwidget用的是RemoteViews,我又用了GridView,想要滑动翻页,必须要对事件做处理,RemoteViews有不支持自定义的view,目前对我来讲,我还没有找到让RemoteViews支持自定义view的方法.所以我只能在appwidget的父view上面想办法.先上代码:
public class RecommendationWidgetLayout extends RelativeLayout {
private static final String WIDGET_TURN_TO_PREV_PAGE_ACTION = "com.android.bookstore.provider.BUT_PREV_PAGE_ACTION";
private static final String WIDGET_TURN_TO_NEXT_PAGE_ACTION = "com.android.bookstore.provider.BUT_NEXT_PAGE_ACTION";
private float lastX;
public RecommendationWidgetLayout(Context context) {
this(context, null);
}
public RecommendationWidgetLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch(ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
lastX = ev.getX();
break;
case MotionEvent.ACTION_MOVE:
return detectDirection(ev) != PageTurningDirection.None;
case MotionEvent.ACTION_UP:
default:
break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
break;
case MotionEvent.ACTION_UP:
PageTurningDirection direction = detectDirection(event);
if (direction == PageTurningDirection.Left) {
turnToPrevPage();
} else if (direction == PageTurningDirection.Right) {
turnToNextPage();
}
break;
default:
break;
}
return true;
}
private void turnToPrevPage() {
sendUpdateWidgetBroadcast(WIDGET_TURN_TO_PREV_PAGE_ACTION);
}
private void turnToNextPage() {
sendUpdateWidgetBroadcast(WIDGET_TURN_TO_NEXT_PAGE_ACTION);
}
private PageTurningDirection detectDirection(MotionEvent currentEvent) {
return PageTurningDetector.detectLeftOrRight(getContext(), (int) (currentEvent.getX() - lastX));
}
private void sendUpdateWidgetBroadcast(String action) {
getContext().sendBroadcast(new Intent(action));
}
}
public abstract class PageTurningDetector {
public static PageTurningDirection detectLeftOrRight(Context context, int deltaX)
{
int x_DELTA_THRESHOLD = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics());
if (Math.abs(deltaX) < x_DELTA_THRESHOLD) {
return PageTurningDirection.None;
}
return deltaX > 0 ? PageTurningDirection.Left : PageTurningDirection.Right;
}
首先自定义的layout继承RelativeLayout,因为这里只是简单的添加一个AppWidgetHostView,所以只需要重写onInterceptTouchEvent和onTouchEvent这两个方法. onInterceptTouchEvent是viewgroup的方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。
onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。
关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。
1.down事件首先会传递到onInterceptTouchEvent()方法
2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
4.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。
上面这段话摘自http://blog.csdn.net/lvxiangan/article/details/9309927,分析的很好,大家一看就明白了,我就不在这里画蛇添足了.(其实我是菜鸟...你懂的...)
在detectLeftOrRight()函数里有一个20,这个就是滑动距离的参照,如果滑动的距离小于它,就不算是滑动,不用拦截.当然这个你自己在实际过程中可以自己改动.
至于更新widget肯定是发广播了,因为本身AppWidgetProvider extends android.content.BroadcastReceiver.需要在onReceive里面处理,这里就不再多说了.不知道的可以查下AppWidgetProvider的说明文档.提醒一下,上面的两个Action一定要在AndroidManifest.xml里面配置哦.本人就犯过这种低级错误.一定要记得配置广播的Action!一定要记得配置广播的Action!一定要记得配置广播的Action!重要的事情说三遍.
以上的办法其实没有解决根本问题,如何让appwidget自己的view可以实现滑动事件的处理,我还没想到办法,知道的大牛可以告诉我下.Thank you very much !