解决水平ListView在ScrollView中出现的滑动冲突

简介: <img src="http://dl2.iteye.com/upload/attachment/0094/0570/11bc8b98-6fdf-3cfd-bbcd-357d2c4c2f03.png" alt="" style="border:0px; font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-h
 

解决的问题有两个: 
1)实现水平滑动的ListView。重写AdapterView,上代码: 
Java代码   收藏代码
  1. package com.liucanwen.horizontallistview.view;  
  2.   
  3. import java.util.LinkedList;  
  4. import java.util.Queue;  
  5.   
  6. import android.content.Context;  
  7. import android.database.DataSetObserver;  
  8. import android.graphics.Rect;  
  9. import android.util.AttributeSet;  
  10. import android.view.GestureDetector;  
  11. import android.view.GestureDetector.OnGestureListener;  
  12. import android.view.View.MeasureSpec;  
  13. import android.view.MotionEvent;  
  14. import android.view.View;  
  15. import android.widget.AdapterView;  
  16. import android.widget.ListAdapter;  
  17. import android.widget.Scroller;  
  18.   
  19. /** 
  20.  * 重写ListView,以达到水平滑动 
  21.  */  
  22. public class HorizontalListView extends AdapterView<ListAdapter>  
  23. {  
  24.   
  25.     public boolean mAlwaysOverrideTouch = true;  
  26.     protected ListAdapter mAdapter;  
  27.     private int mLeftViewIndex = -1;  
  28.     private int mRightViewIndex = 0;  
  29.     protected int mCurrentX;  
  30.     protected int mNextX;  
  31.     private int mMaxX = Integer.MAX_VALUE;  
  32.     private int mDisplayOffset = 0;  
  33.     protected Scroller mScroller;  
  34.     private GestureDetector mGesture;  
  35.     private Queue<View> mRemovedViewQueue = new LinkedList<View>();  
  36.     private OnItemSelectedListener mOnItemSelected;  
  37.     private OnItemClickListener mOnItemClicked;  
  38.     private OnItemLongClickListener mOnItemLongClicked;  
  39.     private boolean mDataChanged = false;  
  40.   
  41.     public HorizontalListView(Context context, AttributeSet attrs)  
  42.     {  
  43.         super(context, attrs);  
  44.         initView();  
  45.     }  
  46.   
  47.     private synchronized void initView()  
  48.     {  
  49.         mLeftViewIndex = -1;  
  50.         mRightViewIndex = 0;  
  51.         mDisplayOffset = 0;  
  52.         mCurrentX = 0;  
  53.         mNextX = 0;  
  54.         mMaxX = Integer.MAX_VALUE;  
  55.         mScroller = new Scroller(getContext());  
  56.         mGesture = new GestureDetector(getContext(), mOnGesture);  
  57.     }  
  58.   
  59.     @Override  
  60.     public void setOnItemSelectedListener(  
  61.             AdapterView.OnItemSelectedListener listener)  
  62.     {  
  63.         mOnItemSelected = listener;  
  64.     }  
  65.   
  66.     @Override  
  67.     public void setOnItemClickListener(AdapterView.OnItemClickListener listener)  
  68.     {  
  69.         mOnItemClicked = listener;  
  70.     }  
  71.   
  72.     @Override  
  73.     public void setOnItemLongClickListener(  
  74.             AdapterView.OnItemLongClickListener listener)  
  75.     {  
  76.         mOnItemLongClicked = listener;  
  77.     }  
  78.   
  79.     private DataSetObserver mDataObserver = new DataSetObserver()  
  80.     {  
  81.   
  82.         @Override  
  83.         public void onChanged()  
  84.         {  
  85.             synchronized (HorizontalListView.this)  
  86.             {  
  87.                 mDataChanged = true;  
  88.             }  
  89.             invalidate();  
  90.             requestLayout();  
  91.         }  
  92.   
  93.         @Override  
  94.         public void onInvalidated()  
  95.         {  
  96.             reset();  
  97.             invalidate();  
  98.             requestLayout();  
  99.         }  
  100.   
  101.     };  
  102.   
  103.     @Override  
  104.     public ListAdapter getAdapter()  
  105.     {  
  106.         return mAdapter;  
  107.     }  
  108.   
  109.     @Override  
  110.     public View getSelectedView()  
  111.     {  
  112.         // TODO: implement  
  113.         return null;  
  114.     }  
  115.   
  116.     @Override  
  117.     public void setAdapter(ListAdapter adapter)  
  118.     {  
  119.         if (mAdapter != null)  
  120.         {  
  121.             mAdapter.unregisterDataSetObserver(mDataObserver);  
  122.         }  
  123.         mAdapter = adapter;  
  124.         mAdapter.registerDataSetObserver(mDataObserver);  
  125.         reset();  
  126.     }  
  127.   
  128.     private synchronized void reset()  
  129.     {  
  130.         initView();  
  131.         removeAllViewsInLayout();  
  132.         requestLayout();  
  133.     }  
  134.   
  135.     @Override  
  136.     public void setSelection(int position)  
  137.     {  
  138.         // TODO: implement  
  139.     }  
  140.   
  141.     private void addAndMeasureChild(final View child, int viewPos)  
  142.     {  
  143.         LayoutParams params = child.getLayoutParams();  
  144.         if (params == null)  
  145.         {  
  146.             params = new LayoutParams(LayoutParams.FILL_PARENT,  
  147.                     LayoutParams.FILL_PARENT);  
  148.         }  
  149.   
  150.         addViewInLayout(child, viewPos, params, true);  
  151.         child.measure(  
  152.                 MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),  
  153.                 MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));  
  154.     }  
  155.   
  156.     @Override  
  157.     protected synchronized void onLayout(boolean changed, int left, int top,  
  158.             int right, int bottom)  
  159.     {  
  160.         super.onLayout(changed, left, top, right, bottom);  
  161.   
  162.         if (mAdapter == null)  
  163.         {  
  164.             return;  
  165.         }  
  166.   
  167.         if (mDataChanged)  
  168.         {  
  169.             int oldCurrentX = mCurrentX;  
  170.             initView();  
  171.             removeAllViewsInLayout();  
  172.             mNextX = oldCurrentX;  
  173.             mDataChanged = false;  
  174.         }  
  175.   
  176.         if (mScroller.computeScrollOffset())  
  177.         {  
  178.             int scrollx = mScroller.getCurrX();  
  179.             mNextX = scrollx;  
  180.         }  
  181.   
  182.         if (mNextX <= 0)  
  183.         {  
  184.             mNextX = 0;  
  185.             mScroller.forceFinished(true);  
  186.         }  
  187.         if (mNextX >= mMaxX)  
  188.         {  
  189.             mNextX = mMaxX;  
  190.             mScroller.forceFinished(true);  
  191.         }  
  192.   
  193.         int dx = mCurrentX - mNextX;  
  194.   
  195.         removeNonVisibleItems(dx);  
  196.         fillList(dx);  
  197.         positionItems(dx);  
  198.   
  199.         mCurrentX = mNextX;  
  200.   
  201.         if (!mScroller.isFinished())  
  202.         {  
  203.             post(new Runnable()  
  204.             {  
  205.                 @Override  
  206.                 public void run()  
  207.                 {  
  208.                     requestLayout();  
  209.                 }  
  210.             });  
  211.   
  212.         }  
  213.     }  
  214.   
  215.     private void fillList(final int dx)  
  216.     {  
  217.         int edge = 0;  
  218.         View child = getChildAt(getChildCount() - 1);  
  219.         if (child != null)  
  220.         {  
  221.             edge = child.getRight();  
  222.         }  
  223.         fillListRight(edge, dx);  
  224.   
  225.         edge = 0;  
  226.         child = getChildAt(0);  
  227.         if (child != null)  
  228.         {  
  229.             edge = child.getLeft();  
  230.         }  
  231.         fillListLeft(edge, dx);  
  232.   
  233.     }  
  234.   
  235.     private void fillListRight(int rightEdge, final int dx)  
  236.     {  
  237.         while (rightEdge + dx < getWidth()  
  238.                 && mRightViewIndex < mAdapter.getCount())  
  239.         {  
  240.   
  241.             View child = mAdapter.getView(mRightViewIndex,  
  242.                     mRemovedViewQueue.poll(), this);  
  243.             addAndMeasureChild(child, -1);  
  244.             rightEdge += child.getMeasuredWidth();  
  245.   
  246.             if (mRightViewIndex == mAdapter.getCount() - 1)  
  247.             {  
  248.                 mMaxX = mCurrentX + rightEdge - getWidth();  
  249.             }  
  250.   
  251.             if (mMaxX < 0)  
  252.             {  
  253.                 mMaxX = 0;  
  254.             }  
  255.             mRightViewIndex++;  
  256.         }  
  257.   
  258.     }  
  259.   
  260.     private void fillListLeft(int leftEdge, final int dx)  
  261.     {  
  262.         while (leftEdge + dx > 0 && mLeftViewIndex >= 0)  
  263.         {  
  264.             View child = mAdapter.getView(mLeftViewIndex,  
  265.                     mRemovedViewQueue.poll(), this);  
  266.             addAndMeasureChild(child, 0);  
  267.             leftEdge -= child.getMeasuredWidth();  
  268.             mLeftViewIndex--;  
  269.             mDisplayOffset -= child.getMeasuredWidth();  
  270.         }  
  271.     }  
  272.   
  273.     private void removeNonVisibleItems(final int dx)  
  274.     {  
  275.         View child = getChildAt(0);  
  276.         while (child != null && child.getRight() + dx <= 0)  
  277.         {  
  278.             mDisplayOffset += child.getMeasuredWidth();  
  279.             mRemovedViewQueue.offer(child);  
  280.             removeViewInLayout(child);  
  281.             mLeftViewIndex++;  
  282.             child = getChildAt(0);  
  283.   
  284.         }  
  285.   
  286.         child = getChildAt(getChildCount() - 1);  
  287.         while (child != null && child.getLeft() + dx >= getWidth())  
  288.         {  
  289.             mRemovedViewQueue.offer(child);  
  290.             removeViewInLayout(child);  
  291.             mRightViewIndex--;  
  292.             child = getChildAt(getChildCount() - 1);  
  293.         }  
  294.     }  
  295.   
  296.     private void positionItems(final int dx)  
  297.     {  
  298.         if (getChildCount() > 0)  
  299.         {  
  300.             mDisplayOffset += dx;  
  301.             int left = mDisplayOffset;  
  302.             for (int i = 0; i < getChildCount(); i++)  
  303.             {  
  304.                 View child = getChildAt(i);  
  305.                 int childWidth = child.getMeasuredWidth();  
  306.                 child.layout(left, 0, left + childWidth,  
  307.                         child.getMeasuredHeight());  
  308.                 left += childWidth + child.getPaddingRight();  
  309.             }  
  310.         }  
  311.     }  
  312.   
  313.     public synchronized void scrollTo(int x)  
  314.     {  
  315.         mScroller.startScroll(mNextX, 0, x - mNextX, 0);  
  316.         requestLayout();  
  317.     }  
  318.   
  319.     @Override  
  320.     public boolean dispatchTouchEvent(MotionEvent ev)  
  321.     {  
  322.         boolean handled = super.dispatchTouchEvent(ev);  
  323.         handled |= mGesture.onTouchEvent(ev);  
  324.         return handled;  
  325.     }  
  326.   
  327.     protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  328.             float velocityY)  
  329.     {  
  330.         synchronized (HorizontalListView.this)  
  331.         {  
  332.             mScroller.fling(mNextX, 0, (int) -velocityX, 00, mMaxX, 00);  
  333.         }  
  334.         requestLayout();  
  335.   
  336.         return true;  
  337.     }  
  338.   
  339.     protected boolean onDown(MotionEvent e)  
  340.     {  
  341.         mScroller.forceFinished(true);  
  342.         return true;  
  343.     }  
  344.   
  345.     private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener()  
  346.     {  
  347.   
  348.         @Override  
  349.         public boolean onDown(MotionEvent e)  
  350.         {  
  351.             return HorizontalListView.this.onDown(e);  
  352.         }  
  353.   
  354.         @Override  
  355.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  356.                 float velocityY)  
  357.         {  
  358.             return HorizontalListView.this  
  359.                     .onFling(e1, e2, velocityX, velocityY);  
  360.         }  
  361.   
  362.         @Override  
  363.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  364.                 float distanceX, float distanceY)  
  365.         {  
  366.   
  367.             synchronized (HorizontalListView.this)  
  368.             {  
  369.                 mNextX += (int) distanceX;  
  370.             }  
  371.             requestLayout();  
  372.   
  373.             return true;  
  374.         }  
  375.   
  376.         @Override  
  377.         public boolean onSingleTapConfirmed(MotionEvent e)  
  378.         {  
  379.             for (int i = 0; i < getChildCount(); i++)  
  380.             {  
  381.                 View child = getChildAt(i);  
  382.                 if (isEventWithinView(e, child))  
  383.                 {  
  384.                     if (mOnItemClicked != null)  
  385.                     {  
  386.                         mOnItemClicked.onItemClick(HorizontalListView.this,  
  387.                                 child, mLeftViewIndex + 1 + i,  
  388.                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));  
  389.                     }  
  390.                     if (mOnItemSelected != null)  
  391.                     {  
  392.                         mOnItemSelected.onItemSelected(HorizontalListView.this,  
  393.                                 child, mLeftViewIndex + 1 + i,  
  394.                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));  
  395.                     }  
  396.                     break;  
  397.                 }  
  398.   
  399.             }  
  400.             return true;  
  401.         }  
  402.   
  403.         @Override  
  404.         public void onLongPress(MotionEvent e)  
  405.         {  
  406.             int childCount = getChildCount();  
  407.             for (int i = 0; i < childCount; i++)  
  408.             {  
  409.                 View child = getChildAt(i);  
  410.                 if (isEventWithinView(e, child))  
  411.                 {  
  412.                     if (mOnItemLongClicked != null)  
  413.                     {  
  414.                         mOnItemLongClicked.onItemLongClick(  
  415.                                 HorizontalListView.this, child, mLeftViewIndex  
  416.                                         + 1 + i,  
  417.                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));  
  418.                     }  
  419.                     break;  
  420.                 }  
  421.   
  422.             }  
  423.         }  
  424.   
  425.         private boolean isEventWithinView(MotionEvent e, View child)  
  426.         {  
  427.             Rect viewRect = new Rect();  
  428.             int[] childPosition = new int[2];  
  429.             child.getLocationOnScreen(childPosition);  
  430.             int left = childPosition[0];  
  431.             int right = left + child.getWidth();  
  432.             int top = childPosition[1];  
  433.             int bottom = top + child.getHeight();  
  434.             viewRect.set(left, top, right, bottom);  
  435.             return viewRect.contains((int) e.getRawX(), (int) e.getRawY());  
  436.         }  
  437.     };  
  438.   
  439. }  



