您的位置:首页 > 其它

自定义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,并在布局文件中引入该自定义类

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();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息