自定义Layout用ViewGroup+ListView+GridView进行滑动事件拦截

来源:互联网 发布:如何装修出租屋知乎 编辑:程序博客网 时间:2024/06/06 01:10

详细解析请看:http://blog.csdn.net/android_tutor/article/details/7193090

onInterceptTouchEvent:

onInterceptTouchEvent是在ViewGroup里面定义的。Android中的layout布局类一般都是继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每个手势事件都会先调用onInterceptTouchEvent。

onTouchEvent:

onTouchEvent同样也是在view中定义的一个方法。处理传递到view 的手势事件。手势事件类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL等事件。

其中Layout里的onInterceptTouchEvent默认返回值是false,这样touch事件会传递到View控件,Layout里的onTouch默认返回值是false, View里的onTouch默认返回值是true,当我们手指点击屏幕时候,先调用ACTION_DOWN事件,当onTouch里返回值是true的时候,onTouch回继续调用ACTION_UP事件,如果onTouch里返回值是false,那么onTouch只会调用ACTION_DOWN而不调用ACTION_UP.

先看一下效果:


public class MoveUpLayoutextends LinearLayout {


privatestaticfinal StringTAG ="TAG";

    publicint_currentStatus = STATUS_EXPANDED// 当前状态

    public static final int STATUS_EXPANDED = 1; // 展开状态

    public static final int STATUS_COLLAPSED = 2; // 收缩状态

    private OnMoveUpTouchListener onMoveUpTouchListener// 向上滑动监听 事件

    

    

    private View _headerView// 头部view

    private View _contentView;// 底部view

    

    privateint_originalHeaderViewHeight// 初始化时(原始)的头部高度

    privateint_currentHeaderViewHeight; //  当前头部高度(可变的高度)

    private int _touchSlop;// 移动的最小距离

    

    private boolean _isMove =true// 是否滑动

    // 分别记录上次滑动的坐标

    private float _lastX = 0;

    private float _mLastY = 0;


    // 分别记录上次滑动的坐标(onInterceptTouchEvent)

    privatefloat_lastXIntercept = 0;

    privatefloat_lastYIntercept = 0;

    

public MoveUpLayout(Context context, AttributeSet attrs,int defStyle) {

super(context, attrs, defStyle);

}

public MoveUpLayout(Context context, AttributeSet attrs) {

super(context, attrs);

}

public MoveUpLayout(Context context) {

super(context);

}

// 当获取到屏幕焦点时,会调用该方法

@Override

public void onWindowFocusChanged(boolean hasWindowFocus) {

// TODO Auto-generated method stub

super.onWindowFocusChanged(hasWindowFocus);

// 该方法只在第一显示该视图时,才执行,只执行一次

if (hasWindowFocus && (_headerView ==null ||_contentView ==null)) {

this.initHeaderAndContentView();

}

}


private void initHeaderAndContentView(){

int count =this.getChildCount();

if (count > 0 && count <= 2) {

_headerView =this.getChildAt(0);

_contentView =this.getChildAt(1);

_originalHeaderViewHeight =_headerView.getMeasuredHeight();

_currentHeaderViewHeight =_originalHeaderViewHeight;

//初始化移动的最小判断距离

_touchSlop = ViewConfiguration.get(this.getContext()).getScaledTouchSlop();

debug("_originalHeaderViewHeight="+_originalHeaderViewHeight+",_touchSlop="+_touchSlop);

}

}

// 触屏 事件拦截

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

boolean isIntercept =false;

float x = ev.getX();

float y = ev.getY();

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

_lastXIntercept = x;

_lastYIntercept = y;

_lastX = x;

_mLastY = y;

isIntercept = false;

break;

case MotionEvent.ACTION_MOVE:

float distance = y -_lastYIntercept;

debug("onInterceptTouchEvent-ACTION_MOVE:distance="+distance+",=_currentStatus:"+_currentStatus);

// 向上滑动

if (_currentStatus ==STATUS_EXPANDED && distance <= -_touchSlop) {

isIntercept = true;

}elseif (onMoveUpTouchListener !=null) { // 向下滑动

if (onMoveUpTouchListener.moveUpTouchEvent(ev) && distance >=_touchSlop) {

isIntercept = true;

}

}

break;

case MotionEvent.ACTION_UP:

isIntercept = false;

_lastXIntercept = 0;

_lastYIntercept = 0;

break;

}

debug("onInterceptTouchEvent.x="+x+",y="+y+","+ev.getAction()+",isIntercept="+isIntercept);

// 返回true 调用onTouch的ACTION_DOWN、ACTION_UP

