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; /** * 主要是用在用户手指离开MyScrollView,MyScrollView还在继续滑动,我们用来保存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 2015年5月8日 下午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); // } // } }
ScrollView 嵌套listview 问题解决
最新推荐文章于 2019-06-04 20:48:24 发布