ScrollView 嵌套listview 问题解决

package com.autotalent.carjob.view;

import android.content.Context;
import android.os.Handler;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ScrollView;

import com.autotalent.carjob.util.LogUtils;

/*
 * ScrollView并没有实现滚动监听,所以我们必须自行实现对ScrollView的监听,
 * 我们很自然的想到在onTouchEvent()方法中实现对滚动Y轴进行监听
 * ScrollView的滚动Y值进行监听
 */
public class MyScrollView extends ScrollView {
    private OnScrollListener onScrollListener;
    /**
     * 主要是用在用户手指离开MyScrollViewMyScrollView还在继续滑动,我们用来保存Y的距离,然后做比较 
     */
    private int lastScrollY;

    public MyScrollView(Context context) {
        super(context, null);
        init();
    }
    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        init();

    }
    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
    void init(){
//        setOverScrollMode(OVER_SCROLL_NEVER);
    }


    /**
     * 设置滚动接口 
     * @param onScrollListener
     */
    public void setOnScrollListener(OnScrollListener onScrollListener){
        this.onScrollListener = onScrollListener;
    }
    /**
     * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中 
     */
//    private Handler handler = new Handler() {
//
//        public void handleMessage(android.os.Message msg) {
//            int scrollY = MyScrollView.this.getScrollY();
//
//            //此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息
//            if(lastScrollY != scrollY){
//                lastScrollY = scrollY;
//                handler.sendMessageDelayed(handler.obtainMessage(), 5);
//            }
//            if(onScrollListener != null){
//                onScrollListener.onScroll(scrollY);
//            }
//
//        };
//
//    };
    boolean disallowInterceptTouchEvent;

    public void setDisallowInterceptTouchEvent(boolean disallowInterceptTouchEvent) {
        LogUtils.e("setDisallowInterceptTouchEvent "+disallowInterceptTouchEvent);
        this.disallowInterceptTouchEvent = disallowInterceptTouchEvent;
        requestDisallowInterceptTouchEvent(disallowInterceptTouchEvent);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        LogUtils.e("MyScrollView.onScrollChanged "+t);
        super.onScrollChanged(l, t, oldl, oldt);
        if(maxScrollY<0){
            maxScrollY=computeVerticalScrollRange()-getHeight();
        }
        if(t>=maxScrollY){
            LogUtils.e(getClass().getSimpleName()+" overScroll "+t);
            t=maxScrollY;
            scrollTo(0,t);
            setDisallowInterceptTouchEvent(true);
        }else{
            setDisallowInterceptTouchEvent(false);
        }

//        if(t!=oldt){
//            if(canChildScrollDown()){
//                setDisallowInterceptTouchEvent(false);
//            }else{
//                setDisallowInterceptTouchEvent(true);
//            }
//        }
    }
