Android一款UI体验好于NumberPicker的自定义控件NumberPickerView

NumberPickerView

another NumberPicker with more flexible attributes on Android platform

ÏîÄ¿µØÖ·

https://github.com/Carbs0126/NumberPickerView

ÎÄÕµØÖ·£º

http://www.jianshu.com/p/ce33faec2a29

Ç°ÑÔ

ÔÚƽʱ¿ª·¢ÖлáÓõ½NumberPicker×é¼þ£¬µ«ÊÇĬÈÏ·ç¸ñµÄNumberPicker¾ßÓÐһЩ²»Áé»îµÄÊôÐÔ£¬ÇÒ¶¨ÖÆÆðÀ´±È½ÏÂé·³£¬ÇÒȱÉÙһЩ¹ý¶É¶¯Ð§£¬Òò´ËÔÚÓ¦Óÿª·¢Ê±£¬Ò»°ã²ÉÓÃ×Ô¶¨ÒåµÄ¿Ø¼þÀ´Íê³ÉÑ¡Ôñ¹¦ÄÜ¡£

¿Ø¼þ½Øͼ

NumberPickerViewµÄ¶¯Ì¬Í¼£º£¨½Øͼ´¦ÀíÓе㿨£¬Êµ¼ÊЧ¹ûºÜÁ÷³©£©

numberpickerview_refine2.gif

NumberPickerViewµÄ½Øͼ£º

numberpickerviewall.jpg

ʹÓÃNumberPickerView¿ª·¢µÄÒ»¿î¹«Àú/Å©ÀúÑ¡ÔñView£º

gregorian.jpg

¾ßÌåÏîÄ¿µØÖ·¿É¼û£º

https://github.com/Carbs0126/GregorianLunarCalendar

˵Ã÷

NumberPickerViewÊÇÒ»¿îÓëandroidÔ­ÉúNumberPicker¾ßÓÐÀàËƽçÃæÒÔ¼°ÀàËƹ¦ÄܵÄView¡£Ö÷Òª¹¦ÄÜͬÑùÊÇ´Ó¶à¸öºòÑ¡ÏîÖÐͨ¹ýÉÏϹö¶¯µÄ·½Ê½Ñ¡ÔñÐèÒªµÄÑ¡Ïµ«ÊÇÓëNumberPickerÏà±È½Ï£¬Óм¸¸öÖ÷Òª²»Í¬µã£¬ÏÂÃæÊÇÁ½ÕߵIJ»Í¬Ö®´¦¡£

ԭʼ¿Ø¼þÌØÐÔ-NumberPicker

1. ÏÔʾ´°¿ÚÖ»ÄÜÏÔʾ3¸ö±¸Ñ¡Ñ¡Ï

2. ÔÚflingʱ×èÁ¦½Ï´ó£¬ÎÞ·¨¿ìËÙ»¬¶¯£»

3. ÔÚÑ¡ÖÐÓë·ÇÑ¡ÖÐ״̬Çл»±È½ÏÉúÓ²£»

4. ÅúÁ¿¸Ä±äÑ¡ÏîÖеÄÄÚÈÝʱ£¬Ã»Óж¯»­Ð§¹û£»

5. ¶¯Ì¬ÉèÖÃwrapģʽʱ(setWrapSelectorWheel()·½·¨)£¬»áÓС°ÔÝʱÏÔʾ²»³ö²¿·ÖÑ¡ÏµÄÎÊÌ⣻

6. Ñ¡ÖÐλÖÃûÓÐÎÄ×Ö˵Ã÷£»

7. ´úÂëÖв»ÄÜ¿ØÖÆÑ¡Ï¶¯¹ö¶¯µ½Ä³Ò»item£»

×Ô¶¨Òå¿Ø¼þÌØÐÔ-NumberPickerView

1. ÏÔʾ´°¿Ú¿ÉÒÔÏÔʾ¶à¸ö±¸Ñ¡Ñ¡Ï

2. flingʱ»¬¶¯ËٶȽϿ죬ÇÒ¿ÉÒÔÉèÖÃĦ²ÁÁ¦£»

3. ÔÚÑ¡ÖÐÓë·ÇÑ¡ÖеÄ״̬»¬¶¯Ê±£¬¾ßÓн¥±äµÄ¶¯»­Ð§¹û£¬°üÀ¨ÎÄ×Ö·Å´óËõСÒÔ¼°ÑÕÉ«µÄ½¥±ä£»

