横向滚动的listview

今天在实现业务需求的时候,抛出了一个展示已选人员的头像的需求。本想使用RecyclerView,但奈何项目使用的support包版本太低,又是用eclipse开发,写好后无法使用,故抛弃改用listview。

查找资料后,准备使用HorizontalListView,国外已大神写好的,准备引用到项目,后发现项目里面已经存在了...故直接使用。

使用方法和使用listview一样,设置adapter即可。

  1 public class HorizontalListView extends AdapterView<ListAdapter> {
  2 
  3     public boolean mAlwaysOverrideTouch = true;
  4     protected ListAdapter mAdapter;
  5     private int mLeftViewIndex = -1;
  6     private int mRightViewIndex = 0;
  7     protected int mCurrentX;
  8     protected int mNextX;
  9     private int mMaxX = Integer.MAX_VALUE;
 10     private int mDisplayOffset = 0;
 11     protected Scroller mScroller;
 12     private GestureDetector mGesture;
 13     private Queue<View> mRemovedViewQueue = new LinkedList<View>();
 14     private OnItemSelectedListener mOnItemSelected;
 15     private OnItemClickListener mOnItemClicked;
 16     private OnItemLongClickListener mOnItemLongClicked;
 17     private boolean mDataChanged = false;
 18 
 19     public HorizontalListView(Context context, AttributeSet attrs) {
 20         super(context, attrs);
 21         initView();
 22     }
 23 
 24     private synchronized void initView() {
 25         mLeftViewIndex = -1;
 26         mRightViewIndex = 0;
 27         mDisplayOffset = 0;
 28         mCurrentX = 0;
 29         mNextX = 0;
 30         mMaxX = Integer.MAX_VALUE;
 31         mScroller = new Scroller(getContext());
 32         mGesture = new GestureDetector(getContext(), mOnGesture);
 33     }
 34 
 35     @Override
 36     public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
 37         mOnItemSelected = listener;
 38     }
 39 
 40     @Override
 41     public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
 42         mOnItemClicked = listener;
 43     }
 44 
 45     @Override
 46     public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {
 47         mOnItemLongClicked = listener;
 48     }
 49 
 50     private DataSetObserver mDataObserver = new DataSetObserver() {
 51 
 52         @Override
 53         public void onChanged() {
 54             synchronized (HorizontalListView.this) {
 55                 mDataChanged = true;
 56             }
 57             invalidate();
 58             requestLayout();
 59         }
 60 
 61         @Override
 62         public void onInvalidated() {
 63             reset();
 64             invalidate();
 65             requestLayout();
 66         }
 67 
 68     };
 69 
 70     @Override
 71     public ListAdapter getAdapter() {
 72         return mAdapter;
 73     }
 74 
 75     @Override
 76     public View getSelectedView() {
 77         // TODO: implement
 78         return null;
 79     }
 80 
 81     @Override
 82     public void setAdapter(ListAdapter adapter) {
 83         if (mAdapter != null) {
 84             mAdapter.unregisterDataSetObserver(mDataObserver);
 85         }
 86         mAdapter = adapter;
 87         mAdapter.registerDataSetObserver(mDataObserver);
 88         reset();
 89     }
 90 
 91     private synchronized void reset() {
 92         initView();
 93         removeAllViewsInLayout();
 94         requestLayout();
 95     }
 96 
 97     @Override
 98     public void setSelection(int position) {
 99         // TODO: implement
100     }
101 
102     private void addAndMeasureChild(final View child, int viewPos) {
103         LayoutParams params = child.getLayoutParams();
104         if (params == null) {
105             params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
106         }
107 
108         addViewInLayout(child, viewPos, params, true);
109         child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
110                 MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
111     }
112 
113     @Override
114     protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) {
115         super.onLayout(changed, left, top, right, bottom);
116 
117         if (mAdapter == null) {
118             return;
119         }
120 
121         if (mDataChanged) {
122             int oldCurrentX = mCurrentX;
123             initView();
124             removeAllViewsInLayout();
125             mNextX = oldCurrentX;
126             mDataChanged = false;
127         }
128 
129         if (mScroller.computeScrollOffset()) {
130             int scrollx = mScroller.getCurrX();
131             mNextX = scrollx;
132         }
133 
134         if (mNextX <= 0) {
135             mNextX = 0;
136             mScroller.forceFinished(true);
137         }
138         if (mNextX >= mMaxX) {
139             mNextX = mMaxX;
140             mScroller.forceFinished(true);
141         }
142 
143         int dx = mCurrentX - mNextX;
144 
145         removeNonVisibleItems(dx);
146         fillList(dx);
147         positionItems(dx);
148 
149         mCurrentX = mNextX;
150 
151         if (!mScroller.isFinished()) {
152             post(new Runnable() {
153                 @Override
154                 public void run() {
155                     requestLayout();
156                 }
157             });
158 
159         }
160     }
161 
162     private void fillList(final int dx) {
163         int edge = 0;
164         View child = getChildAt(getChildCount() - 1);
165         if (child != null) {
166             edge = child.getRight();
167         }
168         fillListRight(edge, dx);
169 
170         edge = 0;
171         child = getChildAt(0);
172         if (child != null) {
173             edge = child.getLeft();
174         }
175         fillListLeft(edge, dx);
176 
177     }
178 
179     private void fillListRight(int rightEdge, final int dx) {
180         while (rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) {
181 
182             View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this);
183             addAndMeasureChild(child, -1);
184             rightEdge += child.getMeasuredWidth();
185 
186             if (mRightViewIndex == mAdapter.getCount() - 1) {
187                 mMaxX = mCurrentX + rightEdge - getWidth();
188             }
189 
190             if (mMaxX < 0) {
191                 mMaxX = 0;
192             }
193             mRightViewIndex++;
194         }
195 
196     }
197 
198     private void fillListLeft(int leftEdge, final int dx) {
199         while (leftEdge + dx > 0 && mLeftViewIndex >= 0) {
200             View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this);
201             addAndMeasureChild(child, 0);
202             leftEdge -= child.getMeasuredWidth();
203             mLeftViewIndex--;
204             mDisplayOffset -= child.getMeasuredWidth();
205         }
206     }
207 
208     private void removeNonVisibleItems(final int dx) {
209         View child = getChildAt(0);
210         while (child != null && child.getRight() + dx <= 0) {
211             mDisplayOffset += child.getMeasuredWidth();
212             mRemovedViewQueue.offer(child);
213             removeViewInLayout(child);
214             mLeftViewIndex++;
215             child = getChildAt(0);
216 
217         }
218 
219         child = getChildAt(getChildCount() - 1);
220         while (child != null && child.getLeft() + dx >= getWidth()) {
221             mRemovedViewQueue.offer(child);
222             removeViewInLayout(child);
223             mRightViewIndex--;
224             child = getChildAt(getChildCount() - 1);
225         }
226     }
227 
228     private void positionItems(final int dx) {
229         if (getChildCount() > 0) {
230             mDisplayOffset += dx;
231             int left = mDisplayOffset;
232             for (int i = 0; i < getChildCount(); i++) {
233                 View child = getChildAt(i);
234                 int childWidth = child.getMeasuredWidth();
235                 child.layout(left, 0, left + childWidth, child.getMeasuredHeight());
236                 left += childWidth + child.getPaddingRight();
237             }
238         }
239     }
240 
241     public synchronized void scrollTo(int x) {
242         mScroller.startScroll(mNextX, 0, x - mNextX, 0);
243         requestLayout();
244     }
245 
246     @Override
247     public boolean dispatchTouchEvent(MotionEvent ev) {
248         boolean handled = super.dispatchTouchEvent(ev);
249         handled |= mGesture.onTouchEvent(ev);
250         return handled;
251     }
252 
253     protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
254         synchronized (HorizontalListView.this) {
255             mScroller.fling(mNextX, 0, (int) -velocityX, 0, 0, mMaxX, 0, 0);
256         }
257         requestLayout();
258 
259         return true;
260     }
261 
262     protected boolean onDown(MotionEvent e) {
263         mScroller.forceFinished(true);
264         return true;
265     }
266 
267     private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {
268 
269         @Override
270         public boolean onDown(MotionEvent e) {
271             return HorizontalListView.this.onDown(e);
272         }
273 
274         @Override
275         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
276             return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY);
277         }
278 
279         @Override
280         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
281 
282             synchronized (HorizontalListView.this) {
283                 mNextX += (int) distanceX;
284             }
285             requestLayout();
286 
287             return true;
288         }
289 
290         @Override
291         public boolean onSingleTapConfirmed(MotionEvent e) {
292             for (int i = 0; i < getChildCount(); i++) {
293                 View child = getChildAt(i);
294                 if (isEventWithinView(e, child)) {
295                     if (mOnItemClicked != null) {
296                         mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i,
297                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));
298                     }
299                     if (mOnItemSelected != null) {
300                         mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i,
301                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));
302                     }
303                     break;
304                 }
305             }
306             return true;
307         }
308 
309         @Override
310         public void onLongPress(MotionEvent e) {
311             int childCount = getChildCount();
312             for (int i = 0; i < childCount; i++) {
313                 View child = getChildAt(i);
314                 if (isEventWithinView(e, child)) {
315                     if (mOnItemLongClicked != null) {
316                         mOnItemLongClicked.onItemLongClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i,
317                                 mAdapter.getItemId(mLeftViewIndex + 1 + i));
318                     }
319                     break;
320                 }
321             }
322         }
323 
324         private boolean isEventWithinView(MotionEvent e, View child) {
325             Rect viewRect = new Rect();
326             int[] childPosition = new int[2];
327             child.getLocationOnScreen(childPosition);
328             int left = childPosition[0];
329             int right = left + child.getWidth();
330             int top = childPosition[1];
331             int bottom = top + child.getHeight();
332             viewRect.set(left, top, right, bottom);
333             return viewRect.contains((int) e.getRawX(), (int) e.getRawY());
334         }
335     };
336 
337 }

 

posted @ 2016-11-30 15:20  HolySee  阅读(278)  评论(0编辑  收藏  举报