//    public void computeScroll() {
//        super.computeScroll();
//        LogUtils.e("MyScrollView.computeScroll");
//    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        LogUtils.e(getClass().getSimpleName() + " onLayout changed==" + changed);
        requestChildFocus(getChildAt(0), null);
        super.onLayout(changed, l, t, r, b);
        LogUtils.e("after MyScrollView.onLayout getScrollY()==" + getScrollY());
        if(mChildScrollView!=null){//向下滚动了
            if(canChildScrollDown()){
                LogUtils.e(getClass().getSimpleName() + " 未滑动到底部");
                if(canChildScrollUp(mChildScrollView)){
                    if(mChildScrollView instanceof AbsListView){
                        ((AbsListView) mChildScrollView).setSelection(0);
                    }
                    else {
                        mChildScrollView.scrollTo(0,0);
                    }
                }

            }
        }
    }
    //如果嵌套listview listview会变成焦点控件,会自动滚动到焦点控件,详见源码
    @Override
    public void requestChildFocus(View child, View focused) {
        LogUtils.e(getClass().getSimpleName() + " requestChildFocus" );
    }

    @Override
    public void scrollTo(int x, int y) {
        LogUtils.e(getClass().getSimpleName() + " scrollTo");
        super.scrollTo(x, y);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        LogUtils.e(getClass().getSimpleName()+".onSizeChanged");
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        LogUtils.e(getClass().getSimpleName()+" onInterceptTouchEvent");
        if(disallowInterceptTouchEvent){
            super.onInterceptTouchEvent(ev);
            return false;
        }
        return super.onInterceptTouchEvent(ev);
    }
    ViewGroup mChildScrollView;

    public void setChildScrollView(ViewGroup mChildScrollView) {
        this.mChildScrollView = mChildScrollView;
    }

    /**
     * 重写onTouchEvent, 当用户的手在MyScrollView上面的时候,
     * 直接将MyScrollView滑动的Y方向距离回调给onScroll方法中,当用户抬起手的时候,
     * MyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理
     * MyScrollView滑动的距离
     */
    boolean firstDownEvent=true;
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
//        LogUtils.e("ScrollView.onTouchEvent");
        if(disallowInterceptTouchEvent) {
            if (mChildScrollView != null) {
//            LogUtils.e("mChildScrollView=="+mChildScrollView);
                if (firstDownEvent) {
                    firstDownEvent = false;
                    ev.setAction(MotionEvent.ACTION_DOWN);
                }
                return mChildScrollView.dispatchTouchEvent(ev);
            } else {
                try {
                    return super.onTouchEvent(ev);
                } catch (Exception e) {
                    LogUtils.e("disallowInterceptTouchEvent and mChildScrollView==null");
                    e.printStackTrace();
                    return true;
                }
            }
        }else{
            firstDownEvent=true;
        }
//        switch(ev.getAction()){
//            case MotionEvent.ACTION_UP:
//                handler.sendMessageDelayed(handler.obtainMessage(), 20);
//                break;
//        }
//        if(onScrollListener != null){
//            onScrollListener.onScroll(lastScrollY = this.getScrollY());
//        }
        try {
            return super.onTouchEvent(ev);
        } catch (Exception e) {
            e.printStackTrace();
//            ev.setAction(MotionEvent.ACTION_DOWN);
//            try {
//                return super.onTouchEvent(ev);
//            } catch (Exception e1) {
//                e1.printStackTrace();
//            }
        }
        return true;
    }

    /**
     * 滚动的回调接口
     */
    public interface OnScrollListener{
        /**
         * 回调方法, 返回MyScrollView滑动的Y方向距离
         */
        public void onScroll(int scrollY);
    }
    int maxScrollY=-1;
    public boolean canChildScrollDown() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if(maxScrollY<0){
                maxScrollY=computeVerticalScrollRange()-getHeight();
            }
            return ViewCompat.canScrollVertically(this, 1) || getScrollY() < maxScrollY ;
        } else {
            return ViewCompat.canScrollVertically(this, 1);
        }
    }
    public boolean canChildScrollUp(View mTarget) {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (mTarget instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) mTarget;
                return absListView.getChildCount() > 0 &&
                        (absListView.getFirstVisiblePosition() > 0 ||
                                absListView.getChildAt(0).getTop() < absListView.getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(mTarget, -1) || mTarget.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(mTarget, -1);
        }
    }


}
package com.autotalent.carjob.view;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.widget.AbsListView;
import android.widget.ListView;

import com.autotalent.carjob.util.LogUtils;

/**
 *
 * @author zhourihu
 * @createdate 201558日 下午3:49:54
 * @Description: 非滚动的全部展示的listView
 */
public class NoScrollDownFromTopListView extends ListView{