4. ÔÚÅúÁ¿¸Ä±äÑ¡ÏîÖеÄÄÚÈÝʱ£¬¿ÉÒÔÑ¡ÔñÊÇ·ñ²ÉÓÃÓѺõĻ¬¶¯Ð§¹û£»

5. ¿ÉÒÔ¶¯Ì¬µÄÉèÖÃÊÇ·ñwrap£¬¼´£¬ÊÇ·ñÑ­»·¹ö¶¯£»

6. Ñ¡ÖÐλÖÿÉÒÔÌí¼ÓÎÄ×Ö˵Ã÷£¬¿É¿ØÖÆÎÄ×Ö×ÖÌå´óСÑÕÉ«µÈ£»

7. ¾ßÓÐÔÚ´úÂëÖж¯Ì¬µÄ»¬¶¯µ½Ä³Ò»Î»ÖõŦÄÜ£»

8. Ö§³Öwrap_content£¬Ö§³ÖitemµÄpadding£»

9. Ìṩ¶àÖÖÊôÐÔ£¬ÓÅ»¯UIЧ¹û£»

10. ÔÚ»¬¶¯¹ý³ÌÖв»ÏìÓ¦onValueChanged()

11. µã»÷ÉÏϵ¥Ôª¸ñ£¬¿ÉÒÔ×Ô¶¯»¬¶¯µ½¶ÔÓ¦µÄµã»÷¶ÔÏó¡£

12. ¼æÈÝNumberPickerµÄÖØÒª·½·¨ºÍ½Ó¿Ú£º

    //¼æÈݵķ½·¨ÓÐ:

    setOnValueChangedListener()

    setOnScrollListener()

    setDisplayedValues()/getDisplayedValues()

    setWrapSelectorWheel()/getWrapSelectorWheel()

    setMinValue()/getMinValue()

    setMaxValue()/getMaxValue()

    setValue()/getValue()

    //¼æÈݵÄÄÚ²¿»Øµ÷½Ó¿ÚÓУº

    OnValueChangeListener

    OnScrollListener

ʹÓ÷½·¨

1.µ¼ÈëÖÁ¹¤³Ì

    compile 'cn.carbswang.android:NumberPickerView:1.0.2'

»òÕß

 

    cn.carbswang.android   

    NumberPickerView 

    1.0.2 

    pom

2.ͨ¹ý²¼¾ÖÉùÃ÷NumberPickerView

<cn.carbswang.android.numberpickerview.library.NumberPickerView

    android:id="@+id/picker"

    android:layout_width="wrap_content"

    android:layout_height="240dp"

    android:layout_centerHorizontal="true"

    android:layout_marginTop="20dp"

    android:background="#11333333"

    android:contentDescription="test_number_picker_view"

    app:npv_ItemPaddingHorizental="5dp"

    app:npv_ItemPaddingVertical="5dp"

    app:npv_ShowCount="5"

    app:npv_TextSizeNormal="16sp"

    app:npv_TextSizeSelected="20sp"

    app:npv_WrapSelectorWheel="true"/>

3.Java´úÂëÖÐʹÓãº

  1. ÈôÉèÖõÄÊý¾Ý(String[] mDisplayedValues)Ò»Ö±¹Ì¶¨²»»áÔٴθı䣬¿ÉÒÔʹÓÃÈçÏ·½Ê½½øÐÐÉèÖ㺣¨ÓëNumberPickerµÄÉèÖ÷½Ê½Ò»Ö£©

    picker.setMinValue(minValue);

    picker.setMaxValue(maxValue);

    picker.setValue(value);

  1. ÈôÉèÖõÄÊý¾Ý(String[] mDisplayedValues)»á¸Ä±ä£¬¿ÉÒÔʹÓÃÈçÏÂ×éºÏ·½Ê½½øÐÐÉèÖ㺣¨ÓëNumberPickerµÄ¸ü¸ÄÊý¾Ý·½Ê½Ò»Ö£©

    int minValue = getMinValue();

    int oldMaxValue = getMaxValue();

    int oldSpan = oldMaxValue - minValue + 1;

    int newMaxValue = display.length - 1;

    int newSpan = newMaxValue - minValue + 1;

    if (newSpan > oldSpan) {

        setDisplayedValues(display);

        setMaxValue(newMaxValue);

    } else {

        setMaxValue(newMaxValue);

        setDisplayedValues(display);

    }

