Merge "Revamping of the NumberPicker widget for improved usablility."

This commit is contained in:
Svetoslav Ganov
2011-09-28 19:43:55 -07:00
committed by Android (Google) Code Review
3 changed files with 282 additions and 141 deletions

View File

@@ -16,13 +16,10 @@
package android.widget;
import com.android.internal.R;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -30,8 +27,8 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputFilter;
import android.text.InputType;
@@ -43,16 +40,18 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.LayoutInflater.Filter;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.LayoutInflater.Filter;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
/**
* A widget that enables the user to select a number form a predefined range.
* The widget presents an input filed and up and down buttons for selecting the
@@ -90,6 +89,12 @@ public class NumberPicker extends LinearLayout {
*/
private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
/**
* The duration of scrolling to the next/previous value while changing
* the current value by one, i.e. increment or decrement.
*/
private static final int CHANGE_CURRENT_BY_ONE_SCROLL_DURATION = 300;
/**
* The the delay for showing the input controls after a single tap on the
* input text.
@@ -97,16 +102,6 @@ public class NumberPicker extends LinearLayout {
private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration
.getDoubleTapTimeout();
/**
* The update step for incrementing the current value.
*/
private static final int UPDATE_STEP_INCREMENT = 1;
/**
* The update step for decrementing the current value.
*/
private static final int UPDATE_STEP_DECREMENT = -1;
/**
* The strength of fading in the top and bottom while drawing the selector.
*/
@@ -115,7 +110,52 @@ public class NumberPicker extends LinearLayout {
/**
* The default unscaled height of the selection divider.
*/
private final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2;
private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2;
/**
* In this state the selector wheel is not shown.
*/
private static final int SELECTOR_WHEEL_STATE_NONE = 0;
/**
* In this state the selector wheel is small.
*/
private static final int SELECTOR_WHEEL_STATE_SMALL = 1;
/**
* In this state the selector wheel is large.
*/
private static final int SELECTOR_WHEEL_STATE_LARGE = 2;
/**
* The alpha of the selector wheel when it is bright.
*/
private static final int SELECTOR_WHEEL_BRIGHT_ALPHA = 255;
/**
* The alpha of the selector wheel when it is dimmed.
*/
private static final int SELECTOR_WHEEL_DIM_ALPHA = 60;
/**
* The alpha for the increment/decrement button when it is transparent.
*/
private static final int BUTTON_ALPHA_TRANSPARENT = 0;
/**
* The alpha for the increment/decrement button when it is opaque.
*/
private static final int BUTTON_ALPHA_OPAQUE = 1;
/**
* The property for setting the selector paint.
*/
private static final String PROPERTY_SELECTOR_PAINT_ALPHA = "selectorPaintAlpha";
/**
* The property for setting the increment/decrement button alpha.
*/
private static final String PROPERTY_BUTTON_ALPHA = "alpha";
/**
* The numbers accepted by the input text's {@link Filter}
@@ -167,6 +207,11 @@ public class NumberPicker extends LinearLayout {
*/
private final int mTextSize;
/**
* The height of the gap between text elements if the selector wheel.
*/
private int mSelectorTextGapHeight;
/**
* The values to be displayed instead the indices.
*/
@@ -223,7 +268,7 @@ public class NumberPicker extends LinearLayout {
/**
* The {@link Paint} for drawing the selector.
*/
private final Paint mSelectorPaint;
private final Paint mSelectorWheelPaint;
/**
* The height of a selector element (text + gap).
@@ -266,16 +311,21 @@ public class NumberPicker extends LinearLayout {
private AdjustScrollerCommand mAdjustScrollerCommand;
/**
* Handle to the reusable command for updating the current value from long
* press.
* Handle to the reusable command for changing the current value from long
* press by one.
*/
private UpdateValueFromLongPressCommand mUpdateFromLongPressCommand;
private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand;
/**
* {@link Animator} for showing the up/down arrows.
*/
private final AnimatorSet mShowInputControlsAnimator;
/**
* {@link Animator} for dimming the selector wheel.
*/
private final Animator mDimSelectorWheelAnimator;
/**
* The Y position of the last down event.
*/
@@ -297,9 +347,9 @@ public class NumberPicker extends LinearLayout {
private boolean mAdjustScrollerOnUpEvent;
/**
* Flag if to draw the selector wheel.
* The state of the selector wheel.
*/
private boolean mDrawSelectorWheel;
private int mSelectorWheelState;
/**
* Determines speed during touch scrolling.
@@ -361,6 +411,11 @@ public class NumberPicker extends LinearLayout {
*/
private final long mShowInputControlsAnimimationDuration;
/**
* Flag whether the scoll wheel and the fading edges have been initialized.
*/
private boolean mScrollWheelAndFadingEdgesInitialized;
/**
* Interface to listen for changes of the current value.
*/
@@ -473,7 +528,7 @@ public class NumberPicker extends LinearLayout {
// the fading edge effect implemented by View and we need our
// draw() method to be called. Therefore, we declare we will draw.
setWillNotDraw(false);
setDrawScrollWheel(false);
setSelectorWheelState(SELECTOR_WHEEL_STATE_NONE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
@@ -483,9 +538,9 @@ public class NumberPicker extends LinearLayout {
public void onClick(View v) {
mInputText.clearFocus();
if (v.getId() == R.id.increment) {
changeCurrent(mValue + 1);
changeCurrentByOne(true);
} else {
changeCurrent(mValue - 1);
changeCurrentByOne(false);
}
}
};
@@ -494,9 +549,9 @@ public class NumberPicker extends LinearLayout {
public boolean onLongClick(View v) {
mInputText.clearFocus();
if (v.getId() == R.id.increment) {
postUpdateValueFromLongPress(UPDATE_STEP_INCREMENT);
postChangeCurrentByOneFromLongPress(true);
} else {
postUpdateValueFromLongPress(UPDATE_STEP_DECREMENT);
postChangeCurrentByOneFromLongPress(false);
}
return true;
}
@@ -516,10 +571,17 @@ public class NumberPicker extends LinearLayout {
mInputText = (EditText) findViewById(R.id.numberpicker_input);
mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
if (hasFocus) {
mInputText.selectAll();
if (inputMethodManager != null) {
inputMethodManager.showSoftInput(mInputText, 0);
}
} else {
mInputText.setSelection(0, 0);
if (inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
}
validateInputTextView(v);
}
}
@@ -548,16 +610,17 @@ public class NumberPicker extends LinearLayout {
ColorStateList colors = mInputText.getTextColors();
int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE);
paint.setColor(color);
mSelectorPaint = paint;
mSelectorWheelPaint = paint;
// create the animator for showing the input controls
final ValueAnimator fadeScroller = ObjectAnimator.ofInt(this, "selectorPaintAlpha", 255, 0);
mDimSelectorWheelAnimator = ObjectAnimator.ofInt(this, PROPERTY_SELECTOR_PAINT_ALPHA,
SELECTOR_WHEEL_BRIGHT_ALPHA, SELECTOR_WHEEL_DIM_ALPHA);
final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton,
"alpha", 0, 1);
PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton,
"alpha", 0, 1);
PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
mShowInputControlsAnimator = new AnimatorSet();
mShowInputControlsAnimator.playTogether(fadeScroller, showIncrementButton,
mShowInputControlsAnimator.playTogether(mDimSelectorWheelAnimator, showIncrementButton,
showDecrementButton);
mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCanceled = false;
@@ -566,11 +629,9 @@ public class NumberPicker extends LinearLayout {
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
// if canceled => we still want the wheel drawn
setDrawScrollWheel(false);
setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
}
mCanceled = false;
mSelectorPaint.setAlpha(255);
invalidate();
}
@Override
@@ -588,20 +649,28 @@ public class NumberPicker extends LinearLayout {
updateInputTextView();
updateIncrementAndDecrementButtonsVisibilityState();
if (mFlingable && !isInEditMode()) {
// Start with shown selector wheel and hidden controls. When made
// visible hide the selector and fade-in the controls to suggest
// fling interaction.
setDrawScrollWheel(true);
hideInputControls();
if (mFlingable) {
if (isInEditMode()) {
setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
} else {
// Start with shown selector wheel and hidden controls. When made
// visible hide the selector and fade-in the controls to suggest
// fling interaction.
setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
hideInputControls();
}
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// need to do this when we know our size
initializeScrollWheel();
if (!mScrollWheelAndFadingEdgesInitialized) {
mScrollWheelAndFadingEdgesInitialized = true;
// need to do all this when we know our size
initializeSelectorWheel();
initializeFadingEdges();
}
}
@Override
@@ -614,9 +683,10 @@ public class NumberPicker extends LinearLayout {
mLastMotionEventY = mLastDownEventY = event.getY();
removeAllCallbacks();
mShowInputControlsAnimator.cancel();
mDimSelectorWheelAnimator.cancel();
mBeginEditOnUpEvent = false;
mAdjustScrollerOnUpEvent = true;
if (mDrawSelectorWheel) {
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
boolean scrollersFinished = mFlingScroller.isFinished()
&& mAdjustScroller.isFinished();
if (!scrollersFinished) {
@@ -635,7 +705,7 @@ public class NumberPicker extends LinearLayout {
|| (!mDecrementButton.isShown()
&& isEventInViewHitRect(event, mDecrementButton))) {
mAdjustScrollerOnUpEvent = false;
setDrawScrollWheel(true);
setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
hideInputControls();
return true;
}
@@ -646,7 +716,7 @@ public class NumberPicker extends LinearLayout {
if (deltaDownY > mTouchSlop) {
mBeginEditOnUpEvent = false;
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
setDrawScrollWheel(true);
setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
hideInputControls();
return true;
}
@@ -683,12 +753,9 @@ public class NumberPicker extends LinearLayout {
break;
case MotionEvent.ACTION_UP:
if (mBeginEditOnUpEvent) {
setDrawScrollWheel(false);
setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
showInputControls(mShowInputControlsAnimimationDuration);
mInputText.requestFocus();
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mInputText, 0);
return true;
}
VelocityTracker velocityTracker = mVelocityTracker;
@@ -715,10 +782,18 @@ public class NumberPicker extends LinearLayout {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if ((action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP)
&& !isEventInViewHitRect(event, mInputText)) {
removeAllCallbacks();
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_MOVE:
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
removeAllCallbacks();
forceCompleteChangeCurrentByOneViaScroll();
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
removeAllCallbacks();
break;
}
return super.dispatchTouchEvent(event);
}
@@ -743,7 +818,7 @@ public class NumberPicker extends LinearLayout {
@Override
public void computeScroll() {
if (!mDrawSelectorWheel) {
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
return;
}
Scroller scroller = mFlingScroller;
@@ -777,7 +852,10 @@ public class NumberPicker extends LinearLayout {
@Override
public void scrollBy(int x, int y) {
int[] selectorIndices = getSelectorIndices();
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
return;
}
int[] selectorIndices = mSelectorIndices;
if (!mWrapSelectorWheel && y > 0
&& selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
mCurrentScrollOffset = mInitialScrollOffset;
@@ -789,19 +867,19 @@ public class NumberPicker extends LinearLayout {
return;
}
mCurrentScrollOffset += y;
while (mCurrentScrollOffset - mInitialScrollOffset >= mSelectorElementHeight) {
while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) {
mCurrentScrollOffset -= mSelectorElementHeight;
decrementSelectorIndices(selectorIndices);
changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
mCurrentScrollOffset = mInitialScrollOffset;
}
}
while (mCurrentScrollOffset - mInitialScrollOffset <= -mSelectorElementHeight) {
while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) {
mCurrentScrollOffset += mSelectorElementHeight;
incrementScrollSelectorIndices(selectorIndices);
incrementSelectorIndices(selectorIndices);
changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) {
if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) {
mCurrentScrollOffset = mInitialScrollOffset;
}
}
@@ -847,7 +925,7 @@ public class NumberPicker extends LinearLayout {
return;
}
mFormatter = formatter;
resetSelectorWheelIndices();
initializeSelectorWheelIndices();
updateInputTextView();
}
@@ -890,8 +968,10 @@ public class NumberPicker extends LinearLayout {
value = mWrapSelectorWheel ? mMinValue : mMaxValue;
}
mValue = value;
initializeSelectorWheelIndices();
updateInputTextView();
updateIncrementAndDecrementButtonsVisibilityState();
invalidate();
}
/**
@@ -981,7 +1061,7 @@ public class NumberPicker extends LinearLayout {
}
boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
setWrapSelectorWheel(wrapSelectorWheel);
resetSelectorWheelIndices();
initializeSelectorWheelIndices();
updateInputTextView();
}
@@ -1012,7 +1092,7 @@ public class NumberPicker extends LinearLayout {
}
boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
setWrapSelectorWheel(wrapSelectorWheel);
resetSelectorWheelIndices();
initializeSelectorWheelIndices();
updateInputTextView();
}
@@ -1043,7 +1123,7 @@ public class NumberPicker extends LinearLayout {
mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
}
updateInputTextView();
resetSelectorWheelIndices();
initializeSelectorWheelIndices();
}
@Override
@@ -1080,18 +1160,19 @@ public class NumberPicker extends LinearLayout {
@Override
public void draw(Canvas canvas) {
// Dispatch draw to our children only if we are not currently running
// the animation for simultaneously fading out the scroll wheel and
// the animation for simultaneously dimming the scroll wheel and
// showing in the buttons. This class takes advantage of the View
// implementation of fading edges effect to draw the selector wheel.
// However, in View.draw(), the fading is applied after all the children
// have been drawn and we do not want this fading to be applied to the
// buttons which are currently showing in. Therefore, we draw our
// children after we have completed drawing ourselves.
// buttons. Therefore, we draw our children after we have completed
// drawing ourselves.
super.draw(canvas);
// Draw our children if we are not showing the selector wheel of fading
// it out
if (mShowInputControlsAnimator.isRunning() || !mDrawSelectorWheel) {
if (mShowInputControlsAnimator.isRunning()
|| mSelectorWheelState != SELECTOR_WHEEL_STATE_LARGE) {
long drawTime = getDrawingTime();
for (int i = 0, count = getChildCount(); i < count; i++) {
View child = getChildAt(i);
@@ -1105,25 +1186,32 @@ public class NumberPicker extends LinearLayout {
@Override
protected void onDraw(Canvas canvas) {
// we only draw the selector wheel
if (!mDrawSelectorWheel) {
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
return;
}
float x = (mRight - mLeft) / 2;
float y = mCurrentScrollOffset;
final int restoreCount = canvas.save();
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_SMALL) {
Rect clipBounds = canvas.getClipBounds();
clipBounds.inset(0, mSelectorElementHeight);
canvas.clipRect(clipBounds);
}
// draw the selector wheel
int[] selectorIndices = getSelectorIndices();
int[] selectorIndices = mSelectorIndices;
for (int i = 0; i < selectorIndices.length; i++) {
int selectorIndex = selectorIndices[i];
String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
canvas.drawText(scrollSelectorValue, x, y, mSelectorPaint);
canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
y += mSelectorElementHeight;
}
// draw the selection dividers (only if scrolling and drawable specified)
if (mSelectionDivider != null) {
mSelectionDivider.setAlpha(mSelectorPaint.getAlpha());
// draw the top divider
int topOfTopDivider =
(getHeight() - mSelectorElementHeight - mSelectionDividerHeight) / 2;
@@ -1137,6 +1225,8 @@ public class NumberPicker extends LinearLayout {
mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider);
mSelectionDivider.draw(canvas);
}
canvas.restoreToCount(restoreCount);
}
@Override
@@ -1149,11 +1239,17 @@ public class NumberPicker extends LinearLayout {
* Resets the selector indices and clear the cached
* string representation of these indices.
*/
private void resetSelectorWheelIndices() {
private void initializeSelectorWheelIndices() {
mSelectorIndexToStringCache.clear();
int[] selectorIdices = getSelectorIndices();
for (int i = 0; i < selectorIdices.length; i++) {
selectorIdices[i] = Integer.MIN_VALUE;
int[] selectorIdices = mSelectorIndices;
int current = getValue();
for (int i = 0; i < mSelectorIndices.length; i++) {
int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX);
if (mWrapSelectorWheel) {
selectorIndex = getWrappedSelectorIndex(selectorIndex);
}
mSelectorIndices[i] = selectorIndex;
ensureCachedScrollSelectorValue(mSelectorIndices[i]);
}
}
@@ -1178,17 +1274,60 @@ public class NumberPicker extends LinearLayout {
notifyChange(previous, current);
}
/**
* Changes the current value by one which is increment or
* decrement based on the passes argument.
*
* @param increment True to increment, false to decrement.
*/
private void changeCurrentByOne(boolean increment) {
if (mFlingable) {
mDimSelectorWheelAnimator.cancel();
mInputText.setVisibility(View.INVISIBLE);
mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
mPreviousScrollerY = 0;
forceCompleteChangeCurrentByOneViaScroll();
if (increment) {
mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight,
CHANGE_CURRENT_BY_ONE_SCROLL_DURATION);
} else {
mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight,
CHANGE_CURRENT_BY_ONE_SCROLL_DURATION);
}
invalidate();
} else {
if (increment) {
changeCurrent(mValue + 1);
} else {
changeCurrent(mValue - 1);
}
}
}
/**
* Ensures that if we are in the process of changing the current value
* by one via scrolling the scroller gets to its final state and the
* value is updated.
*/
private void forceCompleteChangeCurrentByOneViaScroll() {
Scroller scroller = mFlingScroller;
if (!scroller.isFinished()) {
final int yBeforeAbort = scroller.getCurrY();
scroller.abortAnimation();
final int yDelta = scroller.getCurrY() - yBeforeAbort;
scrollBy(0, yDelta);
}
}
/**
* Sets the <code>alpha</code> of the {@link Paint} for drawing the selector
* wheel.
*/
@SuppressWarnings("unused")
// Called by ShowInputControlsAnimator via reflection
// Called via reflection
private void setSelectorPaintAlpha(int alpha) {
mSelectorPaint.setAlpha(alpha);
if (mDrawSelectorWheel) {
invalidate();
}
mSelectorWheelPaint.setAlpha(alpha);
invalidate();
}
/**
@@ -1200,14 +1339,15 @@ public class NumberPicker extends LinearLayout {
}
/**
* Sets if to <code>drawSelectionWheel</code>.
* Sets the <code>selectorWheelState</code>.
*/
private void setDrawScrollWheel(boolean drawSelectorWheel) {
mDrawSelectorWheel = drawSelectorWheel;
// do not fade if the selector wheel not shown
setVerticalFadingEdgeEnabled(drawSelectorWheel);
private void setSelectorWheelState(int selectorWheelState) {
mSelectorWheelState = selectorWheelState;
if (selectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
}
if (mFlingable && mDrawSelectorWheel
if (mFlingable && selectorWheelState == SELECTOR_WHEEL_STATE_LARGE
&& AccessibilityManager.getInstance(mContext).isEnabled()) {
AccessibilityManager.getInstance(mContext).interrupt();
String text = mContext.getString(R.string.number_picker_increment_scroll_action);
@@ -1217,16 +1357,14 @@ public class NumberPicker extends LinearLayout {
}
}
private void initializeScrollWheel() {
if (mInitialScrollOffset != Integer.MIN_VALUE) {
return;
}
int[] selectorIndices = getSelectorIndices();
private void initializeSelectorWheel() {
initializeSelectorWheelIndices();
int[] selectorIndices = mSelectorIndices;
int totalTextHeight = selectorIndices.length * mTextSize;
float totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
float textGapCount = selectorIndices.length - 1;
int selectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
mSelectorElementHeight = mTextSize + selectorTextGapHeight;
mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
mSelectorElementHeight = mTextSize + mSelectorTextGapHeight;
// Ensure that the middle item is positioned the same as the text in mInputText
int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop();
mInitialScrollOffset = editTextTextPosition -
@@ -1235,13 +1373,23 @@ public class NumberPicker extends LinearLayout {
updateInputTextView();
}
private void initializeFadingEdges() {
setVerticalFadingEdgeEnabled(true);
setFadingEdgeLength((mBottom - mTop - mTextSize) / 2);
}
/**
* Callback invoked upon completion of a given <code>scroller</code>.
*/
private void onScrollerFinished(Scroller scroller) {
if (scroller == mFlingScroller) {
postAdjustScrollerCommand(0);
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
postAdjustScrollerCommand(0);
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
} else {
updateInputTextView();
fadeSelectorWheel(mShowInputControlsAnimimationDuration);
}
} else {
updateInputTextView();
showInputControls(mShowInputControlsAnimimationDuration);
@@ -1311,6 +1459,17 @@ public class NumberPicker extends LinearLayout {
mShowInputControlsAnimator.start();
}
/**
* Fade the selector wheel via an animation.
*
* @param animationDuration The duration of the animation.
*/
private void fadeSelectorWheel(long animationDuration) {
mInputText.setVisibility(VISIBLE);
mDimSelectorWheelAnimator.setDuration(animationDuration);
mDimSelectorWheelAnimator.start();
}
/**
* Updates the visibility state of the increment and decrement buttons.
*/
@@ -1327,25 +1486,6 @@ public class NumberPicker extends LinearLayout {
}
}
/**
* @return The selector indices array with proper values with the current as
* the middle one.
*/
private int[] getSelectorIndices() {
int current = getValue();
if (mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] != current) {
for (int i = 0; i < mSelectorIndices.length; i++) {
int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX);
if (mWrapSelectorWheel) {
selectorIndex = getWrappedSelectorIndex(selectorIndex);
}
mSelectorIndices[i] = selectorIndex;
ensureCachedScrollSelectorValue(mSelectorIndices[i]);
}
}
return mSelectorIndices;
}
/**
* @return The wrapped index <code>selectorIndex</code> value.
*/
@@ -1362,7 +1502,7 @@ public class NumberPicker extends LinearLayout {
* Increments the <code>selectorIndices</code> whose string representations
* will be displayed in the selector.
*/
private void incrementScrollSelectorIndices(int[] selectorIndices) {
private void incrementSelectorIndices(int[] selectorIndices) {
for (int i = 0; i < selectorIndices.length - 1; i++) {
selectorIndices[i] = selectorIndices[i + 1];
}
@@ -1467,25 +1607,26 @@ public class NumberPicker extends LinearLayout {
}
/**
* Posts a command for updating the current value every <code>updateMillis
* </code>.
* Posts a command for changing the current value by one.
*
* @param increment Whether to increment or decrement the value.
*/
private void postUpdateValueFromLongPress(int updateMillis) {
private void postChangeCurrentByOneFromLongPress(boolean increment) {
mInputText.clearFocus();
removeAllCallbacks();
if (mUpdateFromLongPressCommand == null) {
mUpdateFromLongPressCommand = new UpdateValueFromLongPressCommand();
if (mChangeCurrentByOneFromLongPressCommand == null) {
mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand();
}
mUpdateFromLongPressCommand.setUpdateStep(updateMillis);
post(mUpdateFromLongPressCommand);
mChangeCurrentByOneFromLongPressCommand.setIncrement(increment);
post(mChangeCurrentByOneFromLongPressCommand);
}
/**
* Removes all pending callback from the message queue.
*/
private void removeAllCallbacks() {
if (mUpdateFromLongPressCommand != null) {
removeCallbacks(mUpdateFromLongPressCommand);
if (mChangeCurrentByOneFromLongPressCommand != null) {
removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
}
if (mAdjustScrollerCommand != null) {
removeCallbacks(mAdjustScrollerCommand);
@@ -1658,17 +1799,17 @@ public class NumberPicker extends LinearLayout {
}
/**
* Command for updating the current value from a long press.
* Command for changing the current value from a long press by one.
*/
class UpdateValueFromLongPressCommand implements Runnable {
private int mUpdateStep = 0;
class ChangeCurrentByOneFromLongPressCommand implements Runnable {
private boolean mIncrement;
private void setUpdateStep(int updateStep) {
mUpdateStep = updateStep;
private void setIncrement(boolean increment) {
mIncrement = increment;
}
public void run() {
changeCurrent(mValue + mUpdateStep);
changeCurrentByOne(mIncrement);
postDelayed(this, mLongPressUpdateInterval);
}
}

View File

@@ -23,8 +23,6 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/numberPickerUpButtonStyle"
android:paddingTop="22dip"
android:paddingBottom="22dip"
android:contentDescription="@string/number_picker_increment_button" />
<EditText android:id="@+id/numberpicker_input"
@@ -36,8 +34,6 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/numberPickerDownButtonStyle"
android:paddingTop="22dip"
android:paddingBottom="22dip"
android:contentDescription="@string/number_picker_decrement_button" />
</merge>

View File

@@ -524,10 +524,14 @@ please see styles_device_defaults.xml.
<style name="Widget.ImageButton.NumberPickerUpButton">
<item name="android:background">@android:drawable/numberpicker_up_btn</item>
<item name="android:paddingTop">22dip</item>
<item name="android:paddingBottom">22dip</item>
</style>
<style name="Widget.ImageButton.NumberPickerDownButton">
<item name="android:background">@android:drawable/numberpicker_down_btn</item>
<item name="android:paddingTop">22dip</item>
<item name="android:paddingBottom">22dip</item>
</style>
<style name="Widget.EditText.NumberPickerInputText">
@@ -1651,15 +1655,15 @@ please see styles_device_defaults.xml.
<style name="Widget.Holo.ImageButton.NumberPickerUpButton">
<item name="android:background">@null</item>
<item name="android:src">@android:drawable/numberpicker_up_btn_holo_dark</item>
<item name="android:paddingTop">26dip</item>
<item name="android:paddingBottom">26dip</item>
<item name="android:paddingTop">16dip</item>
<item name="android:paddingBottom">36dip</item>
</style>
<style name="Widget.Holo.ImageButton.NumberPickerDownButton">
<item name="android:background">@null</item>
<item name="android:src">@android:drawable/numberpicker_down_btn_holo_dark</item>
<item name="android:paddingTop">26dip</item>
<item name="android:paddingBottom">26dip</item>
<item name="android:paddingTop">36dip</item>
<item name="android:paddingBottom">16dip</item>
</style>
<style name="Widget.Holo.EditText.NumberPickerInputText">