    MyScrollView myScrollView;
    public NoScrollDownFromTopListView(Context context, AttributeSet attrs){
        super(context, attrs);
//        setOnScrollListener(new OnScrollListener() {
        //是否向上滚动
//        private boolean mIsScrollToUp = false;
//            //listView中第一项的索引
//            private int mListViewFirstItem = 0;
//            //listView中第一项的在屏幕中的位置
//            private int mScreenY = 0;
//
//            @Override
//            public void onScrollStateChanged(AbsListView view, int scrollState) {
//
//            }
//
//            @Override
//            public void onScroll(AbsListView absListView, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
//                ListView mListView=NoScrollDownFromTopListView.this;
//                if(mListView.getChildCount()>0)
//                {
//                    boolean isScrollToUp = false;
//                    View childAt = mListView.getChildAt(firstVisibleItem);
//                    int[] location = new int[2];
//                    childAt.getLocationOnScreen(location);
//                    Log.d("onScroll", "firstVisibleItem= " + firstVisibleItem + " , y=" + location[1]);
//
//                    if(firstVisibleItem!=mListViewFirstItem)
//                    {
//                        if(firstVisibleItem>mListViewFirstItem)
//                        {
//                            Log.e("--->", "向上滑动");
//                            isScrollToUp = true;
//                        }else{
//                            Log.e("--->", "向下滑动");
//                            isScrollToUp = false;
//                        }
//                        mListViewFirstItem = firstVisibleItem;
//                        mScreenY = location[1];
//                    }else{
//                        if(mScreenY>location[1])
//                        {
//                            Log.i("--->", "->向上滑动");
//                            isScrollToUp = true;
//                        }
//                        else if(mScreenY<location[1])
//                        {
//                            Log.i("--->", "->向下滑动");
//                            isScrollToUp = false;
//                        }
//                        mScreenY = location[1];
//                    }
//
//                    if(mIsScrollToUp!=isScrollToUp)
//                    {
//                        onScrollDirectionChanged(mIsScrollToUp);
//                    }
//
//                }
//            }
//            private void onScrollDirectionChanged(boolean isScrollToUp)
//            {
//
//            }
//        });
        setOverScrollMode(OVER_SCROLL_NEVER);
    }
    boolean hasFoundMyScrollview;
    private void findMyScrollview() {
        ViewParent parent=  getParent();
        while (parent instanceof View){
            View parentView= (View) parent;
            if(parentView instanceof MyScrollView){
                myScrollView= (MyScrollView) parentView;
                break;
            }
            parent=parentView.getParent();
        }
        hasFoundMyScrollview=true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(!hasFoundMyScrollview){
            findMyScrollview();
        }
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        LogUtils.e(getClass().getSimpleName() + " onLayout " );
        super.onLayout(changed, l, t, r, b);
//        if(myScrollView!=null){
//            myScrollView.setChildScrollView(this);
//        }
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
    }

    float lastY;
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
//        LogUtils.e(getClass().getSimpleName()+" onTouchEvent");
        if(myScrollView==null&&!hasFoundMyScrollview){
            findMyScrollview();
        }
//        myScrollView.setDisallowInterceptTouchEvent(true);
        if(!canChildScrollUp()){
            float distance=0;
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    lastY=ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }
            distance=ev.getY()-lastY;
            lastY=ev.getY();
            if(distance>0){
                LogUtils.e("向上滑动到顶部了 myScrollView=="+myScrollView);
                if(myScrollView!=null){
                    myScrollView.setDisallowInterceptTouchEvent(false);
                    return super.onTouchEvent(ev);
                }
            }
        }
        return super.onTouchEvent(ev);
    }
    public boolean canChildScrollUp() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            final AbsListView absListView = this;
            return absListView.getChildCount() > 0 &&
                    (absListView.getFirstVisiblePosition() > 0 ||
                            absListView.getChildAt(0).getTop() < absListView.getPaddingTop());
        } else {
            return ViewCompat.canScrollVertically(this, -1);
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
    }
    //    public boolean canChildScrollUp() {
//        if (android.os.Build.VERSION.SDK_INT < 14) {
//            if (mTarget instanceof AbsListView) {
//                final AbsListView absListView = (AbsListView) mTarget;
//                return absListView.getChildCount() > 0 &&
//                        (absListView.getFirstVisiblePosition() > 0 ||
//                                absListView.getChildAt(0).getTop() < absListView.getPaddingTop());
//            } else {
//                return ViewCompat.canScrollVertically(mTarget, -1) || mTarget.getScrollY() > 0;
//            }
//        } else {
//            return ViewCompat.canScrollVertically(mTarget, -1);
//        }
//    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值