»òÕßÖ±½ÓʹÓÃNumberPickerViewÌṩµÄ·½·¨£º

refreshByNewDisplayedValues(String[] display)

ʹÓô˷½·¨Ê±ÐèҪעÒâ±£Ö¤Êý¾Ý¸Ä±äÇ°ºóµÄminValueÖµ²»±ä¡£

4.ÁíÍ⣬NumberPickerViewÌṩÁËƽ»¬¹ö¶¯µÄ·½·¨£º

public void smoothScrollToValue(int fromValue, int toValue, boolean needRespond)

´Ë·½·¨ÓësetValue(int)·½·¨Ïà֮ͬ´¦ÊÇ¿ÉÒÔ¶¯Ì¬ÉèÖõ±Ç°ÏÔʾµÄitem£¬²»Í¬Ö®´¦ÔÚÓÚ´Ë·½·¨¿ÉÒÔʹNumberPickerViewƽ»¬µÄ¹ö¶¯£¬¼´´ÓfromValueÖµÌôÑ¡×î½ü·¾¶¹ö¶¯µ½toValue¡£µÚÈý¸ö²ÎÊýneedRespondÓÃÀ´±êʶÔÚ»¬¶¯¹ý³ÌÖÐÊÇ·ñÏìÓ¦onValueChanged»Øµ÷º¯Êý£¬ÒòΪ¶à¸öNumberPickerViewÔÚÁª¶¯Ê±£¬ºÜ¿ÉÄܲ»Í¬µÄNumberPickerViewµÄֹͣʱ¼ä²»Í¬£¬Èç¹ûÔÚ´ËʱÏìÓ¦ÁËonValueChanged»Øµ÷£¬¾Í¿ÉÄÜÔÙ´ÎÁª¶¯£¬Ôì³ÉÊý¾Ý²»×¼È·£¬½«needRespondÖÃΪfalse£¬¿É±ÜÃâÔÚ»¬¶¯ÖÐÏìÓ¦»Øµ÷º¯Êý¡£

ÁíÍ⣬ÔÚʹÓô˷½·¨»òÕß¼ä½Óµ÷Óô˷½·¨Ê±£¬ÐèҪעÒâ×îºÃ²»ÒªÔÚonCreate(Bundle savedInstanceState)·½·¨Öе÷Óã¬ÒòΪscroll¶¯»­ÐèÒªÒ»¶¨Ê±¼ä£¬ÈçÐèÈ·ÒªÔÚonCreate(Bundle savedInstanceState)Öе÷Óã¬ÇëʹÓÃÈçÏ·½Ê½£º

    @Override 

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        //´úÂëÊ¡ÂÔ

        mNumberPickerView.post(new Runnable() {

            @Override 

            public void run() {

                //µ÷ÓÃsmoothScrollToValue()µÈ·½·¨µÄ´úÂë

        }

    });

½«NumberPicker¸ÄΪNumberPickerView

ÒªÌæ´úÏîÄ¿ÖÐʹÓõÄNumberPicker£¬Ö»ÐèÒª½«Éæ¼°NumberPickerµÄ´úÂ루Èç»Øµ÷Öд«ÈëÁËNumberPicker¡¢Ê¹ÓÃÁËNumberPickerµÄÄÚ²¿½Ó¿Ú£©¸ÄΪNumberPickerView¼´¿É¡£

