自定义ViewGroup(这里以自定义一个类似ViewPager的控件为例)
2015-07-18 10:36
399 查看
首先,我们得先要明白ViewGroup是什么,职责是什么?
ViewGroup就是用来放置View控件的的容器,职责是测量每一个子view的大小,还有摆放的位置。
* 1,写一个类继承于ViewGroup
* 2,重载onMeasure方法,用于测量的子View的大小
* 3,重载onLayout,用于安置子view的位置
到这里,一个ViewGroup就算自定义完成了,
下面的步骤是实现ViewGroup的功能
想要实现子类滑动的效果,就要借助Scroller这个类,这个类的使用请参考http://blog.csdn.net/qq_15949077/article/details/46940507
* 4.然后通过Gesturector手势识别器的ontuchEvent屏幕监听器即可实现页面的滑动
* 5,最后写一个内部接口,对外提供一个监听的set方法
看代码吧,这是一个实现类似viewPager的例子,里面的Scroller类作用很大
ViewGroup就是用来放置View控件的的容器,职责是测量每一个子view的大小,还有摆放的位置。
* 1,写一个类继承于ViewGroup
* 2,重载onMeasure方法,用于测量的子View的大小
* 3,重载onLayout,用于安置子view的位置
到这里,一个ViewGroup就算自定义完成了,
下面的步骤是实现ViewGroup的功能
想要实现子类滑动的效果,就要借助Scroller这个类,这个类的使用请参考http://blog.csdn.net/qq_15949077/article/details/46940507
* 4.然后通过Gesturector手势识别器的ontuchEvent屏幕监听器即可实现页面的滑动
* 5,最后写一个内部接口,对外提供一个监听的set方法
看代码吧,这是一个实现类似viewPager的例子,里面的Scroller类作用很大
public class MyViewGroup extends ViewGroup { GestureDetector gd;//手势识别器 Scroller scroll; int itemID=0; int firstX; int lastX; int dis; boolean isFling; itemChangelistener listener; /** * 事件中断器用的变量 */ int downx; int downy; int movex; int movey; int distancex; int distancey; public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub scroll=new Scroller(context); gd=new GestureDetector(context, new OnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub if(itemID==0&&distanceX<0){ } else if(itemID==getChildCount()-1&&distanceX>0){ } else{ scrollBy((int) distanceX, 0); } return false; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub isFling=true; if(itemID==0&&velocityX>0){ } else if(itemID==getChildCount()-1&&velocityX<0){ } else if(velocityX>0){ itemID--; } else if(velocityX<0){ itemID++; } return false; } @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } }); } //测量子view的大小 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); for(int i=0;i<this.getChildCount();i++){ getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } } //指定子View的位置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub for(int i=0;i<this.getChildCount();i++){ getChildAt(i).layout(i*getWidth(), 0, i*getWidth()+getWidth(), getHeight()); } } /** * 事件中断器 * 比较上下和左右移动的距离谁大,大的就移动谁 * * * 如果返回值为true:则代表事件到这来被中断掉,就会执行自己的onTouchEvent, * 注意,奇怪的是从move开始,而不是down,所以在down里有做处理的要注意, * 而且这里有时会产生跳动bug,原因不知道,理解不了,(不是因为从move开始执行的原因,因为在down都没做处理的情况下也一样跳动) * 解决这个bug的方法也很简单,在dowm的方法里将这个事件传给手势识别器就ok了 * * 如果返回值为false:将不会执行onTouchEvent方法,而是把事件传给子控件 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub boolean result=false; switch(ev.getAction()){ case MotionEvent.ACTION_DOWN: gd.onTouchEvent(ev); downx=(int) ev.getX(); downy=(int) ev.getY(); break; case MotionEvent.ACTION_MOVE: movex=(int) ev.getX(); movey=(int) ev.getY(); distancex=Math.abs(movex-downx); distancey=Math.abs(movey-downy); if(distancex>distancey&&distancex>10){ result= true; } else{ result= false; } // else if(distancex<distancey&&distancey>10){ // result= false; // } break; } return result; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub gd.onTouchEvent(event); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: firstX=(int)event.getX(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: lastX=(int) event.getX(); dis=lastX-firstX; if(!isFling){ if(itemID==0&&dis>0){ } else if(itemID==getChildCount()-1&&dis<0){ } else if(dis>0&&dis>getWidth()/5){ itemID--; } else if(dis<0&&Math.abs(dis)>getWidth()/5){ itemID++; } } myScrollto(itemID); break; } return true; } /** * 开始移动 * @param ItemID */ public void myScrollto(int itemID){ if(listener!=null){ listener.itemID(itemID); } int dis=itemID*getWidth()-getScrollX(); scroll.startScroll(getScrollX(), 0, dis, 0, Math.abs(dis)); invalidate(); } /** * 执行invalidata方法后回调 */ @Override public void computeScroll() { // TODO Auto-generated method stub super.computeScroll(); if(scroll.computeScrollOffset()){ scrollTo(scroll.getCurrX(), 0); invalidate(); } else{ isFling=false; } } /** * 对外部提供的设置指定页面的方法 * @param itemID */ public void setItemID(int itemID){ this.itemID=itemID; myScrollto(itemID); } /** * 对外提供一个监听页面改变后获取id的方法 * @param listener */ public void setonItemChangelistener(itemChangelistener listener){ this.listener=listener; } /** * 对外提供的滑动到哪个页面id的接口 * @author Administrator * */ interface itemChangelistener{ void itemID(int ItemID); } }
相关文章推荐
- [译]用R语言做挖掘数据《三》
- web.py安装时出现ImportError: No module named 'utils'
- 《RocketMQ 安装和使用》
- SSL/TLS协议运行机制的概述
- 设计一个算法,采用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G采用邻接表存储)
- LeetCode 118 Pascal's Triangle
- [LeetCode][Java] Minimum Window Substring
- 【实训项目】银行储蓄系统
- Secure Boot
- 地道
- SSL/TLS协议运行机制的概述
- linux运维人员需要知道的重要/常用目录介绍
- ajax提交form表单的两种方法
- 1048. Find Coins (25)
- [UEFI启动教程][第三章]BIOS锁定纯UEFI启动的解锁办法
- 3Sum
- wordpress添加后台菜单及权限设置
- java初学笔记20150718.十进制数转换为二进
- 1048. Find Coins (25)
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)