How to use Android tools that imitate the time wheel of iPhone
= adapter.getItemsCount () {if (isCyclic) {while (index)
< 0) { index += adapter.getItemsCount(); } index %= adapter.getItemsCount(); } else { return; } } if (index != currentItem) { if (animated) { scroll(index - currentItem, SCROLLING_DURATION); } else { invalidateLayouts(); int old = currentItem; currentItem = index; notifyChangingListeners(old, currentItem); invalidate(); } } } /** * 设置当前item w/o 动画. 当index有误是不做任何响应. * * @param index * the item index */ public void setCurrentItem(int index) { setCurrentItem(index, false); } /** * 测试滚轮是否可循环. * * @return true if wheel is cyclic */ public boolean isCyclic() { return isCyclic; } /** * 设置滚轮循环标志 * * @param isCyclic * the flag to set */ public void setCyclic(boolean isCyclic) { this.isCyclic = isCyclic; invalidate(); invalidateLayouts(); } /** * 使布局无效 */ private void invalidateLayouts() { itemsLayout = null; valueLayout = null; scrollingOffset = 0; } /** * 初始化资源信息 */ private void initResourceIfNecessary() { if (itemsPaint == null) { itemsPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG); itemsPaint.setTextSize(TEXT_SIZE); } if (valuePaint == null) { valuePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG | Paint.DITHER_FLAG); valuePaint.setTextSize(TEXT_SIZE); valuePaint.setShadowLayer(0.1f, 0, 0.1f, 0xFFC0C0C0); } if (centerDrawable == null) { centerDrawable = getContext().getResources().getDrawable( R.drawable.wheel_val); } if (topShadow == null) { topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS); } if (bottomShadow == null) { bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS); } setBackgroundResource(R.drawable.wheel_bg); } /** * 计算layout所需的高度 * @param layout * @return */ private int getDesiredHeight(Layout layout) { if (layout == null) { return 0; } int desired = getItemHeight() * visibleItems - ITEM_OFFSET * 2 - ADDITIONAL_ITEM_HEIGHT; desired = Math.max(desired,getSuggestedMinimumHeight()); return desired; } /** * 通过index得到text * @param index * @return */ private String getTextItem(int index){ if(adapter == null || adapter.getItemsCount() == 0){ return null; } int count = adapter.getItemsCount(); if((index < 0 || index >= count) & &! isCyclic) {return null;} else {while (index
< 0){ index += count; } } index %= count; return adapter.getItem(index); } /** * 根据当前值构建text * * @param useCurrentValue * @return the text */ private String buildText(boolean useCurrentValue) { StringBuilder itemsText = new StringBuilder(); int addItems = visibleItems / 2 + 1; for (int i = currentItem - addItems; i 0) { return adapterLength; } String maxText = null; int addItems = visibleItems / 2; for (int i = Math.max(currentItem - addItems, 0); i < Math.min(currentItem + visibleItems, adapter.getItemsCount()); i++) { String text = adapter.getItem(i); if (text != null && (maxText == null || maxText.length() < text.length())) { maxText = text; } } return maxText != null ? maxText.length() : 0; } /** * 返回滚轮item的高度 * @return the item height */ private int getItemHeight() { if (itemHeight != 0) { return itemHeight; } else if (itemsLayout != null && itemsLayout.getLineCount() >2) {itemHeight = itemsLayout.getLineTop (2)-itemsLayout.getLineTop (1); return itemHeight;} return getHeight () / visibleItems } / * calculate control width and create text layout * @ param widthSize the input layout width * @ param mode the layout mode * @ return the calculated control width * / private int calculateLayoutWidth (int widthSize, int mode) {initResourceIfNecessary (); int width = widthSize; int maxLength = getMaxTextLength () If (maxLength > 0) {float textWidth = FloatMath.ceil (Layout.getDesiredWidth ("0", itemsPaint)); itemsWidth = (int) (maxLength * textWidth);} else {itemsWidth = 0;} itemsWidth + = ADDITIONAL_ITEMS_SPACE; / / make it some more labelWidth = 0 If (label! = null & & label.length () > 0) {labelWidth = (int) FloatMath.ceil (Layout.getDesiredWidth (label, valuePaint));} boolean recalculate = false; if (mode = = MeasureSpec.EXACTLY) {width = widthSize; recalculate = true;} else {width = itemsWidth + labelWidth + 2 * PADDING If (labelWidth > 0) {width + = LABEL_OFFSET;} / / Check against our minimum width width = Math.max (width, getSuggestedMinimumWidth ()); if (mode = = MeasureSpec.AT_MOST & & widthSize
< width) { width = widthSize; recalculate = true; } } if (recalculate) { // recalculate width int pureWidth = width - LABEL_OFFSET - 2 * PADDING; if (pureWidth 0) { double newWidthItems = (double) itemsWidth * pureWidth / (itemsWidth + labelWidth); itemsWidth = (int) newWidthItems; labelWidth = pureWidth - itemsWidth; } else { itemsWidth = pureWidth + LABEL_OFFSET; // no label } } if (itemsWidth > < 0) { pos += adapter.getItemsCount(); } pos %= adapter.getItemsCount(); } else if (isScrollingPerformed) { // if (pos < 0) { count = currentItem; pos = 0; } else if (pos >= adapter.getItemsCount () {count = currentItem-adapter.getItemsCount () + 1; pos = adapter.getItemsCount ()-1;} else {/ / fix position pos = Math.max (pos, 0); pos = Math.min (pos, adapter.getItemsCount ()-1) } int offset = scrollingOffset; if (pos! = currentItem) {setCurrentItem (pos, false);} else {invalidate ();} / / update offset scrollingOffset = offset-count * getItemHeight (); if (scrollingOffset > getHeight ()) {scrollingOffset = scrollingOffset% getHeight () + getHeight () }} / / gesture listener private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener () {public boolean onDown (MotionEvent e) {if (isScrollingPerformed) {scroller.forceFinished (true); clearMessages (); return true;} return false } public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {startScrolling (); doScroll ((int)-distanceY); return true;} public boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {lastScrollY = currentItem * getItemHeight () + scrollingOffset Int maxY = isCyclic? 0x7FFFFFFF: adapter.getItemsCount () * getItemHeight (); int minY = isCyclic?-maxY: 0; scroller.fling (0, lastScrollY, 0, (int)-velocityY / 2,0,0, minY, maxY); setNextMessage (MESSAGE_SCROLL); return true;}}; / / Messages private final int MESSAGE_SCROLL = 0 Private final int MESSAGE_JUSTIFY = 1; / * * Set next message to queue. Clears queue before. * * @ param message the message to set * / private void setNextMessage (int message) {clearMessages (); animationHandler.sendEmptyMessage (message);} / * Clears messages from queue * / private void clearMessages () {animationHandler.removeMessages (MESSAGE_SCROLL); animationHandler.removeMessages (MESSAGE_JUSTIFY) } / / animation handler private Handler animationHandler = new Handler () {public void handleMessage (Message msg) {scroller.computeScrollOffset (); int currY = scroller.getCurrY (); int delta = lastScrollY-currY; lastScrollY = currY; if (delta! = 0) {doScroll (delta) } / / scrolling is not finished when it comes to final Y / / so, finish it manually if (Math.abs (currY-scroller.getFinalY ())
< MIN_DELTA_FOR_SCROLLING) { currY = scroller.getFinalY(); scroller.forceFinished(true); } if (!scroller.isFinished()) { animationHandler.sendEmptyMessage(msg.what); } else if (msg.what == MESSAGE_SCROLL) { justify(); } else { finishScrolling(); } } }; /** * Justifies wheel */ private void justify() { if (adapter == null) { return; } lastScrollY = 0; int offset = scrollingOffset; int itemHeight = getItemHeight(); boolean needToIncrease = offset >0? CurrentItem
< adapter.getItemsCount() : currentItem >0; if ((isCyclic | | needToIncrease) & & Math.abs ((float) offset) > (float) itemHeight / 2) {if (offset)
< 0) offset += itemHeight + MIN_DELTA_FOR_SCROLLING; else offset -= itemHeight + MIN_DELTA_FOR_SCROLLING; } if (Math.abs(offset) >MIN_DELTA_FOR_SCROLLING) {scroller.startScroll (0,0,0, offset, SCROLLING_DURATION); setNextMessage (MESSAGE_JUSTIFY);} else {finishScrolling ();}} / * * start scrolling * / private void startScrolling () {if (! isScrollingPerformed) {isScrollingPerformed = true NotifyScrollingListenersAboutStart ();}} / * stop scrolling * / void finishScrolling () {if (isScrollingPerformed) {notifyScrollingListenersAboutEnd (); isScrollingPerformed = false;} invalidateLayouts (); invalidate ();} public void scroll (int itemsToScroll, int time) {scroller.forceFinished (true) LastScrollY = scrollingOffset; int offset = itemsToScroll * getItemHeight (); scroller.startScroll (0, lastScrollY, 0, offset-lastScrollY, time); setNextMessage (MESSAGE_SCROLL); startScrolling ();}} above is how Android imitates iPhone's time wheel tools. The editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.