¸÷Ïî×Ô¶¨ÒåÊôÐÔµÄ˵Ã÷

    <attr name="npv_ShowCount"format="reference|integer"/>//ÏÔʾµÄÌõÄ¿¸öÊý£¬Ä¬ÈÏ3¸ö

    <attr name="npv_ShowDivider"format="reference|boolean"/>//ÊÇ·ñÏÔʾÁ½Ìõdivider£¬Ä¬ÈÏÏÔʾ

    <attr name="npv_DividerColor"format="reference|color"/>//Á½ÌõdividerµÄÑÕÉ«

    <attr name="npv_DividerMarginLeft"format="reference|dimension"/>//divider¾à×ó²àµÄ¾àÀë

    <attr name="npv_DividerMarginRight"format="reference|dimension"/>//divider¾àÓÒ²àµÄ¾àÀë

    <attr name="npv_DividerHeight"format="reference|dimension"/>//dividerµÄ¸ß¶È

    <attr name="npv_TextColorNormal"format="reference|color"/>//δѡÖÐÎÄ×ÖµÄÑÕÉ«

    <attr name="npv_TextColorSelected"format="reference|color"/>//Ñ¡ÖÐÎÄ×ÖµÄÑÕÉ«

    <attr name="npv_TextColorHint"format="reference|color"/>//ÖмäÆ«ÓÒ²à˵Ã÷ÎÄ×ÖµÄÑÕÉ«

    <attr name="npv_TextSizeNormal"format="reference|dimension"/>//δѡÖÐÎÄ×ֵĴóС

    <attr name="npv_TextSizeSelected"format="reference|dimension"/>//Ñ¡ÖÐÎÄ×ֵĴóС

    <attr name="npv_TextSizeHint"format="reference|dimension"/>//˵Ã÷ÎÄ×ֵĴóС

    <attr name="npv_TextArray"format="reference"/>//ÎÄ×ÖÄÚÈÝ£¬stringarrayÀàÐÍ

    <attr name="npv_MinValue"format="reference|integer"/>//×îСֵ£¬Í¬setMinValue()

    <attr name="npv_MaxValue"format="reference|integer"/>//×î´óÖµ£¬Í¬setMaxValue()

    <attr name="npv_WrapSelectorWheel"format="reference|boolean"/>//ÉèÖÃÊÇ·ñwrap£¬Í¬setWrapSelectorWheel

    <attr name="npv_HintText"format="reference|string"/>//ÉèÖÃ˵Ã÷ÎÄ×Ö

    <attr name="npv_EmptyItemHint"format="reference|string"/>//¿ÕÐеÄÏÔʾÎÄ×Ö£¬Ä¬Èϲ»ÏÔʾÈκÎÎÄ×Ö¡£Ö»ÔÚWrapSelectorWheel==falseÊÇÆð×÷ÓÃ

    <attr name="npv_MarginStartOfHint"format="reference|dimension"/>//˵Ã÷ÎÄ×Ö¾àÀë×ó²àµÄ¾àÀ룬"×ó²à"ÊÇÖ¸ÎÄ×Öarray×î¿íitemµÄÓÒ²à

    <attr name="npv_MarginEndOfHint"format="reference|dimension"/>//˵Ã÷ÎÄ×Ö¾àÀëÓÒ²àµÄ¾àÀë

    <attr name="npv_ItemPaddingHorizental"format="reference|dimension"/>//itemµÄˮƽpadding£¬ÓÃÓÚwrap_contentģʽ

    <attr name="npv_ItemPaddingVertical"format="reference|dimension"/>//itemµÄÊúÖ±padding£¬ÓÃÓÚwrap_contentģʽ

//ÒÔÏÂÊôÐÔÓÃÓÚÔÚwrap_contentģʽÏ£¬¸Ä±äÄÚÈÝarray²¢ÇÒÓÖ²»ÏëÈÿؼþ"Ìø¶¯"£¬ÄÇô¾Í¿ÉÒÔÉèÖÃËùÓиıäµÄÄÚÈݵÄ×î´ó¿í¶È

    <attr name="npv_AlternativeTextArrayWithMeasureHint"format="reference"/>//¿ÉÄÜ´ïµ½µÄ×î´ó¿í¶È£¬°üÀ¨ËµÃ÷ÎÄ×ÖÔÚÄÚ£¬×î´ó¿í¶ÈÖ»¿ÉÄܱȴËStringµÄ¿í¶È¸ü´ó

    <attr name="npv_AlternativeTextArrayWithoutMeasureHint"format="reference"/>//¿ÉÄÜ´ïµ½µÄ×î´ó¿í¶È£¬²»°üÀ¨ËµÃ÷ÎÄ×ÖÔÚÄÚ£¬×î´ó¿í¶ÈÖ»¿ÉÄܱȴËStringµÄ¿í¶È+˵Ã÷ÎÄ×Ö+˵Ã÷ÎÄ×Ömarginstart +˵Ã÷ÎÄ×Ömarginend ¸ü´ó

    <attr name="npv_AlternativeHint"format="reference|string"/>//˵Ã÷ÎÄ×ÖµÄ×î´ó¿í¶È