2)第一步实现了水平滑动,往往我们会把这个水平ListView放到ScrollView里面(见截图实现),而这两个控件恰好滑动会有冲突,滑动水平ListView时会有卡顿,因此重写ScrollView,以达到流畅滑动: 
Java代码   收藏代码
  1. package com.liucanwen.horizontallistview.view;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.view.GestureDetector;  
  6. import android.view.GestureDetector.SimpleOnGestureListener;  
  7. import android.view.MotionEvent;  
  8. import android.view.View;  
  9. import android.widget.ScrollView;  
  10.   
  11. /** 
  12.  * 重写ScrollView,以解决ScrollView与水平listView滑动时冲突 
  13.  */  
  14. public class MyScrollView extends ScrollView  
  15. {  
  16.     private GestureDetector mGestureDetector;  
  17.     View.OnTouchListener mGestureListener;  
  18.   
  19.     public MyScrollView(Context context, AttributeSet attrs)  
  20.     {  
  21.         super(context, attrs);  
  22.         mGestureDetector = new GestureDetector(new YScrollDetector());  
  23.         setFadingEdgeLength(0);  
  24.     }  
  25.   
  26.     @Override  
  27.     public boolean onInterceptTouchEvent(MotionEvent ev)  
  28.     {  
  29.         return super.onInterceptTouchEvent(ev)  
  30.                 && mGestureDetector.onTouchEvent(ev);  
  31.     }  
  32.   
  33.     class YScrollDetector extends SimpleOnGestureListener  
  34.     {  
  35.         @Override  
  36.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  37.                 float distanceX, float distanceY)  
  38.         {  
  39.             if (Math.abs(distanceY) > Math.abs(distanceX))  
  40.             {  
  41.                 return true;  
  42.             }  
  43.             return false;  
  44.         }  
  45.     }  
  46. }  



