下拉刷新组件与侧滑菜单总结

来源:互联网 发布:和珅如何发家 知乎 编辑:程序博客网 时间:2024/06/07 05:47
由于在日常开发中,我们经常要用到下拉刷新组件,像QQ刷新好友那样的功能,或者像人人网那样左侧可以滑出一个菜单,于是之前在网上找了两个例子,当然是别人写的代码,在下还只是菜鸟一枚,只是下载的时间久了,没办法贴出原帖的地址了,如果原作者看到了也可以联系我或者帮我加上原帖的出处,这里先谢过那些无私奉献的高手们。两个DEMO已做为附件上传。
  前段时间一直在赶项目没什么时间,今天特意想到对之前用到的一些组件进行总结,之所以挑这两个组件,是因为这两个组件有许多共同之处,比如都是自定义组件,都是要求某一个组件根据用户的手指进行滑动,手指抬起之后都要自动滚动一段距离,然而不同的人有不同的编程风格,两个组件在一些实现细节上还是有许多不同之处,再就是对于我这样的初学者来说,这些代码还是很有难度的,至少我自己写不出来,看过几遍还是难以完全消化,所以以下对这两个组件写一些自己的理解,如有不妥之处欢迎各位指出。也希望能帮到那些跟我有一样困惑的朋友。

一、PullDownHeadrViewListView垂直排列于一个LinearLayout中,重写ListViewonTouchEvent方法)
1、手指滑动阶段(核心思想:getRawY的值不断相减算差值,再与HeaderViewlayoutParams.height进行加减运算):
1action_down时获取getRawY()的值,记录;
2action_move时不断用当前的getRawY的值减去down时的getRawY的值,做为差值deltaY,减完后还要将当前的y值做为最后的y值,下次的getRawY做差值是跟记录下的最新的getRawY做差值,而不再是down时的getRawY的值;
3HeaderViewlayoutParams.height加上或减去deltaY,再对HeaderView进行setLayoutParams

2、自动滚动阶段(没有使用ScrollTo方法,还是跟上边一样用layoutParams.heightdeltaY进行加减运算,只不过deltaYTimerTimerTask自动生成):
1当检测到UP时先new一个Timer类实例;
2timer实例每10毫秒new一个TimerTask类实例(因为Timer类的方法中要求传入你定义的TimerTask实例(其实TimerTaskRunnable接口的实现类,里边有run方法,每new一次run方法就会被调用一次),其实本质上就是每10毫秒执行一次你定义的方法);
3接下来就是在TimerTask中写你定义的方法了,在run体中写,注意这个run体运行在子线程,表面上看不出来,所以更新UI的操作要放在主线程当中,具体怎么做我想不必我细说了,用handler向主线程发送消息就可以了;那么具体做法就是HeaderViewlayoutParams.height10个像素,由于这里的run方法会每10毫秒调用一次,所以每10毫秒高度减10,就形成类似于动画的效果了;
4当发现已经滚动到我们想要的位置了,要调用TimerTaskcancel()方法取消Timer的时间表。

二、SliddingMenuMenuViewContentView重叠放到一个RelativeLayout中,重写ContentViewonTouchEvent事件)
1、手指滑动阶段(核心思想:event.getX()getScrollX运算后的值做为最终的滚动位置传入ViewGroupscrollTo()方法中):
1action_down时记录getX()的值;
2action_move时用当前的getX减去down时记录的x,并用当前的x替换down时的x,以便下次减时用getX减这次记录的x,做为deltaX
3紧接着还是在action_move中,用ViewGroupgetScrollX+deltaX做为组件当前的X值;
4ViewGroupscrollTo()方法将其子View滑动到当前X位置(注意是子View,其内部的直接子View是个FrameLayout,而整个ContentView其实不动,这也是为什么ContentView要继承ViewGroup的原因之一)。

2、自动滚动阶段(核心思想:算出要滚动的距离,用Scroller组件生成要滚动到的位置,还是传入scrollTo方法):
1当检测到UP事件时开始自动滚动;
2-MENU_WIDTH减去getScrollX做为要滚动的距离dx(或者直接就是getScrollX,取决于过没过MENU的中线,这里要注意getScrollX的值的正负,屏幕左边界还往左是正,屏幕左边界往右获取到的是负值);
3定义一个Scroller实例,将前两个参数(起始x,y)设置为当前的getScrollX,getScrollY,第三、第四个参数是要滚动的距离(注意不是滚动的终点,而是相对于起始的距离)设置为dxgetScrollY,这里由于不涉及纵向滚动,所以第四个参数设成什么都没关系,其实getScrollY一直是0
4重写ViewGroupcomputeScroll()方法(其实这个方法是View的),在这个方法中使用刚才定义好的scroller,如果scroller还在滚动,则获取scroller当前的x,y值,传入到scrollTo()方法中,将子View滑动到scoller的当前位置(注意scoller的起点是刚才UP时的getScrollX,getScollY的值)。

三、对比以上两个组件的实现方式
相同点是:
1都重写了ViewGrouponTouchEvent方法,都对downmoveup三个事件进行监听;
2都是在某一个子View中重写onTouchEvent方法,而不是在父容器中重写onTouchEvent,这一点很重要。例如在下拉刷新组件中,一个LinearLayout内部垂直放了HeaderViewListView,但并没有在LinearLayout中重写onTouchEvent,而是在ListView中重写onTouchEvent,这样可以在很大程度上减少一个父容器中各个子View之间的触摸冲突,也可以减少父容器与子View的触摸冲突,当然完全避免是不大可能的;侧滑组件也是这样,一个RelativeLayout中放了两个ViewGroup,分别是MenuViewContentView,却只在ContentView中重写onTouchEvent事件,实际上在常规方式下也只有ContentView在动,除非有特殊要求。

不同点是:
1第一个组件用gerRawY,获取的是该组件相对于屏幕左上角的位置,第二个组件用getX,获取的是相对其父容器左上角的位置;
2在实现组件跟随手指滑动的效果上,第一次组件是不断改变LinearLayout中第一个组件的高度,那么下边的组件自然就被“顶”下来或“挤”上去;而第二个组件用的是ViewGroup自带的scrollTo方法去挪动它子View的位置;
3在手指离开屏幕实现自动移动效果上,第一个组件用了线程,开启子线程,每10毫秒使LinearLayout的第一个组件的高度减10,实现了类似于动画的效果;而第二个组件则是另外一种思想,用一个现成的Scroller组件去scrollToView,也是实现了类似动画的效果。
  以上两个组件都想实现动画,却都没有使用animation,一个用Timer+TimerTask的线程思想,一个用scroller+scrollTo,通过逐渐改变组件坐标的思想去实现。
原创粉丝点击