Ö÷ÒªÔ­Àí

Ò»°ãÇé¿öÏ£¬ÎÒÃÇֻʹÓÃNumberPicker¶ÔÎÄ×Ö½øÐÐÑ¡Ôñ£¬ºÜÉÙÉæ¼°µ½Ìí¼Ó²»Í¬µÄViewÉõÖÁÊÇͼƬ£¬Òò´Ë£¬NumberPickerViewÖ»Õë¶Ô´«ÈëµÄString[] ÀàÐ͵ÄÄÚÈÝͨ¹ýonDraw(Canvas canvas)º¯Êý½øÐÐÏÔʾ¡£

ÕâÀïÖ÷ÒªÉæ¼°Èý¸ö֪ʶµã£º

1.¹ö¶¯Ð§¹ûµÄ²úÉú£º

AndroidµÄframeworkÖдøÓÐÒ»¸ö¹¤¾ßÀàScroller£¬´ËÀàµÄ¹¦ÄÜÊǸù¾ÝÊäÈëÖµÒÔ¼°µ±Ç°³ÖÐøµÄʱ¼ä£¬ÅäºÏ²åÖµ¼ÆËãÆ÷£¬¼ÆËã³öµ±Ç°µÄÊä³öÖµ¡£ÊäÈëÖµÒ»°ãÊÇËٶȺÍ×ø±êÖµ£¬Êä³öÖµÊÇ×ø±êÖµ£¬¾ÙÀýÀ´Ëµ£¬¿ÉÒÔ½«ÆäÏëÏñ³É¸ßÖÐÎïÀí¸ù¾Ý³õʼËٶȡ¢¼ÓËٶȺÍÔËÐÐʱ¼äÇóÈ¡µ±Ç°Â·³Ì¡£ScrollerµÄʵÏֱȽÏÇÉÃËü²»»áÔÚstartScroll()ºóÈ¥¼ÆË㵱ǰ¡°Â·³Ì¡±£¬¶øÊÇÖ»¼Ç¼¡°³ö·¢¡±Ê±µÄ¸÷ÖÖ״̬£¬Ö»Óе±ÍⲿÐèÒªÖªµÀ´Ëʱ»¬¶¯µ½µÄλÖÃʱ£¬²Å»áÈ¥¸ù¾Ýʱ¼äÒÔ¼°²åÖµÀ´½øÐмÆË㣬ÕâÖÖÉè¼Æ±ÜÃâÁËÁíÆðÏß³Ìʵʱ¼ÆËãµÈÎÊÌâ¡£ÄÇôÎÊÌâÀ´ÁË£¬Ê²Ã´Ê±ºòÈ¥»ñÈ¡scrollerÖе±Ç°µÄ×ø±êÖµÄØ£¿ÔĶÁViewÀàµÄÔ´Â룬ÎÒÃÇ¿ÉÒÔ¿´µ½ÔÚViewµÄboolean draw(Canvas canvas, ViewGroup parent, long drawingTime)º¯ÊýÖУ¬ÓÐÈçÏ´úÂ룺

    if (!drawingWithRenderNode) {

        computeScroll();

        sx = mScrollX;

        sy = mScrollY;

    }

