横向ListView中嵌套ListView


最近有个需求,横向列表中,每项又是一个垂直列表。在HorizontalListView的Adapter中使用Listview后,HorizontalListView不能左右滑动。


1,解决这个问题,先来看几个基础的方法:,

View类中:

    /**
     * Pass the touch screen motion event down to the target view, or this
     * view if it is the target.
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     */
    public boolean dispatchTouchEvent(MotionEvent event) {

@Override
    public boolean onTouchEvent(MotionEvent event) {


/**
     * {@inheritDoc}
     */
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {

ViewGroup类中:注意加粗有下划线的部分的内容

/**
     * Implement this method to intercept all touch screen motion events.  This
     * allows you to watch events as they are dispatched to your children, and
     * take ownership of the current gesture at any point.
     *
     * <p>Using this function takes some care, as it has a fairly complicated
     * interaction with {@link View#onTouchEvent(MotionEvent)
     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
     * that method as well as this one in the correct way.  Events will be
     * received in the following order:
     *
     * <ol>
     * <li> You will receive the down event here.
     * <li> The down event will be handled either by a child of this view
     * group, or given to your own onTouchEvent() method to handle; this means
     * you should implement onTouchEvent() to return true, so you will
     * continue to see the rest of the gesture (instead of looking for
     * a parent view to handle it).  Also, by returning true from
     * onTouchEvent(), you will not receive any following
     * events in onInterceptTouchEvent() and all touch processing must
     * happen in onTouchEvent() like normal.
     * <li> For as long as you return false from this function, each following
     * event (up to and including the final up) will be delivered first here
     * and then to the target's onTouchEvent().
     * <li> If you return true from here, you will not receive any
     * following events: the target view will receive the same event but
     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
     * events will be delivered to your onTouchEvent() method and no longer
     * appear here.
     * </ol>
     *
     * @param ev The motion event being dispatched down the hierarchy.
     * <strong><u><span style="color:#ff0000;">@return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.</span></u></strong>
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }

2,测试代码

HorizontalListView每个item为ListView,ListView的每个Item为TextView,Touch事件分发过程为:

</pre><pre code_snippet_id="1570234" snippet_file_name="blog_20160130_7_9380784" name="code" class="html">--------- beginning of main
--------- beginning of system
D/DemoApp (20605): MyHorizontalListView dispatchTouchEvent:0
D/DemoApp (20605): MyHorizontalListView onInterceptTouchEvent:0
D/DemoApp (20605): MyListView dispatchTouchEvent:0
D/DemoApp (20605): MyListView onInterceptTouchEvent:0
D/DemoApp (20605): MyTextView dispatchTouchEvent:0
D/DemoApp (20605): MyTextView onTouchEvent:0
D/DemoApp (20605): MyListView onTouchEvent:0, gestureDealed:true
D/DemoApp (20605): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (20605): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (20605): MyListView dispatchTouchEvent:2
D/DemoApp (20605): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (20605): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (20605): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (20605): MyListView dispatchTouchEvent:2
D/DemoApp (20605): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (20605): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (20605): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (20605): MyListView dispatchTouchEvent:2
D/DemoApp (20605): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (20605): MyHorizontalListView dispatchTouchEvent:1
D/DemoApp (20605): MyHorizontalListView onInterceptTouchEvent:1
D/DemoApp (20605): MyListView dispatchTouchEvent:1
D/DemoApp (20605): MyListView onTouchEvent:1, gestureDealed:false


3,我们再来看View类中的方法:
<pre name="code" class="html">/**
     * {@inheritDoc}
     */
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
            // We're already in this state, assume our ancestors are too
            return;
        }

        if (disallowIntercept) {
            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
        } else {
            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        }

        // Pass it up to our parent
        if (mParent != null) {
            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
        }
    }


 当子类调用请求父类拦截时,主要最开始标红色部分的说明。在下一个Touch事件,父控件会直接交给自己的onTouchEvent处理。 

4,所以,为了满足需求我们做如下改造:

自定义MyListView类,修改的地方为:定义手势检测,横向滑动不处理

private GestureDetector mGestureDetector;

    /** 是否忽略该滑动事件,忽略则交给父控件处理 */
    private boolean ignoreEvent = false;

    /** 是否已经判断过滑动方向 */
    private boolean checkedDirection = false;

    private GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {
            ignoreEvent = false;
            checkedDirection = false;
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            if (!checkedDirection) {
                checkedDirection = true;
                if (Math.abs(velocityX) > Math.abs(velocityY)) {
                    ignoreEvent = true;
                    return false;
                }
            }
            if(ignoreEvent){
                return false;
            }

            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

            if (!checkedDirection) {
                checkedDirection = true;
                if (Math.abs(distanceX) > 3 && Math.abs(distanceX) > Math.abs(distanceY)) {
                    ignoreEvent = true;
                    return false;
                }
            }

            if(ignoreEvent){
                return false;
            }

            return true;
        }
    };

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean gestureDealed = mGestureDetector.onTouchEvent(ev);
        GyLog.d(TAG, "onTouchEvent:" + ev.getAction() +", gestureDealed:"+gestureDealed);

        if(checkedDirection && ignoreEvent){
            requestDisallowInterceptTouchEvent(!ignoreEvent);
        }

        if (!gestureDealed) {
            return false;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        GyLog.d(TAG, "requestDisallowInterceptTouchEvent:" + disallowIntercept);
        super.requestDisallowInterceptTouchEvent(disallowIntercept);

        ViewParent parent = getParent();
        while (parent != null){
            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
            parent = parent.getParent();
        }
    }