好了,大功告成! 
以下系项目的源代码下载地址: 
http://download.csdn.net/detail/qq15989177612/6943633
目录
相关文章
|
8月前
|
XML Java Android开发
Android 中ScrollView垂直滚动视图之隐藏滚动条的三种方法
Android 中ScrollView垂直滚动视图之隐藏滚动条的三种方法
91 0
|
10月前
解决ListView显示不全、滑动冲突问题
解决ListView显示不全、滑动冲突问题
|
10月前
|
Android开发
ScrollView 与 ListView 以及 GridView 滑动冲突完美解决
ScrollView 与 ListView 以及 GridView 滑动冲突完美解决
SwipeRefreshLayout 嵌套ScrollView 滑动冲突
SwipeRefreshLayout 嵌套ScrollView 滑动冲突
202 0
|
Android开发
NestedScrollView + ExpandableListView 显示不全问题和滑动冲突问题 。
NestedScrollView + ExpandableListView 显示不全问题和滑动冲突问题 。
还在为ScrollView嵌套RecyclerView而发愁吗?
还在为ScrollView嵌套RecyclerView而发愁吗?
163 0
|
Android开发 容器 Java
Android取消RecyclerView、ListView、ScrollView、HorizontalScrollView滑动到边缘闪现灰白色水波纹动画
Android取消RecyclerView、ListView、ScrollView、HorizontalScrollView滑动到边缘闪现灰白色水波纹动画 标准的Android RecyclerView、ListView、ScrollView、HorizontalScrollView滑动到边缘,会闪现灰白色水波纹动画,以这样大的动画效果提示用户已经滑动到边缘,没法再滑动了。
2924 0
|
前端开发
02.自定义View(RippleTextView可颜色渐变的TextView)
感谢红橙Darren博主 package com.rzm.commonlibrary.views; import android.content.Context; import android.
971 0