@@ -202,6 +202,11 @@ public String format(int value) {
202202 */
203203 private final EditText mInputText ;
204204
205+ /**
206+ * The min height of this widget.
207+ */
208+ private final int mMinHeight ;
209+
205210 /**
206211 * The max height of this widget.
207212 */
@@ -210,7 +215,17 @@ public String format(int value) {
210215 /**
211216 * The max width of this widget.
212217 */
213- private final int mMaxWidth ;
218+ private final int mMinWidth ;
219+
220+ /**
221+ * The max width of this widget.
222+ */
223+ private int mMaxWidth ;
224+
225+ /**
226+ * Flag whether to compute the max width.
227+ */
228+ private final boolean mComputeMaxWidth ;
214229
215230 /**
216231 * The height of the text.
@@ -527,8 +542,19 @@ public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
527542 getResources ().getDisplayMetrics ());
528543 mSelectionDividerHeight = attributesArray .getDimensionPixelSize (
529544 R .styleable .NumberPicker_selectionDividerHeight , defSelectionDividerHeight );
530- mMaxHeight = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_maxHeight , 0 );
531- mMaxWidth = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_maxWidth , 0 );
545+ mMinHeight = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_minHeight , 0 );
546+ mMaxHeight = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_maxHeight ,
547+ Integer .MAX_VALUE );
548+ if (mMinHeight > mMaxHeight ) {
549+ throw new IllegalArgumentException ("minHeight > maxHeight" );
550+ }
551+ mMinWidth = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_minWidth , 0 );
552+ mMaxWidth = attributesArray .getDimensionPixelSize (R .styleable .NumberPicker_maxWidth ,
553+ Integer .MAX_VALUE );
554+ if (mMinWidth > mMaxWidth ) {
555+ throw new IllegalArgumentException ("minWidth > maxWidth" );
556+ }
557+ mComputeMaxWidth = (mMaxWidth == Integer .MAX_VALUE );
532558 attributesArray .recycle ();
533559
534560 mShowInputControlsAnimimationDuration = getResources ().getInteger (
@@ -677,37 +703,33 @@ public void onAnimationCancel(Animator animation) {
677703
678704 @ Override
679705 protected void onLayout (boolean changed , int left , int top , int right , int bottom ) {
680- if (mMaxHeight <= 0 && mMaxWidth <= 0 ) {
681- super .onLayout (changed , left , top , right , bottom );
682- } else {
683- final int msrdWdth = getMeasuredWidth ();
684- final int msrdHght = getMeasuredHeight ();
685-
686- // Increment button at the top.
687- final int inctBtnMsrdWdth = mIncrementButton .getMeasuredWidth ();
688- final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth ) / 2 ;
689- final int incrBtnTop = 0 ;
690- final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth ;
691- final int incrBtnBottom = incrBtnTop + mIncrementButton .getMeasuredHeight ();
692- mIncrementButton .layout (incrBtnLeft , incrBtnTop , incrBtnRight , incrBtnBottom );
693-
694- // Input text centered horizontally.
695- final int inptTxtMsrdWdth = mInputText .getMeasuredWidth ();
696- final int inptTxtMsrdHght = mInputText .getMeasuredHeight ();
697- final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth ) / 2 ;
698- final int inptTxtTop = (msrdHght - inptTxtMsrdHght ) / 2 ;
699- final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth ;
700- final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght ;
701- mInputText .layout (inptTxtLeft , inptTxtTop , inptTxtRight , inptTxtBottom );
702-
703- // Decrement button at the top.
704- final int decrBtnMsrdWdth = mIncrementButton .getMeasuredWidth ();
705- final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth ) / 2 ;
706- final int decrBtnTop = msrdHght - mDecrementButton .getMeasuredHeight ();
707- final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth ;
708- final int decrBtnBottom = msrdHght ;
709- mDecrementButton .layout (decrBtnLeft , decrBtnTop , decrBtnRight , decrBtnBottom );
710- }
706+ final int msrdWdth = getMeasuredWidth ();
707+ final int msrdHght = getMeasuredHeight ();
708+
709+ // Increment button at the top.
710+ final int inctBtnMsrdWdth = mIncrementButton .getMeasuredWidth ();
711+ final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth ) / 2 ;
712+ final int incrBtnTop = 0 ;
713+ final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth ;
714+ final int incrBtnBottom = incrBtnTop + mIncrementButton .getMeasuredHeight ();
715+ mIncrementButton .layout (incrBtnLeft , incrBtnTop , incrBtnRight , incrBtnBottom );
716+
717+ // Input text centered horizontally.
718+ final int inptTxtMsrdWdth = mInputText .getMeasuredWidth ();
719+ final int inptTxtMsrdHght = mInputText .getMeasuredHeight ();
720+ final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth ) / 2 ;
721+ final int inptTxtTop = (msrdHght - inptTxtMsrdHght ) / 2 ;
722+ final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth ;
723+ final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght ;
724+ mInputText .layout (inptTxtLeft , inptTxtTop , inptTxtRight , inptTxtBottom );
725+
726+ // Decrement button at the top.
727+ final int decrBtnMsrdWdth = mIncrementButton .getMeasuredWidth ();
728+ final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth ) / 2 ;
729+ final int decrBtnTop = msrdHght - mDecrementButton .getMeasuredHeight ();
730+ final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth ;
731+ final int decrBtnBottom = msrdHght ;
732+ mDecrementButton .layout (decrBtnLeft , decrBtnTop , decrBtnRight , decrBtnBottom );
711733
712734 if (!mScrollWheelAndFadingEdgesInitialized ) {
713735 mScrollWheelAndFadingEdgesInitialized = true ;
@@ -719,20 +741,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
719741
720742 @ Override
721743 protected void onMeasure (int widthMeasureSpec , int heightMeasureSpec ) {
722- super .onMeasure (widthMeasureSpec , heightMeasureSpec );
723- final int measuredWidth ;
724- if (mMaxWidth > 0 ) {
725- measuredWidth = getMaxSize (widthMeasureSpec , mMaxWidth );
726- } else {
727- measuredWidth = getMeasuredWidth ();
728- }
729- final int measuredHeight ;
730- if (mMaxHeight > 0 ) {
731- measuredHeight = getMaxSize (heightMeasureSpec , mMaxHeight );
732- } else {
733- measuredHeight = getMeasuredHeight ();
734- }
735- setMeasuredDimension (measuredWidth , measuredHeight );
744+ final int newWidthMeasureSpec = makeMeasureSpec (widthMeasureSpec , mMinWidth , mMaxWidth );
745+ final int newHeightMeasureSpec = makeMeasureSpec (heightMeasureSpec , mMinHeight , mMaxHeight );
746+ super .onMeasure (newWidthMeasureSpec , newHeightMeasureSpec );
736747 }
737748
738749 @ Override
@@ -1033,6 +1044,49 @@ public void setValue(int value) {
10331044 invalidate ();
10341045 }
10351046
1047+ /**
1048+ * Computes the max width if no such specified as an attribute.
1049+ */
1050+ private void tryComputeMaxWidth () {
1051+ if (!mComputeMaxWidth ) {
1052+ return ;
1053+ }
1054+ int maxTextWidth = 0 ;
1055+ if (mDisplayedValues == null ) {
1056+ float maxDigitWidth = 0 ;
1057+ for (int i = 0 ; i <= 9 ; i ++) {
1058+ final float digitWidth = mSelectorWheelPaint .measureText (String .valueOf (i ));
1059+ if (digitWidth > maxDigitWidth ) {
1060+ maxDigitWidth = digitWidth ;
1061+ }
1062+ }
1063+ int numberOfDigits = 0 ;
1064+ int current = mMaxValue ;
1065+ while (current > 0 ) {
1066+ numberOfDigits ++;
1067+ current = current / 10 ;
1068+ }
1069+ maxTextWidth = (int ) (numberOfDigits * maxDigitWidth );
1070+ } else {
1071+ final int valueCount = mDisplayedValues .length ;
1072+ for (int i = 0 ; i < valueCount ; i ++) {
1073+ final float textWidth = mSelectorWheelPaint .measureText (mDisplayedValues [i ]);
1074+ if (textWidth > maxTextWidth ) {
1075+ maxTextWidth = (int ) textWidth ;
1076+ }
1077+ }
1078+ }
1079+ maxTextWidth += mInputText .getPaddingLeft () + mInputText .getPaddingRight ();
1080+ if (mMaxWidth != maxTextWidth ) {
1081+ if (maxTextWidth > mMinWidth ) {
1082+ mMaxWidth = maxTextWidth ;
1083+ } else {
1084+ mMaxWidth = mMinWidth ;
1085+ }
1086+ invalidate ();
1087+ }
1088+ }
1089+
10361090 /**
10371091 * Gets whether the selector wheel wraps when reaching the min/max value.
10381092 *
@@ -1119,6 +1173,7 @@ public void setMinValue(int minValue) {
11191173 setWrapSelectorWheel (wrapSelectorWheel );
11201174 initializeSelectorWheelIndices ();
11211175 updateInputTextView ();
1176+ tryComputeMaxWidth ();
11221177 }
11231178
11241179 /**
@@ -1150,6 +1205,7 @@ public void setMaxValue(int maxValue) {
11501205 setWrapSelectorWheel (wrapSelectorWheel );
11511206 initializeSelectorWheelIndices ();
11521207 updateInputTextView ();
1208+ tryComputeMaxWidth ();
11531209 }
11541210
11551211 /**
@@ -1298,24 +1354,28 @@ public void sendAccessibilityEvent(int eventType) {
12981354 }
12991355
13001356 /**
1301- * Gets the max value for a size based on the measure spec passed by
1302- * the parent and the max value for that size.
1357+ * Makes a measure spec that tries greedily to use the max value.
13031358 *
13041359 * @param measureSpec The measure spec.
13051360 * @param maxValue The max value for the size.
1306- * @return The max size.
1361+ * @return A measure spec greedily imposing the max size.
13071362 */
1308- private int getMaxSize (int measureSpec , int maxValue ) {
1363+ private int makeMeasureSpec (int measureSpec , int minValue , int maxValue ) {
1364+ final int size = MeasureSpec .getSize (measureSpec );
1365+ if (size < minValue ) {
1366+ throw new IllegalArgumentException ("Available space is less than min size: "
1367+ + size + " < " + minValue );
1368+ }
13091369 final int mode = MeasureSpec .getMode (measureSpec );
13101370 switch (mode ) {
13111371 case MeasureSpec .EXACTLY :
1312- return MeasureSpec . getSize ( measureSpec ) ;
1372+ return measureSpec ;
13131373 case MeasureSpec .AT_MOST :
1314- return Math .min (MeasureSpec . getSize ( measureSpec ) , maxValue );
1374+ return MeasureSpec . makeMeasureSpec ( Math .min (size , maxValue ), MeasureSpec . EXACTLY );
13151375 case MeasureSpec .UNSPECIFIED :
1316- return maxValue ;
1376+ return MeasureSpec . makeMeasureSpec ( maxValue , MeasureSpec . EXACTLY ) ;
13171377 default :
1318- throw new IllegalArgumentException ();
1378+ throw new IllegalArgumentException ("Unknown measure mode: " + mode );
13191379 }
13201380 }
13211381
0 commit comments