// 返回false 调用onTouch 的ACTION_DOWN

return isIntercept &&_isMove;// 默认返回值是false ,不拦截消息

// return false;  //不拦截事件

}

// 执行滑动事件

@Override

public boolean onTouchEvent(MotionEvent event) {

if (!_isMove) {

returntrue;

}

float x = event.getX();

float y = event.getY();

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:


break;

case MotionEvent.ACTION_MOVE:

// float distanceX = x - _lastX;

float distanceY = y -_mLastY;

// 跟随滑动去的距离,动态的改变headerView的大小

//注意: 这行代码很重要,跟随滑动的位置,改变头部View的当前高度

_currentHeaderViewHeight += (int)distanceY; 

setHeaderViewHeight(_currentHeaderViewHeight);

break;

case MotionEvent.ACTION_UP:

            // 这里做了下判断,当松开手的时候,会自动向两边滑动,具体向哪边滑,要看当前所处的位置

int distance = 0;// 滑动距离

//  当向下滑动时,滑动距离小于头部原高度一半时,还原原来收缩(隐藏)状态

            if (_currentHeaderViewHeight <=_originalHeaderViewHeight * 0.5) {

            distance = 0;

                _currentStatus =STATUS_COLLAPSED;

            } else {

            // 当向上滑动时,滑动距离小于头部原高度一半时,还原原来扩展(展开)状态

            distance = _originalHeaderViewHeight;

                _currentStatus =STATUS_EXPANDED;

            }

            // 慢慢滑向终点

            setSmoothHeaderHeight(_currentHeaderViewHeight, distance, 500);

break;

}

// debug("onTouchEvent.x="+x+",y="+y+","+event.getAction());


_lastX = x; // 当前位置设置为点击屏幕的位置

_mLastY = y;

// ViewGroup里的onTouchEvent默认值是false。

// View里的onTouchEvent返回默认值是true

returntrue;

}

/**************

* 设置头部的高度,并更新当前视图

* @param height

*/

private void setHeaderViewHeight(int height){

// 当头部的高度小于零时,等于零

if (height < 0) {

height = 0;

}elseif (height >_originalHeaderViewHeight) {

// 当头部的高度大于原高度时,等于原高度

height = _originalHeaderViewHeight;

}

if (_headerView !=null &&_headerView.getLayoutParams() !=null) {

_headerView.getLayoutParams().height = height;// 改变头部View的高度

_headerView.requestLayout();//请求重新加载头部视图

_currentHeaderViewHeight = height;

}

debug("setHeaderView:Height="+height+",_currentHeaderViewHeight="+_currentHeaderViewHeight);

}

/***************

* 快速滑动或滑动到头部高度一半时调用,起平滑过度作用

* @param from  当前头部高度

* @param to   移动的目标高度

* @param duration  过度时长

*/

private void setSmoothHeaderHeight(final int from, final int to, final int duration){

final int frameCount = (int) (duration / 1000f * 30) + 1;// 过度帧数,起平滑过度效果

        final float partation = (to - from) / (float) frameCount;// 每帧移动距离

        new Thread("Thread") {


            @Override

            public void run() {

                for (int i = 0; i < frameCount; i++) {

                    final int height;

                    if (i == frameCount - 1) {// 当为最后一帧时,设置为目标位置

                        height = to;

                    } else {// 向 to目标进行过度

                        height = (int) (from + partation * i);

                    }

                    // 更新高度

                    post(new Runnable() {

                        public void run() {

                        setHeaderViewHeight(height);

                        }

                    });

                    try {

                        sleep(10);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            };


        }.start();

}

public void setOnMoveUpTouchListener(OnMoveUpTouchListener onMoveUpTouchListener) {

this.onMoveUpTouchListener = onMoveUpTouchListener;

}


public boolean isMove() {

return_isMove;

}


public void setMove(boolean isMove) {

this._isMove = isMove;

}


public void debug(String msg){

Log.i(TAG, msg);

}

public interface OnMoveUpTouchListener{

        public boolean moveUpTouchEvent(MotionEvent event);


}

}


在Actiivty中实现OnMoveUpTouchListener接口,这个接口是判断在什么时候,可以向下滑动,展开头的内容

@Override

public boolean moveUpTouchEvent(MotionEvent event) {

Log.i("TAG""moveUpTouchEvent");

// Listview是否显示的是第一项

if (listview.getFirstVisiblePosition() == 0) {

View view = listview.getChildAt(0);

// 显示第一个项时,可以向下滑动

if (view != null && view.getTop() >= 0) {

return true;

}

};

return false;

}









0 0
原创粉丝点击