Skip to content

Commit 7f0c850

Browse files
sganovAndroid (Google) Code Review
authored andcommitted
Merge "Updating NumberPicker, TimePicker, DatePicker to fit different screen and font sizes." into ics-mr1
2 parents f9d8faf + ec1e06a commit 7f0c850

File tree

8 files changed

+151
-121
lines changed

8 files changed

+151
-121
lines changed

core/java/android/widget/NumberPicker.java

Lines changed: 116 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -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

core/res/res/layout-sw600dp/date_picker_dialog.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@
2222
android:layout_gravity="center_horizontal"
2323
android:layout_width="wrap_content"
2424
android:layout_height="wrap_content"
25+
android:spinnersShown="true"
26+
android:calendarViewShown="true"
2527
/>

core/res/res/layout-sw600dp/number_picker.xml

Lines changed: 0 additions & 39 deletions
This file was deleted.

core/res/res/layout/date_picker.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<!-- Month -->
4141
<NumberPicker
4242
android:id="@+id/month"
43-
android:layout_width="80dip"
43+
android:layout_width="wrap_content"
4444
android:layout_height="wrap_content"
4545
android:layout_marginLeft="1dip"
4646
android:layout_marginRight="1dip"
@@ -51,7 +51,7 @@
5151
<!-- Day -->
5252
<NumberPicker
5353
android:id="@+id/day"
54-
android:layout_width="80dip"
54+
android:layout_width="wrap_content"
5555
android:layout_height="wrap_content"
5656
android:layout_marginLeft="1dip"
5757
android:layout_marginRight="1dip"
@@ -62,7 +62,7 @@
6262
<!-- Year -->
6363
<NumberPicker
6464
android:id="@+id/year"
65-
android:layout_width="95dip"
65+
android:layout_width="wrap_content"
6666
android:layout_height="wrap_content"
6767
android:layout_marginLeft="1dip"
6868
android:layout_marginRight="1dip"

core/res/res/layout/date_picker_holo.xml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,49 +23,48 @@
2323
depending on the date format selected by the user.
2424
-->
2525
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
26-
android:layout_width="fill_parent"
27-
android:layout_height="fill_parent"
26+
android:layout_width="wrap_content"
27+
android:layout_height="wrap_content"
2828
android:layout_gravity="center_horizontal"
2929
android:orientation="horizontal"
3030
android:gravity="center">
3131

3232
<LinearLayout android:id="@+id/pickers"
3333
android:layout_width="wrap_content"
3434
android:layout_height="wrap_content"
35-
android:layout_marginRight="22dip"
3635
android:layout_weight="1"
3736
android:orientation="horizontal"
3837
android:gravity="center">
3938

4039
<!-- Month -->
4140
<NumberPicker
4241
android:id="@+id/month"
43-
android:layout_width="48dip"
42+
android:layout_width="wrap_content"
4443
android:layout_height="wrap_content"
45-
android:layout_marginLeft="22dip"
46-
android:layout_marginRight="22dip"
44+
android:layout_marginLeft="16dip"
45+
android:layout_marginRight="16dip"
4746
android:focusable="true"
4847
android:focusableInTouchMode="true"
4948
/>
5049

5150
<!-- Day -->
5251
<NumberPicker
5352
android:id="@+id/day"
54-
android:layout_width="48dip"
53+
android:layout_width="wrap_content"
5554
android:layout_height="wrap_content"
56-
android:layout_marginLeft="22dip"
57-
android:layout_marginRight="22dip"
55+
android:layout_marginLeft="16dip"
56+
android:layout_marginRight="16dip"
5857
android:focusable="true"
5958
android:focusableInTouchMode="true"
6059
/>
6160

6261
<!-- Year -->
6362
<NumberPicker
6463
android:id="@+id/year"
65-
android:layout_width="48dip"
64+
android:layout_width="wrap_content"
6665
android:layout_height="wrap_content"
67-
android:layout_marginLeft="22dip"
68-
android:layout_marginRight="22dip"
66+
android:layout_marginLeft="16dip"
67+
android:layout_marginRight="16dip"
6968
android:focusable="true"
7069
android:focusableInTouchMode="true"
7170
/>

0 commit comments

Comments
 (0)