橫向滾動選擇ScrollPickerView
阿新 • • 發佈:2018-12-21
github下載地址 ScrollPickerView
public abstract class ScrollPickerView<T> extends View { private int mVisibleItemCount = 3; // 可見的item數量 private boolean mIsInertiaScroll = true; // 快速滑動時是否慣性滾動一段距離,預設開啟 private boolean mIsCirculation = true; // 是否迴圈滾動,預設開啟 /* 不允許父元件攔截觸控事件,設定為true為不允許攔截,此時該設定才生效 當嵌入到ScrollView等滾動元件中,為了使該自定義滾動選擇器可以正常工作,請設定為true */ private boolean mDisallowInterceptTouch = false; private int mSelected; // 當前選中的item下標 private List<T> mData; private int mItemHeight = 0; // 每個條目的高度,當垂直滾動時,高度=mMeasureHeight/mVisibleItemCount private int mItemWidth = 0; // 每個條目的寬度,當水平滾動時,寬度=mMeasureWidth/mVisibleItemCount private int mItemSize; // 當垂直滾動時,mItemSize = mItemHeight;水平滾動時,mItemSize = mItemWidth private int mCenterPosition = -1; // 中間item的位置,0<=mCenterPosition<mVisibleItemCount,預設為 mVisibleItemCount / 2 private int mCenterY; // 中間item的起始座標y(不考慮偏移),當垂直滾動時,y= mCenterPosition*mItemHeight private int mCenterX; // 中間item的起始座標x(不考慮偏移),當垂直滾動時,x = mCenterPosition*mItemWidth private int mCenterPoint; // 當垂直滾動時,mCenterPoint = mCenterY;水平滾動時,mCenterPoint = mCenterX private float mLastMoveY; // 觸控的座標y private float mLastMoveX; // 觸控的座標X private float mMoveLength = 0; // item移動長度,負數表示向上移動,正數表示向下移動 private GestureDetector mGestureDetector; private OnSelectedListener mListener; private Scroller mScroller; private boolean mIsFling; // 是否正在慣性滑動 private boolean mIsMovingCenter; // 是否正在滑向中間 // 可以把scroller看做模擬的觸屏滑動操作,mLastScrollY為上次觸屏滑動的座標 private int mLastScrollY = 0; // Scroller的座標y private int mLastScrollX = 0; // Scroller的座標x private boolean mDisallowTouch = false; // 不允許觸控 private Paint mPaint; // private Drawable mCenterItemBackground = null; // 中間選中item的背景色 private boolean mCanTap = true; // 單擊切換選項或觸發點選監聽器 private boolean mIsHorizontal = false; // 是否水平滾動 private boolean mDrawAllItem = false; // 是否繪製每個item(包括在邊界外的item) public ScrollPickerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ScrollPickerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mGestureDetector = new GestureDetector(getContext(), new FlingOnGestureListener()); mScroller = new Scroller(getContext()); mAutoScrollAnimator = ValueAnimator.ofInt(0, 0); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); init(attrs); } private void init(AttributeSet attrs) { if (attrs != null) { TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ScrollPickerView); if (typedArray.hasValue(R.styleable.ScrollPickerView_spv_center_item_background)) { setCenterItemBackground(typedArray.getDrawable(R.styleable.ScrollPickerView_spv_center_item_background)); } setVisibleItemCount(typedArray.getInt( R.styleable.ScrollPickerView_spv_visible_item_count, getVisibleItemCount())); setCenterPosition(typedArray.getInt( R.styleable.ScrollPickerView_spv_center_item_position, getCenterPosition())); setIsCirculation(typedArray.getBoolean(R.styleable.ScrollPickerView_spv_is_circulation, isIsCirculation())); setDisallowInterceptTouch(typedArray.getBoolean(R.styleable.ScrollPickerView_spv_disallow_intercept_touch, isDisallowInterceptTouch())); setHorizontal(typedArray.getInt(R.styleable.ScrollPickerView_spv_orientation, mIsHorizontal ? 1 : 2) == 1); typedArray.recycle(); } } @Override protected void onDraw(Canvas canvas) { if (mData == null || mData.size() <= 0) { return; } // 選中item的背景色 if (mCenterItemBackground != null) { mCenterItemBackground.draw(canvas); } // 只繪製可見的item int length = Math.max(mCenterPosition + 1, mVisibleItemCount - mCenterPosition); int position; int start = Math.min(length, mData.size()); if (mDrawAllItem) { start = mData.size(); } // 上下兩邊 for (int i = start; i >= 1; i--) { // 先從遠離中間位置的item繪製,當item內容偏大時,較近的item覆蓋在較遠的上面 if (mDrawAllItem || i <= mCenterPosition + 1) { // 上面的items,相對位置為 -i position = mSelected - i < 0 ? mData.size() + mSelected - i : mSelected - i; // 傳入位置資訊,繪製item if (mIsCirculation) { drawItem(canvas, mData, position, -i, mMoveLength, mCenterPoint + mMoveLength - i * mItemSize); } else if (mSelected - i >= 0) { // 非迴圈滾動 drawItem(canvas, mData, position, -i, mMoveLength, mCenterPoint + mMoveLength - i * mItemSize); } } if (mDrawAllItem || i <= mVisibleItemCount - mCenterPosition) { // 下面的items,相對位置為 i position = mSelected + i >= mData.size() ? mSelected + i - mData.size() : mSelected + i; // 傳入位置資訊,繪製item if (mIsCirculation) { drawItem(canvas, mData, position, i, mMoveLength, mCenterPoint + mMoveLength + i * mItemSize); } else if (mSelected + i < mData.size()) { // 非迴圈滾動 drawItem(canvas, mData, position, i, mMoveLength, mCenterPoint + mMoveLength + i * mItemSize); } } } // 選中的item drawItem(canvas, mData, mSelected, 0, mMoveLength, mCenterPoint + mMoveLength); } /** * 繪製item * * @param canvas * @param data 資料集 * @param position 在data資料集中的位置 * @param relative 相對中間item的位置,relative==0表示中間item,relative<0表示上(左)邊的item,relative>0表示下(右)邊的item * @param moveLength 中間item滾動的距離,moveLength<0則表示向上(右)滾動的距離,moveLength>0則表示向下(左)滾動的距離 * @param top 當前繪製item的座標,當垂直滾動時為頂部y的座標;當水平滾動時為item最左邊x的座標 */ public abstract void drawItem(Canvas canvas, List<T> data, int position, int relative, float moveLength, float top); @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); reset(); } private void reset() { if (mCenterPosition < 0) { mCenterPosition = mVisibleItemCount / 2; } if (mIsHorizontal) { mItemHeight = getMeasuredHeight(); mItemWidth = getMeasuredWidth() / mVisibleItemCount; mCenterY = 0; mCenterX = mCenterPosition * mItemWidth; mItemSize = mItemWidth; mCenterPoint = mCenterX; } else { mItemHeight = getMeasuredHeight() / mVisibleItemCount; mItemWidth = getMeasuredWidth(); mCenterY = mCenterPosition * mItemHeight; mCenterX = 0; mItemSize = mItemHeight; mCenterPoint = mCenterY; } if (mCenterItemBackground != null) { mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight); } } private int mSelectedOnTouch; @Override public boolean onTouchEvent(MotionEvent event) { if (mDisallowTouch) { // 不允許觸控 return true; } switch (event.getActionMasked()) { // 按下監聽 case MotionEvent.ACTION_DOWN: mSelectedOnTouch = mSelected; break; } if (mGestureDetector.onTouchEvent(event)) { return true; } switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: if (mIsHorizontal) { if (Math.abs(event.getX() - mLastMoveX) < 0.1f) { return true; } mMoveLength += event.getX() - mLastMoveX; } else { if (Math.abs(event.getY() - mLastMoveY) < 0.1f) { return true; } mMoveLength += event.getY() - mLastMoveY; } mLastMoveY = event.getY(); mLastMoveX = event.getX(); checkCirculation(); invalidate(); break; case MotionEvent.ACTION_UP: mLastMoveY = event.getY(); mLastMoveX = event.getX(); if (mMoveLength == 0) { if (mSelectedOnTouch != mSelected) { //前後發生變化 notifySelected(); } } else { moveToCenter(); // 滾動到中間位置 } break; } return true; } /** * @param curr * @param end */ private void computeScroll(int curr, int end, float rate) { if (rate < 1) { // 正在滾動 if (mIsHorizontal) { // 可以把scroller看做模擬的觸屏滑動操作,mLastScrollX為上次滑動的座標 mMoveLength = mMoveLength + curr - mLastScrollX; mLastScrollX = curr; } else { // 可以把scroller看做模擬的觸屏滑動操作,mLastScrollY為上次滑動的座標 mMoveLength = mMoveLength + curr - mLastScrollY; mLastScrollY = curr; } checkCirculation(); invalidate(); } else { // 滾動完畢 mIsMovingCenter = false; mLastScrollY = 0; mLastScrollX = 0; // 直接居中,不通過動畫 if (mMoveLength > 0) { //// 向下滑動 if (mMoveLength < mItemSize / 2) { mMoveLength = 0; } else { mMoveLength = mItemSize; } } else { if (-mMoveLength < mItemSize / 2) { mMoveLength = 0; } else { mMoveLength = -mItemSize; } } checkCirculation(); notifySelected(); invalidate(); } } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // 正在滾動 if (mIsHorizontal) { // 可以把scroller看做模擬的觸屏滑動操作,mLastScrollX為上次滑動的座標 mMoveLength = mMoveLength + mScroller.getCurrX() - mLastScrollX; } else { // 可以把scroller看做模擬的觸屏滑動操作,mLastScrollY為上次滑動的座標 mMoveLength = mMoveLength + mScroller.getCurrY() - mLastScrollY; } mLastScrollY = mScroller.getCurrY(); mLastScrollX = mScroller.getCurrX(); checkCirculation(); // 檢測當前選中的item invalidate(); } else { // 滾動完畢 if (mIsFling) { mIsFling = false; if (mMoveLength == 0) { //慣性滑動後的位置剛好居中的情況 notifySelected(); } else { moveToCenter(); // 滾動到中間位置 } } else if (mIsMovingCenter) { // 選擇完成,回撥給監聽器 notifySelected(); } } } public void cancelScroll() { mLastScrollY = 0; mLastScrollX = 0; mIsFling = mIsMovingCenter = false; mScroller.abortAnimation(); stopAutoScroll(); } // 檢測當前選擇的item位置 private void checkCirculation() { if (mMoveLength >= mItemSize) { // 向下滑動 // 該次滾動距離中越過的item數量 int span = (int) (mMoveLength / mItemSize); mSelected -= span; if (mSelected < 0) { // 滾動頂部,判斷是否迴圈滾動 if (mIsCirculation) { do { mSelected = mData.size() + mSelected; } while (mSelected < 0); // 當越過的item數量超過一圈時 mMoveLength = (mMoveLength - mItemSize) % mItemSize; } else { // 非迴圈滾動 mSelected = 0; mMoveLength = mItemSize; if (mIsFling) { // 停止慣性滑動,根據computeScroll()中的邏輯,下一步將呼叫moveToCenter() mScroller.forceFinished(true); } if (mIsMovingCenter) { // 移回中間位置 scroll(mMoveLength, 0); } } } else { mMoveLength = (mMoveLength - mItemSize) % mItemSize; } } else if (mMoveLength <= -mItemSize) { // 向上滑動 // 該次滾動距離中越過的item數量 int span = (int) (-mMoveLength / mItemSize); mSelected += span; if (mSelected >= mData.size()) { // 滾動末尾,判斷是否迴圈滾動 if (mIsCirculation) { do { mSelected = mSelected - mData.size(); } while (mSelected >= mData.size()); // 當越過的item數量超過一圈時 mMoveLength = (mMoveLength + mItemSize) % mItemSize; } else { // 非迴圈滾動 mSelected = mData.size() - 1; mMoveLength = -mItemSize; if (mIsFling) { // 停止慣性滑動,根據computeScroll()中的邏輯,下一步將呼叫moveToCenter() mScroller.forceFinished(true); } if (mIsMovingCenter) { // 移回中間位置 scroll(mMoveLength, 0); } } } else { mMoveLength = (mMoveLength + mItemSize) % mItemSize; } } } // 移動到中間位置 private void moveToCenter() { if (!mScroller.isFinished() || mIsFling || mMoveLength == 0) { return; } cancelScroll(); // 向下滑動 if (mMoveLength > 0) { if (mIsHorizontal) { if (mMoveLength < mItemWidth / 2) { scroll(mMoveLength, 0); } else { scroll(mMoveLength, mItemWidth); } } else { if (mMoveLength < mItemHeight / 2) { scroll(mMoveLength, 0); } else { scroll(mMoveLength, mItemHeight); } } } else { if (mIsHorizontal) { if (-mMoveLength < mItemWidth / 2) { scroll(mMoveLength, 0); } else { scroll(mMoveLength, -mItemWidth); } } else { if (-mMoveLength < mItemHeight / 2) { scroll(mMoveLength, 0); } else { scroll(mMoveLength, -mItemHeight); } } } } // 平滑滾動 private void scroll(float from, int to) { if (mIsHorizontal) { mLastScrollX = (int) from; mIsMovingCenter = true; mScroller.startScroll((int) from, 0, 0, 0); mScroller.setFinalX(to); } else { mLastScrollY = (int) from; mIsMovingCenter = true; mScroller.startScroll(0, (int) from, 0, 0); mScroller.setFinalY(to); } invalidate(); } // 慣性滑動, private void fling(float from, float vel) { if (mIsHorizontal) { mLastScrollX = (int) from; mIsFling = true; // 最多可以慣性滑動10個item mScroller.fling((int) from, 0, (int) vel, 0, -10 * mItemWidth, 10 * mItemWidth, 0, 0); } else { mLastScrollY = (int) from; mIsFling = true; // 最多可以慣性滑動10個item mScroller.fling(0, (int) from, 0, (int) vel, 0, 0, -10 * mItemHeight, 10 * mItemHeight); } invalidate(); } private void notifySelected() { mMoveLength = 0; cancelScroll(); if (mListener != null) { // 告訴監聽器選擇完畢 mListener.onSelected(ScrollPickerView.this, mSelected); } } private boolean mIsAutoScrolling = false; private ValueAnimator mAutoScrollAnimator; private final static SlotInterpolator sAutoScrollInterpolator = new SlotInterpolator(); /** * 自動滾動(必須設定為可迴圈滾動) * * @param position * @param duration * @param speed 每毫秒移動的畫素點 */ public void autoScrollFast(final int position, long duration, float speed, final Interpolator interpolator) { if (mIsAutoScrolling || !mIsCirculation) { return; } cancelScroll(); mIsAutoScrolling = true; int length = (int) (speed * duration); int circle = (int) (length * 1f / (mData.size() * mItemSize) + 0.5f); // 圈數 circle = circle <= 0 ? 1 : circle; int aPlan = circle * (mData.size()) * mItemSize + (mSelected - position) * mItemSize; int bPlan = aPlan + (mData.size()) * mItemSize; // 多一圈 // 讓其儘量接近length final int end = Math.abs(length - aPlan) < Math.abs(length - bPlan) ? aPlan : bPlan; mAutoScrollAnimator.cancel(); mAutoScrollAnimator.setIntValues(0, end); mAutoScrollAnimator.setInterpolator(interpolator); mAutoScrollAnimator.setDuration(duration); mAutoScrollAnimator.removeAllUpdateListeners(); if (end != 0) { // itemHeight為0導致endy=0 mAutoScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float rate = 0; rate = animation.getCurrentPlayTime() * 1f / animation.getDuration(); computeScroll((int) animation.getAnimatedValue(), end, rate); } }); mAutoScrollAnimator.removeAllListeners(); mAutoScrollAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); mIsAutoScrolling = false; } }); mAutoScrollAnimator.start(); } else { computeScroll(end, end, 1); mIsAutoScrolling = false; } } /** * 自動滾動,預設速度為 0.6dp/ms * * @see ScrollPickerView#autoScrollFast(int, long, float, Interpolator) */ public void autoScrollFast(final int position, long duration) { float speed = dip2px(0.6f); autoScrollFast(position, duration, speed, sAutoScrollInterpolator); } /** * 自動滾動 * * @see ScrollPickerView#autoScrollFast(int, long, float, Interpolator) */ public void autoScrollFast(final int position, long duration, float speed) { autoScrollFast(position, duration, speed, sAutoScrollInterpolator); } /** * 滾動到指定位置 * * @param toPosition 需要滾動到的位置 * @param duration 滾動時間 * @param interpolator */ public void autoScrollToPosition(int toPosition, long duration, final Interpolator interpolator) { toPosition = toPosition % mData.size(); final int endY = (mSelected - toPosition) * mItemHeight; autoScrollTo(endY, duration, interpolator, false); } /** * @param endY 需要滾動到的位置 * @param duration 滾動時間 * @param interpolator * @param canIntercept 能否終止滾動,比如觸控式螢幕幕終止滾動 */ public void autoScrollTo(final int endY, long duration, final Interpolator interpolator, boolean canIntercept) { if (mIsAutoScrolling) { return; } final boolean temp = mDisallowTouch; mDisallowTouch = !canIntercept; mIsAutoScrolling = true; mAutoScrollAnimator.cancel(); mAutoScrollAnimator.setIntValues(0, endY); mAutoScrollAnimator.setInterpolator(interpolator); mAutoScrollAnimator.setDuration(duration); mAutoScrollAnimator.removeAllUpdateListeners(); mAutoScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float rate = 0; rate = animation.getCurrentPlayTime() * 1f / animation.getDuration(); computeScroll((int) animation.getAnimatedValue(), endY, rate); } }); mAutoScrollAnimator.removeAllListeners(); mAutoScrollAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); mIsAutoScrolling = false; mDisallowTouch = temp; } }); mAutoScrollAnimator.start(); } /** * 停止自動滾動 */ public void stopAutoScroll() { mIsAutoScrolling = false; mAutoScrollAnimator.cancel(); } private static class SlotInterpolator implements Interpolator { @Override public float getInterpolation(float input) { return (float) (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } } /** * 快速滑動時,慣性滑動一段距離 * * @author huangziwei */ private class FlingOnGestureListener extends SimpleOnGestureListener { private boolean mIsScrollingLastTime = false; public boolean onDown(MotionEvent e) { if (mDisallowInterceptTouch) { // 不允許父元件攔截事件 ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } } mIsScrollingLastTime = isScrolling(); // 記錄是否從滾動狀態終止 // 點選時取消所有滾動效果 cancelScroll(); mLastMoveY = e.getY(); mLastMoveX = e.getX(); return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, final float velocityY) { // 慣性滑動 if (mIsInertiaScroll) { cancelScroll(); if (mIsHorizontal) { fling(mMoveLength, velocityX); } else { fling(mMoveLength, velocityY); } } return true; } @Override public boolean onSingleTapUp(MotionEvent e) { mLastMoveY = e.getY(); mLastMoveX = e.getX(); float lastMove = 0; if (isHorizontal()) { mCenterPoint = mCenterX; lastMove = mLastMoveX; } else { mCenterPoint = mCenterY; lastMove = mLastMoveY; } if (mCanTap && !mIsScrollingLastTime) { if (lastMove >= mCenterPoint && lastMove <= mCenterPoint + mItemSize) { //點選中間item,回撥點選事件 performClick(); } else if (lastMove < mCenterPoint) { // 點選兩邊的item,移動到相應的item int move = mItemSize; autoScrollTo(move, 150, sAutoScrollInterpolator, false); } else { // lastMove > mCenterPoint + mItemSize int move = -mItemSize; autoScrollTo(move, 150, sAutoScrollInterpolator, false); } } else { moveToCenter(); } return true; } } public List<T> getData() { return mData; } public void setData(List<? extends T> data) { if (data == null) { mData = new ArrayList<T>(); } else { this.mData = (List<T>) data; } mSelected = mData.size() / 2; invalidate(); } public T getSelectedItem() { return mData.get(mSelected); } public int getSelectedPosition() { return mSelected; } public void setSelectedPosition(int position) { if (position < 0 || position > mData.size() - 1 || position == mSelected) { return; } mSelected = position; invalidate(); notifySelected(); } public void setOnSelectedListener(OnSelectedListener listener) { mListener = listener; } public OnSelectedListener getListener() { return mListener; } public boolean isInertiaScroll() { return mIsInertiaScroll; } public void setInertiaScroll(boolean inertiaScroll) { this.mIsInertiaScroll = inertiaScroll; } public boolean isIsCirculation() { return mIsCirculation; } public void setIsCirculation(boolean isCirculation) { this.mIsCirculation = isCirculation; } public boolean isDisallowInterceptTouch() { return mDisallowInterceptTouch; } public int getVisibleItemCount() { return mVisibleItemCount; } public void setVisibleItemCount(int visibleItemCount) { mVisibleItemCount = visibleItemCount; reset(); invalidate(); } /** * 是否允許父元素攔截事件,設定true後可以保證在ScrollView下正常滾動 */ public void setDisallowInterceptTouch(boolean disallowInterceptTouch) { mDisallowInterceptTouch = disallowInterceptTouch; } public int getItemHeight() { return mItemHeight; } public int getItemWidth() { return mItemWidth; } /** * @return 當垂直滾動時,mItemSize = mItemHeight;水平滾動時,mItemSize = mItemWidth */ public int getItemSize() { return mItemSize; } /** * @return 中間item的起始座標x(不考慮偏移), 當垂直滾動時,x = mCenterPosition*mItemWidth */ public int getCenterX() { return mCenterX; } /** * @return 中間item的起始座標y(不考慮偏移), 當垂直滾動時,y= mCenterPosition*mItemHeight */ public int getCenterY() { return mCenterY; } /** * @return 當垂直滾動時,mCenterPoint = mCenterY;水平滾動時,mCenterPoint = mCenterX */ public int getCenterPoint() { return mCenterPoint; } public boolean isDisallowTouch() { return mDisallowTouch; } /** * 設定是否允許手動觸控滾動 * * @param disallowTouch */ public void setDisallowTouch(boolean disallowTouch) { mDisallowTouch = disallowTouch; } /** * 中間item的位置,0 <= centerPosition <= mVisibleItemCount * * @param centerPosition */ public void setCenterPosition(int centerPosition) { if (centerPosition < 0) { mCenterPosition = 0; } else if (centerPosition >= mVisibleItemCount) { mCenterPosition = mVisibleItemCount - 1; } else { mCenterPosition = centerPosition; } mCenterY = mCenterPosition * mItemHeight; invalidate(); } /** * 中間item的位置,預設為 mVisibleItemCount / 2 * * @return */ public int getCenterPosition() { return mCenterPosition; } public void setCenterItemBackground(Drawable centerItemBackground) { mCenterItemBackground = centerItemBackground; mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight); invalidate(); } public void setCenterItemBackground(int centerItemBackgroundColor) { mCenterItemBackground = new ColorDrawable(centerItemBackgroundColor); mCenterItemBackground.setBounds(mCenterX, mCenterY, mCenterX + mItemWidth, mCenterY + mItemHeight); invalidate(); } public Drawable getCenterItemBackground() { return mCenterItemBackground; } public boolean isScrolling() { return mIsFling || mIsMovingCenter || mIsAutoScrolling; } public boolean isFling() { return mIsFling; } public boolean isMovingCenter() { return mIsMovingCenter; } public boolean isAutoScrolling() { return mIsAutoScrolling; } public boolean isCanTap() { return mCanTap; } /** * 設定 單擊切換選項或觸發點選監聽器 * * @param canTap */ public void setCanTap(boolean canTap) { mCanTap = canTap; } public boolean isHorizontal() { return mIsHorizontal; } public boolean isVertical() { return !mIsHorizontal; } public void setHorizontal(boolean horizontal) { if (mIsHorizontal == horizontal) { return; } mIsHorizontal = horizontal; reset(); if (mIsHorizontal) { mItemSize = mItemWidth; } else { mItemSize = mItemHeight; } invalidate(); } public void setVertical(boolean vertical) { if (mIsHorizontal == !vertical) { return; } mIsHorizontal = !vertical; reset(); if (mIsHorizontal) { mItemSize = mItemWidth; } else { mItemSize = mItemHeight; } invalidate(); } public boolean isDrawAllItem() { return mDrawAllItem; } public void setDrawAllItem(boolean drawAllItem) { mDrawAllItem = drawAllItem; } /** * @author huangziwei */ public interface OnSelectedListener { void onSelected(ScrollPickerView scrollPickerView, int position); } public int dip2px(float dipVlue) { DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); float sDensity = metrics.density; return (int) (dipVlue * sDensity + 0.5F); } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); if (visibility == VISIBLE) { moveToCenter(); } } }
XML中使用案例
<com.yyf.demo.view.StringScrollPicker android:id="@+id/picker_05_horizontal" android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginLeft="100dp" android:layout_marginRight="100dp" android:layout_marginTop="10dp" app:spv_alignment="center" app:spv_disallow_intercept_touch="true" app:spv_draw_bitmap_height="40dp" app:spv_draw_bitmap_mode="size" app:spv_draw_bitmap_width="40dp" app:spv_is_circulation="false" app:spv_max_line_width="300dp" app:spv_max_text_size="30dp" app:spv_min_text_size="20dp" app:spv_orientation="horizontal" app:spv_visible_item_count="5" />