package com.geekband.luminous.homework.widget; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Adapter; import android.widget.AdapterView; import java.util.LinkedList; /** * custom twice * Created by luminous on 15/8/15. */ public class MyHorizontalListView extends AdapterView { public static final String TAG = "MHV"; /** 滚动的状态 */ public static final int TOUCH_STATE_SCROLLING = 2; /** 没有点击的状态 */ private static final int TOUCH_STATE_RESTING = 0; /** 点击的状态 */ private static final int TOUCH_STATE_CLICK = 1; /** 用于判定是否为scroll的threshold */ static int TOUCH_THRESHOLD = 10; Adapter mAdapter; /** 列表的最左边 */ int mListLeft; /** 手指点下去的X */ int mTouchDownX; /** 手指点下去的Y */ int mTouchDownY; /** 测量时的List的右边缘,超出屏幕则不再添加View */ int rightEdge; /** 测量时得List得左边缘,超出屏幕则不在添加View */ int leftEdge; /** 最后一个加入的View的position */ int myLastAddPosition = -1; /** layout中的第一个View的position */ int myFirstViewPosition; LinkedList<View> cacheViews = new LinkedList<>(); /** 按键状态 */ private int mTouchState = TOUCH_STATE_RESTING; private Runnable longClickHandler; public MyHorizontalListView(Context context, AttributeSet attrs) { super(context, attrs); this.setClickable(true); TOUCH_THRESHOLD = ViewConfiguration.get(context).getScaledPagingTouchSlop(); } @Override public Adapter getAdapter() { return mAdapter; } @Override public void setAdapter(Adapter adapter) { this.mAdapter = adapter; } @Override public View getSelectedView() { throw new UnsupportedOperationException("Not supported"); } @Override public void setSelection(int position) { throw new UnsupportedOperationException("Not supported"); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } //TODO:reconstruct the method @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (mAdapter == null || mAdapter.getCount() <= 0) { return; } //新添加的View没有被layout,所以left,right的值都是错误的,不能在add之后调用remove //remove left while (getChildCount() > 0 && getChildAt(0).getRight() < 0) { View firstView = getChildAt(0); cacheViews.addLast(firstView); mListLeft += firstView.getWidth(); leftEdge += firstView.getMeasuredWidth(); removeViewInLayout(firstView); myFirstViewPosition++; //Log.w(TAG, "onLayout after remove left views count:" + getChildCount()); } //remove right while (getChildCount() > 0 && getChildAt(getChildCount() - 1).getLeft() > getWidth()) { View lastView = getChildAt(getChildCount() - 1); cacheViews.addLast(lastView); rightEdge -= lastView.getMeasuredWidth(); removeViewInLayout(lastView); myLastAddPosition--; //Log.w(TAG, "onLayout after remove right views count:" + getChildCount()); } //add in right while (rightEdge < getWidth() && myLastAddPosition + 1 < mAdapter.getCount()) { View v = mAdapter.getView(myLastAddPosition + 1, getCachedView(), this); v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY | getHeight()); rightEdge += v.getMeasuredWidth(); LayoutParams myLayoutParams = v.getLayoutParams(); if (myLayoutParams == null) { myLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); } addViewInLayout(v, -1, myLayoutParams); myLastAddPosition++; } //add in left while (leftEdge >= 0 && myFirstViewPosition > 0) { View v = mAdapter.getView(myFirstViewPosition - 1, getCachedView(), this); //TODO:当View是回收来的时候,View是否需要measure v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY | getHeight()); leftEdge -= v.getMeasuredWidth(); mListLeft -= v.getMeasuredWidth(); LayoutParams myLayoutParams = v.getLayoutParams(); if (myLayoutParams == null) { myLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); } addViewInLayout(v, 0, myLayoutParams); myFirstViewPosition--; //Log.d(TAG, "onLayout add to Left"); } //Layout int mLeft = 0; //Log.e(TAG, "onLayout last added position:" + myLastAddPosition); for (int i = 0; i < getChildCount(); i++) { View childView = getChildAt(i); int cRight = childView.getMeasuredWidth(); childView.layout(mLeft + mListLeft, 0, mLeft + cRight + mListLeft, getHeight()); mLeft += cRight; //Log.e(TAG, "onLayout mLeft" + mLeft); } } /** * 如果在这里不返回true的话,所有的事件都会被Item的listener拦截,导致无法移动List * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; } return true; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mTouchDownX = (int) event.getX(); mTouchDownY = (int) event.getY(); mTouchState = TOUCH_STATE_CLICK; startLongClickCheck(mTouchDownX, mTouchDownY); break; case MotionEvent.ACTION_MOVE: if (mTouchState == TOUCH_STATE_CLICK) { if (Math.abs(event.getX() - mTouchDownX) > TOUCH_THRESHOLD || Math.abs(event.getY() - mTouchDownY) > TOUCH_THRESHOLD) { mTouchDownX = (int) event.getX(); mTouchDownY = (int) event.getY(); scrollingList(event); removeCallbacks(longClickHandler); } } else if (mTouchState == TOUCH_STATE_SCROLLING) { scrollingList(event); } break; case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_CLICK) { clickChild((int) event.getX(), (int) event.getY()); } endTouch(); break; default: endTouch(); break; } return super.onTouchEvent(event); } private void endTouch() { removeCallbacks(longClickHandler); mTouchState = TOUCH_STATE_RESTING; } private void scrollingList(MotionEvent event) { mListLeft += (int) (event.getX() - mTouchDownX); rightEdge += (int) (event.getX() - mTouchDownX); leftEdge += (int) (event.getX() - mTouchDownX); // if (mListLeft > 0) { // rightEdge -= mListLeft; // mListLeft = 0; // } mTouchDownX = (int) event.getX(); mTouchDownY = (int) event.getY(); mTouchState = TOUCH_STATE_SCROLLING; requestLayout(); } private void clickChild(int x, int y) { Rect rect = new Rect(); for (int i = 0; i < getChildCount(); i++) { View v = getChildAt(i); v.getHitRect(rect); if (rect.contains(x, y)) { performItemClick(v, myFirstViewPosition + i, mAdapter.getItemId(myFirstViewPosition + i)); } } } public void startLongClickCheck(final int x, final int y) { longClickHandler = new Runnable() { @Override public void run() { longClickChild(x, y); } }; postDelayed(longClickHandler, ViewConfiguration.get(getContext()).getLongPressTimeout()); } private void longClickChild(int x, int y) { Rect rect = new Rect(); for (int i = 0; i < getChildCount(); i++) { View v = getChildAt(i); v.getHitRect(rect); if (rect.contains(x, y)) { OnItemLongClickListener listener = getOnItemLongClickListener(); if (listener != null) { listener.onItemLongClick(this, v, myFirstViewPosition + i, mAdapter.getItemId(myFirstViewPosition + i)); mTouchState = TOUCH_STATE_RESTING; } } } } /** * 获得缓存的View,作为ConvertView * * @return */ private View getCachedView() { if (cacheViews.size() > 0) { return cacheViews.removeFirst(); } return null; } }