How to customize the time scrolling selection control by iOS
Editor to share with you how iOS customizes the time scroll selection control, I believe most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!
The details are as follows
1. First, go to the custom control:
/ * Roller selector * author LH * data 17:26 on 2016-8-20 * / public class WheelView extends View {public static final String TAG = "WheelView"; / * the speed of automatic rollback to the middle * / public static final float SPEED = 2; / * except for item, the number of options to be displayed up and down * / public static final int SHOW_SIZE = 1; private Context context; private List itemList; private int itemCount / * item height * / private int itemHeight = 50; / * selected position, which is the central position of the mDataList and remains the same * / private int currentItem; private Paint selectPaint; private Paint mPaint; / / the distance at which individual brushes in the background image private Paint centerLinePaint; private float centerY; private float centerX; private float mLastDownY; / * slide * / private float mMoveLen = 0; private boolean isInit = false; private SelectListener mSelectListener; private Timer timer; private MyTimerTask mTask Handler updateHandler = new Handler () {@ Override public void handleMessage (Message msg) {if (Math.abs (mMoveLen))
< SPEED) { // 如果偏移量少于最少偏移量 mMoveLen = 0; if (null != timer) { timer.cancel(); timer.purge(); timer = null; } if (mTask != null) { mTask.cancel(); mTask = null; performSelect(); } } else { // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚 mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED; } invalidate(); } }; public WheelView(Context context) { super(context); init(context); } public WheelView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void setOnSelectListener(SelectListener listener) { mSelectListener = listener; } public void setWheelStyle(int style) { itemList = WheelStyle.getItemList(context, style); if (itemList != null) { itemCount = itemList.size(); resetCurrentSelect(); invalidate(); } else { Log.i(TAG, "item is null"); } } public void setWheelItemList(List itemList) { this.itemList = itemList; if (itemList != null) { itemCount = itemList.size(); resetCurrentSelect(); } else { Log.i(TAG, "item is null"); } } private void resetCurrentSelect() { if (currentItem < 0) { currentItem = 0; } while (currentItem >= itemCount) {currentItem--;} if (currentItem > = 0 & & currentItem
< itemCount) { invalidate(); } else { Log.i(TAG, "current item is invalid"); } } public int getItemCount() { return itemCount; } /** * 选择选中的item的index * author LH * data 2016/9/4 11:09 */ public void setCurrentItem(int selected) { currentItem = selected; resetCurrentSelect(); } public int getCurrentItem() { return currentItem; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int mViewHeight = getMeasuredHeight(); int mViewWidth = getMeasuredWidth(); centerX = (float) (mViewWidth / 2.0); centerY = (float) (mViewHeight / 2.0); isInit = true; invalidate(); } private void init(Context context) { this.context = context; timer = new Timer(); itemList = new ArrayList(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Style.FILL); mPaint.setTextAlign(Align.CENTER); mPaint.setColor(getResources().getColor(R.color.wheel_unselect_text)); int size1 = (int) (SupportDisplay.getLayoutScale()*22+0.5); mPaint.setTextSize(size1); selectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); selectPaint.setStyle(Style.FILL); selectPaint.setTextAlign(Align.CENTER); selectPaint.setColor(getResources().getColor(R.color.color_1a1a1a)); int size2 = (int) (SupportDisplay.getLayoutScale()*24+0.5); selectPaint.setTextSize(size2); centerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); centerLinePaint.setStyle(Style.FILL); centerLinePaint.setTextAlign(Align.CENTER); centerLinePaint.setColor(getResources().getColor(R.color.wheel_unselect_text)); // 绘制背景 setBackground(null); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isInit) { drawData(canvas); } } private void drawData(Canvas canvas) { // 先绘制选中的text再往上往下绘制其余的text if (!itemList.isEmpty()) { // 绘制中间data drawCenterText(canvas); // 绘制上方data for (int i = 1; i < SHOW_SIZE + 1; i++) { drawOtherText(canvas, i, -1); } // 绘制下方data for (int i = 1; i < SHOW_SIZE + 1; i++) { drawOtherText(canvas, i, 1); } } } private void drawCenterText(Canvas canvas) { // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标 float y = centerY + mMoveLen; FontMetricsInt fmi = selectPaint.getFontMetricsInt(); float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); canvas.drawText(itemList.get(currentItem), centerX, baseline, selectPaint); } /** * 绘制文本 * author LH * data 2016/9/4 11:10 * @param canvas 画布 * @param position 距离mCurrentSelected的差值 * @param type 1表示向下绘制,-1表示向上绘制 */ private void drawOtherText(Canvas canvas, int position, int type) { int index = currentItem + type * position; if (index >= itemCount) {index = index-itemCount;} if (index
< 0) { index = index + itemCount; } String text = itemList.get(index); int itemHeight = getHeight() / (SHOW_SIZE * 2 + 1); float d = itemHeight * position + type * mMoveLen; float y = centerY + type * d; FontMetricsInt fmi = mPaint.getFontMetricsInt(); float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0)); canvas.drawText(text, centerX, baseline, mPaint); } @Override public void setBackground(Drawable background) { background = new Drawable() { @Override public void draw(Canvas canvas) { itemHeight = getHeight() / (SHOW_SIZE * 2 + 1); int width = getWidth(); canvas.drawLine(0, itemHeight, width, itemHeight, centerLinePaint); canvas.drawLine(0, itemHeight * 2, width, itemHeight * 2, centerLinePaint); centerLinePaint.setColor(getResources().getColor(R.color.wheel_bg)); Rect topRect = new Rect(0, 0, width, itemHeight); canvas.drawRect(topRect, centerLinePaint); Rect bottomRect = new Rect(0, itemHeight * 2, width, itemHeight * 3); canvas.drawRect(bottomRect, centerLinePaint); } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter cf) { } @Override public int getOpacity() { return 0; } }; super.setBackground(background); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: doDown(event); break; case MotionEvent.ACTION_MOVE: doMove(event); break; case MotionEvent.ACTION_UP: doUp(); break; default: break; } return true; } private void doDown(MotionEvent event) { if (mTask != null) { mTask.cancel(); mTask = null; } mLastDownY = event.getY(); } private void doMove(MotionEvent event) { mMoveLen += (event.getY() - mLastDownY); if (mMoveLen >ItemHeight / 2) {/ / slide down more than the distance away mMoveLen = mMoveLen-itemHeight; currentItem--; if (currentItem
< 0) { currentItem = itemCount - 1; } } else if (mMoveLen < -itemHeight / 2) { // 往上滑超过离开距离 mMoveLen = mMoveLen + itemHeight; currentItem++; if (currentItem >= itemCount) {currentItem = 0;}} mLastDownY = event.getY (); invalidate ();} private void doUp () {/ / the position of mCurrentSelected after raising the hand from the current position move to the middle selected position if (Math.abs (mMoveLen) < 0.0001) {mMoveLen = 0; return;} if (mTask! = null) {mTask.cancel (); mTask = null;} if (null = timer) {timer = new Timer ();} mTask = new MyTimerTask (updateHandler) Timer.schedule (mTask, 0,10);} class MyTimerTask extends TimerTask {Handler handler; public MyTimerTask (Handler handler) {this.handler = handler;} @ Override public void run () {handler.sendMessage (handler.obtainMessage ());}} private void performSelect () {if (mSelectListener! = null) {mSelectListener.onSelect (currentItem, itemList.get (currentItem));} else {Log.i (TAG, "null listener");}} public interface SelectListener {void onSelect (int index, String text);}}
two。 Then there is the style tool class of the time selection control
/ * * data 2016-9-4 11:05 * / public class WheelStyle {public static final int minYear = 1980; public static final int maxYear = 2020; / * WheelStyle Hour * / public static final int STYLE_HOUR = 1; / * WheelStyle Minute * / public static final int STYLE_MINUTE = 2; / * WheelStyle Year * / public static final int STYLE_YEAR = 3; / * WheelStyle Month * / public static final int STYLE_MONTH = 4 / * WheelStyle Day * / public static final int STYLE_DAY = 5; / * WheelStyle Simple Day * / public static final int STYLE_SIMPLE_DAY = 6; / * WheelStyle Set Warn * / public static final int STYLE_SET_WARN = 7; / * WheelStyle Work Answer * / public static final int STYLE_WORK_ANSWER = 8; private WheelStyle () {} public static List getItemList (Context context, int Style) {if (Style = = STYLE_HOUR) {return createHourString () } else if (Style = = STYLE_MINUTE) {return createMinuteString ();} else if (Style = = STYLE_YEAR) {return createYearString ();} else if (Style = = STYLE_MONTH) {return createMonthString ();} else if (Style = = STYLE_DAY) {return createDayString ();} else if (Style = = STYLE_SIMPLE_DAY) {return createSimpleDayString ();} else if (Style = = STYLE_SET_WARN) {return createSetWarnTimeString ();} else {throw new IllegalArgumentException ("style is illegal") }} private static List createHourString () {List wheelString = new ArrayList (); for (int I = 0; I < 24; iFen +) {wheelString.add (String.format ("d" + "h", I));} return wheelString;} private static List createMinuteString () {List wheelString = new ArrayList (); for (int I = 0; I < 60; iFen +) {wheelString.add ("d" + "fen", I);} return wheelString } private static List createYearString () {List wheelString = new ArrayList (); for (int I = minYear; I