MyHorizontalListView的改动:


/** 是否拦截touch事件 */
	private boolean interceptTouchEvent = false;

	@Override
	public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
		GyLog.d(TAG, "requestDisallowInterceptTouchEvent:" + disallowIntercept);

		interceptTouchEvent = !disallowIntercept;

		super.requestDisallowInterceptTouchEvent(disallowIntercept);
	}

@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		GyLog.d(TAG, "onInterceptTouchEvent:"+ ev.getAction());

		if(ev.getAction() == MotionEvent.ACTION_DOWN){
			interceptTouchEvent = false;
		}

		return interceptTouchEvent;


//		return super.onInterceptTouchEvent(ev);
	}

5,再来看Touch分发流程:
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:0
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:0
D/DemoApp (28089): MyListView dispatchTouchEvent:0
D/DemoApp (28089): MyListView onInterceptTouchEvent:0
D/DemoApp (28089): MyTextView dispatchTouchEvent:0
D/DemoApp (28089): MyTextView onTouchEvent:0
D/DemoApp (28089): MyListView onTouchEvent:0, gestureDealed:true
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:2
D/DemoApp (28089): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:2
D/DemoApp (28089): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:2
D/DemoApp (28089): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:2
D/DemoApp (28089): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:2
D/DemoApp (28089): MyListView onTouchEvent:2, gestureDealed:false
D/DemoApp (28089): MyListView requestDisallowInterceptTouchEvent:false
D/DemoApp (28089): MyHorizontalListView requestDisallowInterceptTouchEvent:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onInterceptTouchEvent:2
D/DemoApp (28089): MyListView dispatchTouchEvent:3
D/DemoApp (28089): MyListView onTouchEvent:3, gestureDealed:false
D/DemoApp (28089): MyListView requestDisallowInterceptTouchEvent:false
D/DemoApp (28089): MyHorizontalListView requestDisallowInterceptTouchEvent:false
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:2
D/DemoApp (28089): MyHorizontalListView onTouchEvent:2
D/DemoApp (28089): MyHorizontalListView dispatchTouchEvent:1
D/DemoApp (28089): MyHorizontalListView onTouchEvent:1

冲突解决。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值