¼´ÔÚ»æÖÆviewʱ£¬Ïȵ÷ÓÃcomputeScroll()£¬Òò´ËÎÒÃÇ¿ÉÒÔÔÚcomputeScroll()º¯ÊýÖØÐÂÉèÖûòˢе±Ç°µÄ×ø±ê£¬²¢ÔÚonDraw(Canvas canvas)º¯ÊýÖиù¾Ýµ±Ç°µÄ״̬ÖØлæÖÆ´Ëview¡£computeScroll()µÄʹÓ÷½·¨Í¨³£Îª£º

    @Override

    public void computeScroll() {

    //Èç¹ûScrollerÈÔÈ»ÔÚ¹ö¶¯

    if (mScroller.computeScrollOffset()) {

        //»ñÈ¡mScrollerÖеÄÖµ²¢¼ÆËãºÍ¼Ç¼£¬Èç mGlobalY = mScroller.getCurrY();

        //Ë¢ÐÂ

        postInvalidate();

    }

ÔÚNumberPickerViewÖУ¬ÎÒʹÓÃÒ»¸öglobalYÖµÀ´¼Ç¼µ±Ç°¹ö¶¯µ½µÄ×ø±ê£¬²¢Í¨¹ýÓëItemµÄ¸ß¶ÈÏà³ý£¬¼ÆË㵱ǰӦ¸ÃÏÔʾµÄitemµÄÆ«ÒÆÖµ£¬´Ó¶ø»­³öµ±Ç°Ö»ÔÚÏÔʾÇøÓòµÄitem¡£»æÖƵÄ˼·Ã÷È·ÁË£¬ÔÙÀ´¿´»¬¶¯¸úËæÊÖÖ¸Òƶ¯ÒÔ¼°flingЧ¹û¡£ÕâÁ½Õß¾ùÊÇͨ¹ýoverrideonTouchEvent(MotionEvent event)º¯ÊýÀ´ÊµÏֵģ¬²»¹ýʵÏֵľßÌå¹ý³ÌÉÔÓв»Í¬£º

(1). ¸úËæÊÖÖ¸»¬¶¯ÊǸ´Ð´ÁËMotionEvent.ACTION_MOVEµÄÇé¿ö£¬¸ù¾Ýµ±Ç°ÊÖÖ¸Òƶ¯µÄ×ø±êÖµ£¬¼ÆËãglobalYÖµ£¬²¢Ë¢ÐÂÏÔʾ¡£

(2). flingЧ¹ûÊÇͨ¹ýVelocityTracker¹¤¾ßÀàʵÏֵģ¬´Ë¹¤¾ßÀà¿ÉÒÔ¸ù¾Ý½ÓÊÕµÄÁ½¸öÁ¬Ðø·¢³öµÄMotionEventÀ´»ñÈ¡µ±Ç°µÄ»¬¶¯Ëٶȣ¬ÈôËٶȴóÓÚãÐÖµ£¬Ôò½«³õʼ×ø±êÖµ¡¢VelocityTracker¼ÆËã»ñÈ¡µÄËٶȴ«µÝ¸øScroller.fling(...)º¯Êý£¬´ËʱÔÙ´ÎˢУ¬¼´¿Éͨ¹ýcomputeScroll()º¯Êý£¬»ñÈ¡µ±Ç°globalYÖµ£¬½ø¶ø¸üлæͼ¡£

2.×Ô¶¯Ð£×¼Î»ÖÃ

ΪÁËʵÏÖ×Ô¶¯Ð£×¼£¬ÎÒÔÚÿ´ÎÊÖÖ¸Up»òÕßScroller¿ªÊ¼Flingʱ£¬¾ùͨ¹ýhandler·¢ËÍrefreshÏûÏ¢£¬ÔÚ½ÓÊܵ½´ËÏûϢʱ£¬¼ÆË㵱ǰλÖÃÊÇ·ñ´¦ÓÚ±»Ð£×¼µÄλÖã¬Èç¹û·ñ£¬Ôò¼ÆËãÐèÒª»¬¶¯µÄλÒÆ£¬²¢½«Öµ´«µÝ¸øScroller£¬½ø¶ø½øÐÐУ׼»¬¶¯¡£µ±È·±£ÒѾ­Ð£×¼ºó£¬ÔÝÍ£·¢ËÍrefreshÏûÏ¢¡£

3.½¥±äµÄUIЧ¹û

½¥±äUIЧ¹ûͬÑùÊÇͨ¹ý¼ÆË㵱ǰ»¬¶¯µÄ×ø±êÒÔ¼°Ä³¸öitemÓëÖмäÏÔʾλÖõIJîÖµ±ÈÀý£¬À´È·¶¨´ËitemÖеÄ×ÖÌå´óСÒÔ¼°ÑÕÉ«¡£

½«NumberPicker¸ÄΪNumberPickerView

ÒªÌæ´úÏîÄ¿ÖÐʹÓõÄNumberPicker£¬Ö»ÐèÒª½«Éæ¼°NumberPickerµÄ´úÂ루Èç»Øµ÷Öд«ÈëÁËNumberPicker¡¢Ê¹ÓÃÁËNumberPickerµÄÄÚ²¿½Ó¿Ú£©¸ÄΪNumberPickerView¼´¿É¡£

ÏîÄ¿µØÖ·

https://github.com/Carbs0126/NumberPickerView

»¶Ó­´ó¼ÒÖ¸½Ì¡£email:[email protected]