自定义ViewGroup实现侧滑功能
2016-11-21 19:56
127 查看
首先我们必须知道:事件分发是Android中非常重要的机制,是用户与界面交互的基础。与事件分发相关的方法主要有三个:
dispatchTouchEvent();分发
onInterceptTouchEvent:拦截
onTouchEvent();触摸,消费
而事件分发一般会经过三种容器,分别为Activity、ViewGroup、View。onInterceptTouchEvent比较特殊,只有在ViewGroup容器中才存在.
其三个方法所代表的含义为:
分发: dispatchTouchEvent如果返回true,则表示在当前View或者其子View(子子…View)中,找到了处理事件的View;反之,则表示没有寻找到
拦截: onInterceptTouchEvent如果返回true,则表示这个事件由当前View进行处理,不管处理结果如何,都不会再向子View传递这个事件;反之,则表示当前View不主动处理这个事件,除非他的子View返回的事件分发结果为false
触摸消费: onTouchEvent如果返回true,则表示当前View就是事件传递的终点;反之,则表示当前View不是事件传递的终点
在发生触摸消费的时候:触摸事件是一个先自顶向下分发的过程,最早发送在activity,接着activity向下传递到第一个
viewGroup,viewGroup将事件接着往下传递,一直传到除了需要处理这个事件的类。如果一直没有任何控件能够出来这个事件,事件就会往上传递,一直到activity。
代码实现效果图:
1,自定义类继承ViewGroup,并在布局文件中引入该自定义类
dispatchTouchEvent();分发
onInterceptTouchEvent:拦截
onTouchEvent();触摸,消费
而事件分发一般会经过三种容器,分别为Activity、ViewGroup、View。onInterceptTouchEvent比较特殊,只有在ViewGroup容器中才存在.
其三个方法所代表的含义为:
分发: dispatchTouchEvent如果返回true,则表示在当前View或者其子View(子子…View)中,找到了处理事件的View;反之,则表示没有寻找到
拦截: onInterceptTouchEvent如果返回true,则表示这个事件由当前View进行处理,不管处理结果如何,都不会再向子View传递这个事件;反之,则表示当前View不主动处理这个事件,除非他的子View返回的事件分发结果为false
触摸消费: onTouchEvent如果返回true,则表示当前View就是事件传递的终点;反之,则表示当前View不是事件传递的终点
在发生触摸消费的时候:触摸事件是一个先自顶向下分发的过程,最早发送在activity,接着activity向下传递到第一个
viewGroup,viewGroup将事件接着往下传递,一直传到除了需要处理这个事件的类。如果一直没有任何控件能够出来这个事件,事件就会往上传递,一直到activity。
代码实现效果图:
1,自定义类继承ViewGroup,并在布局文件中引入该自定义类
package com.m520it.myapplication; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; /** * @author * @time * @desc */ //不利用其坐标的变化实现移动 public class SlideMeun2 extends ViewGroup { private View mMeunView; private View mContentView; private int mMeunHeight; private int mMeunWidth; private int mContentHeight; private int mContentWidth; private float mStartX; private float mStartY; private Scroller mScroller; private int mScarollX; public SlideMeun2(Context context) { super(context); } public SlideMeun2(Context context, AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); } //测量获取子控件的宽高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mMeunView = getChildAt(0); mContentView = getChildAt(1); measureChild(mMeunView, widthMeasureSpec, heightMeasureSpec); measureChild(mContentView, widthMeasureSpec, heightMeasureSpec); mMeunHeight = mMeunView.getMeasuredHeight(); mMeunWidth = mMeunView.getMeasuredWidth(); mContentHeight = mContentView.getMeasuredHeight(); mContentWidth = mContentView.getMeasuredWidth(); } @Override protected void onLayout(boolean b, int i, int i1, int i2, int i3) { //布局-->左上右下 mMeunView.layout(-mMeunWidth, 0, 0, mMeunHeight); mContentView.layout(0, 0, mContentWidth, mContentHeight); } int mInterceptDx = 0; //触摸事件的拦截 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int eventAction = ev.getAction(); switch (eventAction) { case MotionEvent.ACTION_DOWN: mStartX = ev.getX(); mStartY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float newX = ev.getX(); float newY = ev.getY(); //偏移量 float dx = newX - mStartX; mInterceptDx += dx; mStartX = newX; mStartY = newY; if (Math.abs(mInterceptDx) > 2) { //认为是水平的滑动,开始拦截 返回true就代表拦截 return true; } break; case MotionEvent.ACTION_UP: break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { //按下 case MotionEvent.ACTION_DOWN: mStartX = event.getX(); mStartY = event.getY(); break; //移动 case MotionEvent.ACTION_MOVE: float newX = event.getX(); float newY = event.getY(); float dx = newX - mStartX; //利用scroll来实现其滚动,其参数表示的是偏移量 //底层是调用scrollTo() scrollBy((int) -dx, 0); //获取到当前滚动位置的x坐标 mScarollX = getScrollX(); if (mScarollX < -mMeunWidth) { //直接回滚到某个地方,其参数表示的是具体的坐标点 scrollTo(-mMeunWidth, 0); } if (mScarollX > 0) { scrollTo(0, 0); } mStartX = newX; mStartY = newY; break; //抬起 case MotionEvent.ACTION_UP: //同样是获取当前的X点坐标 mScarollX = getScrollX(); /* 以提供的起始点和将要滑动的距离开始滚动。滚动会使用缺省值250ms作为持续时间。 startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动 startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动 dx 水平方向滑动的距离,正值会使滚动向左滚动 dy 垂直方向滑动的距离,正值会使滚动向上滚动*/ if (mScarollX <= -mMeunWidth / 2) { //完全展示 mScroller.startScroll(mScarollX, 0, -mMeunWidth - mScarollX, 0); } else { //收缩 mScroller.startScroll(mScarollX, 0, 0 - mScarollX, 0); } invalidate(); break; } return true; } //必须覆写此方法,才能实现其滚动(才能让ScrollBAy()和scrollTo()生效) @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { //获取当前滚动的x点位置 int currX = mScroller.getCurrX(); //移动到当前的位置 scrollTo(currX, 0); //重新绘制 invalidate(); } } }
相关文章推荐
- SwipeListView实现QQ消息侧滑删除功能
- 实现左右侧滑功能
- RESideMenu左右半侧滑的功能实现,主视图会和状态栏(StatusBar)不会随着一起滑动
- [android]手把手通过一个类实现侧滑退出activity功能
- qml listview 实现QQ侧滑删除功能
- DrawerLayout实现简单的侧滑功能
- Android LRecyclerView实现Item侧滑菜单、长按拖拽Item、滑动删除Item等功能
- SlidingMenu实现app侧滑功能
- Android学习之仿QQ侧滑功能的实现
- Android简单实现侧滑功能
- Fragement替换Tabhost,实现侧滑功能
- 类似QQ侧滑菜单功能实现
- 实现侧滑功能 CDRTranslucentSideBar<转>
- DrawerLayout+ListView+AutoCompleteTextView实现侧滑+提示+筛选+再次筛选数据功能
- JDSideMenu实现(整块)侧滑功能,主视图会和状态栏(StatusBar)会一起滑动。
- Android一步一步带你实现RecyclerView的拖拽和侧滑删除功能
- 实现在退出activity或按back键的侧滑功能
- iOS,侧滑(最简单效果却很好的侧滑功能实现
- 简单的方法实现侧滑功能
- 怎样实现安卓中侧滑功能