下拉刷新组件与侧滑菜单总结
来源:互联网 发布:和珅如何发家 知乎 编辑:程序博客网 时间:2024/06/07 05:47
由于在日常开发中,我们经常要用到下拉刷新组件,像QQ刷新好友那样的功能,或者像人人网那样左侧可以滑出一个菜单,于是之前在网上找了两个例子,当然是别人写的代码,在下还只是菜鸟一枚,只是下载的时间久了,没办法贴出原帖的地址了,如果原作者看到了也可以联系我或者帮我加上原帖的出处,这里先谢过那些无私奉献的高手们。两个DEMO已做为附件上传。
前段时间一直在赶项目没什么时间,今天特意想到对之前用到的一些组件进行总结,之所以挑这两个组件,是因为这两个组件有许多共同之处,比如都是自定义组件,都是要求某一个组件根据用户的手指进行滑动,手指抬起之后都要自动滚动一段距离,然而不同的人有不同的编程风格,两个组件在一些实现细节上还是有许多不同之处,再就是对于我这样的初学者来说,这些代码还是很有难度的,至少我自己写不出来,看过几遍还是难以完全消化,所以以下对这两个组件写一些自己的理解,如有不妥之处欢迎各位指出。也希望能帮到那些跟我有一样困惑的朋友。
一、PullDown(HeadrView、ListView垂直排列于一个LinearLayout中,重写ListView的onTouchEvent方法)
1、手指滑动阶段(核心思想:getRawY的值不断相减算差值,再与HeaderView的layoutParams.height进行加减运算):
(1)action_down时获取getRawY()的值,记录;
(2)action_move时不断用当前的getRawY的值减去down时的getRawY的值,做为差值deltaY,减完后还要将当前的y值做为最后的y值,下次的getRawY做差值是跟记录下的最新的getRawY做差值,而不再是down时的getRawY的值;
(3)用HeaderView的layoutParams.height加上或减去deltaY,再对HeaderView进行setLayoutParams。
2、自动滚动阶段(没有使用ScrollTo方法,还是跟上边一样用layoutParams.height与deltaY进行加减运算,只不过deltaY由Timer和TimerTask自动生成):
(1)当检测到UP时先new一个Timer类实例;
(2)用timer实例每10毫秒new一个TimerTask类实例(因为Timer类的方法中要求传入你定义的TimerTask实例(其实TimerTask是Runnable接口的实现类,里边有run方法,每new一次run方法就会被调用一次),其实本质上就是每10毫秒执行一次你定义的方法);
(3)接下来就是在TimerTask中写你定义的方法了,在run体中写,注意这个run体运行在子线程,表面上看不出来,所以更新UI的操作要放在主线程当中,具体怎么做我想不必我细说了,用handler向主线程发送消息就可以了;那么具体做法就是HeaderView的layoutParams.height减10个像素,由于这里的run方法会每10毫秒调用一次,所以每10毫秒高度减10,就形成类似于动画的效果了;
(4)当发现已经滚动到我们想要的位置了,要调用TimerTask的cancel()方法取消Timer的时间表。
二、SliddingMenu(MenuView、ContentView重叠放到一个RelativeLayout中,重写ContentView的onTouchEvent事件)
1、手指滑动阶段(核心思想:event.getX()与getScrollX运算后的值做为最终的滚动位置传入ViewGroup的scrollTo()方法中):
(1)action_down时记录getX()的值;
(2)action_move时用当前的getX减去down时记录的x,并用当前的x替换down时的x,以便下次减时用getX减这次记录的x,做为deltaX;
(3)紧接着还是在action_move中,用ViewGroup的getScrollX+deltaX做为组件当前的X值;
(4)用ViewGroup的scrollTo()方法将其子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,第三、第四个参数是要滚动的距离(注意不是滚动的终点,而是相对于起始的距离)设置为dx和getScrollY,这里由于不涉及纵向滚动,所以第四个参数设成什么都没关系,其实getScrollY一直是0;
(4)重写ViewGroup的computeScroll()方法(其实这个方法是View的),在这个方法中使用刚才定义好的scroller,如果scroller还在滚动,则获取scroller当前的x,y值,传入到scrollTo()方法中,将子View滑动到scoller的当前位置(注意scoller的起点是刚才UP时的getScrollX,getScollY的值)。
三、对比以上两个组件的实现方式
相同点是:
(1)都重写了ViewGroup的onTouchEvent方法,都对down、move、up三个事件进行监听;
(2)都是在某一个子View中重写onTouchEvent方法,而不是在父容器中重写onTouchEvent,这一点很重要。例如在下拉刷新组件中,一个LinearLayout内部垂直放了HeaderView和ListView,但并没有在LinearLayout中重写onTouchEvent,而是在ListView中重写onTouchEvent,这样可以在很大程度上减少一个父容器中各个子View之间的触摸冲突,也可以减少父容器与子View的触摸冲突,当然完全避免是不大可能的;侧滑组件也是这样,一个RelativeLayout中放了两个ViewGroup,分别是MenuView和ContentView,却只在ContentView中重写onTouchEvent事件,实际上在常规方式下也只有ContentView在动,除非有特殊要求。
不同点是:
(1)第一个组件用gerRawY,获取的是该组件相对于屏幕左上角的位置,第二个组件用getX,获取的是相对其父容器左上角的位置;
(2)在实现组件跟随手指滑动的效果上,第一次组件是不断改变LinearLayout中第一个组件的高度,那么下边的组件自然就被“顶”下来或“挤”上去;而第二个组件用的是ViewGroup自带的scrollTo方法去挪动它子View的位置;
(3)在手指离开屏幕实现自动移动效果上,第一个组件用了线程,开启子线程,每10毫秒使LinearLayout的第一个组件的高度减10,实现了类似于动画的效果;而第二个组件则是另外一种思想,用一个现成的Scroller组件去scrollTo子View,也是实现了类似动画的效果。
以上两个组件都想实现动画,却都没有使用animation,一个用Timer+TimerTask的线程思想,一个用scroller+scrollTo,通过逐渐改变组件坐标的思想去实现。
前段时间一直在赶项目没什么时间,今天特意想到对之前用到的一些组件进行总结,之所以挑这两个组件,是因为这两个组件有许多共同之处,比如都是自定义组件,都是要求某一个组件根据用户的手指进行滑动,手指抬起之后都要自动滚动一段距离,然而不同的人有不同的编程风格,两个组件在一些实现细节上还是有许多不同之处,再就是对于我这样的初学者来说,这些代码还是很有难度的,至少我自己写不出来,看过几遍还是难以完全消化,所以以下对这两个组件写一些自己的理解,如有不妥之处欢迎各位指出。也希望能帮到那些跟我有一样困惑的朋友。
一、PullDown(HeadrView、ListView垂直排列于一个LinearLayout中,重写ListView的onTouchEvent方法)
1、手指滑动阶段(核心思想:getRawY的值不断相减算差值,再与HeaderView的layoutParams.height进行加减运算):
(1)action_down时获取getRawY()的值,记录;
(2)action_move时不断用当前的getRawY的值减去down时的getRawY的值,做为差值deltaY,减完后还要将当前的y值做为最后的y值,下次的getRawY做差值是跟记录下的最新的getRawY做差值,而不再是down时的getRawY的值;
(3)用HeaderView的layoutParams.height加上或减去deltaY,再对HeaderView进行setLayoutParams。
2、自动滚动阶段(没有使用ScrollTo方法,还是跟上边一样用layoutParams.height与deltaY进行加减运算,只不过deltaY由Timer和TimerTask自动生成):
(1)当检测到UP时先new一个Timer类实例;
(2)用timer实例每10毫秒new一个TimerTask类实例(因为Timer类的方法中要求传入你定义的TimerTask实例(其实TimerTask是Runnable接口的实现类,里边有run方法,每new一次run方法就会被调用一次),其实本质上就是每10毫秒执行一次你定义的方法);
(3)接下来就是在TimerTask中写你定义的方法了,在run体中写,注意这个run体运行在子线程,表面上看不出来,所以更新UI的操作要放在主线程当中,具体怎么做我想不必我细说了,用handler向主线程发送消息就可以了;那么具体做法就是HeaderView的layoutParams.height减10个像素,由于这里的run方法会每10毫秒调用一次,所以每10毫秒高度减10,就形成类似于动画的效果了;
(4)当发现已经滚动到我们想要的位置了,要调用TimerTask的cancel()方法取消Timer的时间表。
二、SliddingMenu(MenuView、ContentView重叠放到一个RelativeLayout中,重写ContentView的onTouchEvent事件)
1、手指滑动阶段(核心思想:event.getX()与getScrollX运算后的值做为最终的滚动位置传入ViewGroup的scrollTo()方法中):
(1)action_down时记录getX()的值;
(2)action_move时用当前的getX减去down时记录的x,并用当前的x替换down时的x,以便下次减时用getX减这次记录的x,做为deltaX;
(3)紧接着还是在action_move中,用ViewGroup的getScrollX+deltaX做为组件当前的X值;
(4)用ViewGroup的scrollTo()方法将其子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,第三、第四个参数是要滚动的距离(注意不是滚动的终点,而是相对于起始的距离)设置为dx和getScrollY,这里由于不涉及纵向滚动,所以第四个参数设成什么都没关系,其实getScrollY一直是0;
(4)重写ViewGroup的computeScroll()方法(其实这个方法是View的),在这个方法中使用刚才定义好的scroller,如果scroller还在滚动,则获取scroller当前的x,y值,传入到scrollTo()方法中,将子View滑动到scoller的当前位置(注意scoller的起点是刚才UP时的getScrollX,getScollY的值)。
三、对比以上两个组件的实现方式
相同点是:
(1)都重写了ViewGroup的onTouchEvent方法,都对down、move、up三个事件进行监听;
(2)都是在某一个子View中重写onTouchEvent方法,而不是在父容器中重写onTouchEvent,这一点很重要。例如在下拉刷新组件中,一个LinearLayout内部垂直放了HeaderView和ListView,但并没有在LinearLayout中重写onTouchEvent,而是在ListView中重写onTouchEvent,这样可以在很大程度上减少一个父容器中各个子View之间的触摸冲突,也可以减少父容器与子View的触摸冲突,当然完全避免是不大可能的;侧滑组件也是这样,一个RelativeLayout中放了两个ViewGroup,分别是MenuView和ContentView,却只在ContentView中重写onTouchEvent事件,实际上在常规方式下也只有ContentView在动,除非有特殊要求。
不同点是:
(1)第一个组件用gerRawY,获取的是该组件相对于屏幕左上角的位置,第二个组件用getX,获取的是相对其父容器左上角的位置;
(2)在实现组件跟随手指滑动的效果上,第一次组件是不断改变LinearLayout中第一个组件的高度,那么下边的组件自然就被“顶”下来或“挤”上去;而第二个组件用的是ViewGroup自带的scrollTo方法去挪动它子View的位置;
(3)在手指离开屏幕实现自动移动效果上,第一个组件用了线程,开启子线程,每10毫秒使LinearLayout的第一个组件的高度减10,实现了类似于动画的效果;而第二个组件则是另外一种思想,用一个现成的Scroller组件去scrollTo子View,也是实现了类似动画的效果。
以上两个组件都想实现动画,却都没有使用animation,一个用Timer+TimerTask的线程思想,一个用scroller+scrollTo,通过逐渐改变组件坐标的思想去实现。
- 下拉刷新组件与侧滑菜单总结
- Android“上拉刷新/下拉加载”与“侧滑菜单”的兼容
- PullToRefresh 下拉刷新菜单
- Android下拉刷新组件
- 下拉刷新组件SwipeRefreshLayout
- 下拉刷新组件SwipeRefreshLayout
- Bootstrap下拉菜单组件
- Bootstrap组件--下拉菜单
- Android下拉刷新与菜单及ListView的应用
- android--仿微博下拉刷新菜单
- 29、下拉刷新组件SwipeLayout
- 自定义下拉刷新组件SuperSwipeRefreshLayout
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- 集下拉刷新、自动加载和侧滑菜单的RecyclerView基本实现原理
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载
- 《Head.First设计模式》的学习笔记(2)--策略模式
- 百度收购91无线,效果未必如愿
- maven详解之生命周期与插件(一)
- java参数
- 深入了解Struts2返回JSON数据的原理及具体应用范例
- 下拉刷新组件与侧滑菜单总结
- java classLoader介绍
- Ural 1548 Sakura and Statistics
- 《Head.First设计模式》的学习笔记(3)--观察者模式
- Ubuntu下调试Qt报错ptrace operation not permitted
- socket中的SO_REUSEADDR
- VMware8安装centos的vmtool 增强包的问题,终端界面下
- Socket programming FAQ
- 黑马程序员 自学日记(二) java基础 二