VerticalTextSpinnerpublic class VerticalTextSpinner extends android.view.View
Fields Summary |
---|
private static final int | SELECTOR_ARROW_HEIGHT | private static final int | TEXT_SPACING | private static final int | TEXT_MARGIN_RIGHT | private static final int | TEXT_SIZE | private static final int | TEXT1_Y | private static final int | TEXT2_Y | private static final int | TEXT3_Y | private static final int | TEXT4_Y | private static final int | TEXT5_Y | private static final int | SCROLL_MODE_NONE | private static final int | SCROLL_MODE_UP | private static final int | SCROLL_MODE_DOWN | private static final long | DEFAULT_SCROLL_INTERVAL_MS | private static final int | SCROLL_DISTANCE | private static final int | MIN_ANIMATIONS | private final android.graphics.drawable.Drawable | mBackgroundFocused | private final android.graphics.drawable.Drawable | mSelectorFocused | private final android.graphics.drawable.Drawable | mSelectorNormal | private final int | mSelectorDefaultY | private final int | mSelectorMinY | private final int | mSelectorMaxY | private final int | mSelectorHeight | private final android.text.TextPaint | mTextPaintDark | private final android.text.TextPaint | mTextPaintLight | private int | mSelectorY | private android.graphics.drawable.Drawable | mSelector | private int | mDownY | private boolean | isDraggingSelector | private int | mScrollMode | private long | mScrollInterval | private boolean | mIsAnimationRunning | private boolean | mStopAnimation | private boolean | mWrapAround | private int | mTotalAnimatedDistance | private int | mNumberOfAnimations | private long | mDelayBetweenAnimations | private int | mDistanceOfEachAnimation | private String[] | mTextList | private int | mCurrentSelectedPos | private OnChangedListener | mListener | private String | mText1 | private String | mText2 | private String | mText3 | private String | mText4 | private String | mText5 |
Constructors Summary |
---|
public VerticalTextSpinner(android.content.Context context)
this(context, null);
| public VerticalTextSpinner(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, 0);
| public VerticalTextSpinner(android.content.Context context, android.util.AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
mBackgroundFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_background);
mSelectorFocused = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_selected);
mSelectorNormal = context.getResources().getDrawable(com.android.internal.R.drawable.pickerbox_unselected);
mSelectorHeight = mSelectorFocused.getIntrinsicHeight();
mSelectorDefaultY = (mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight) / 2;
mSelectorMinY = 0;
mSelectorMaxY = mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight;
mSelector = mSelectorNormal;
mSelectorY = mSelectorDefaultY;
mTextPaintDark = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaintDark.setTextSize(TEXT_SIZE);
mTextPaintDark.setColor(context.getResources().getColor(com.android.internal.R.color.primary_text_light));
mTextPaintLight = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaintLight.setTextSize(TEXT_SIZE);
mTextPaintLight.setColor(context.getResources().getColor(com.android.internal.R.color.secondary_text_dark));
mScrollMode = SCROLL_MODE_NONE;
mScrollInterval = DEFAULT_SCROLL_INTERVAL_MS;
calculateAnimationValues();
|
Methods Summary |
---|
private void | calculateAnimationValues()
mNumberOfAnimations = (int) mScrollInterval / SCROLL_DISTANCE;
if (mNumberOfAnimations < MIN_ANIMATIONS) {
mNumberOfAnimations = MIN_ANIMATIONS;
mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
mDelayBetweenAnimations = 0;
} else {
mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
mDelayBetweenAnimations = mScrollInterval / mNumberOfAnimations;
}
| private void | calculateTextPositions()Called every time the text items or current position
changes. We calculate store we don't have to calculate
onDraw.
mText1 = getTextToDraw(-2);
mText2 = getTextToDraw(-1);
mText3 = getTextToDraw(0);
mText4 = getTextToDraw(1);
mText5 = getTextToDraw(2);
| private boolean | canScrollDown()
return (mCurrentSelectedPos > 0) || mWrapAround;
| private boolean | canScrollUp()
return ((mCurrentSelectedPos < (mTextList.length - 1)) || mWrapAround);
| private void | drawText(android.graphics.Canvas canvas, java.lang.String text, int y, android.text.TextPaint paint)
int width = (int) paint.measureText(text);
int x = getMeasuredWidth() - width - TEXT_MARGIN_RIGHT;
canvas.drawText(text, x, y, paint);
| public int | getCurrentSelectedPos()
return mCurrentSelectedPos;
| private int | getNewIndex(int offset)
int index = mCurrentSelectedPos + offset;
if (index < 0) {
if (mWrapAround) {
index += mTextList.length;
} else {
return -1;
}
} else if (index >= mTextList.length) {
if (mWrapAround) {
index -= mTextList.length;
} else {
return -1;
}
}
return index;
| private java.lang.String | getTextToDraw(int offset)
int index = getNewIndex(offset);
if (index < 0) {
return "";
}
return mTextList[index];
| protected void | onDraw(android.graphics.Canvas canvas)
/* The bounds of the selector */
final int selectorLeft = 0;
final int selectorTop = mSelectorY;
final int selectorRight = mMeasuredWidth;
final int selectorBottom = mSelectorY + mSelectorHeight;
/* Draw the selector */
mSelector.setBounds(selectorLeft, selectorTop, selectorRight, selectorBottom);
mSelector.draw(canvas);
if (mTextList == null) {
/* We're not setup with values so don't draw anything else */
return;
}
final TextPaint textPaintDark = mTextPaintDark;
if (hasFocus()) {
/* The bounds of the top area where the text should be light */
final int topLeft = 0;
final int topTop = 0;
final int topRight = selectorRight;
final int topBottom = selectorTop + SELECTOR_ARROW_HEIGHT;
/* Assign a bunch of local finals for performance */
final String text1 = mText1;
final String text2 = mText2;
final String text3 = mText3;
final String text4 = mText4;
final String text5 = mText5;
final TextPaint textPaintLight = mTextPaintLight;
/*
* Draw the 1st, 2nd and 3rd item in light only, clip it so it only
* draws in the area above the selector
*/
canvas.save();
canvas.clipRect(topLeft, topTop, topRight, topBottom);
drawText(canvas, text1, TEXT1_Y
+ mTotalAnimatedDistance, textPaintLight);
drawText(canvas, text2, TEXT2_Y
+ mTotalAnimatedDistance, textPaintLight);
drawText(canvas, text3,
TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
canvas.restore();
/*
* Draw the 2nd, 3rd and 4th clipped to the selector bounds in dark
* paint
*/
canvas.save();
canvas.clipRect(selectorLeft, selectorTop + SELECTOR_ARROW_HEIGHT,
selectorRight, selectorBottom - SELECTOR_ARROW_HEIGHT);
drawText(canvas, text2, TEXT2_Y
+ mTotalAnimatedDistance, textPaintDark);
drawText(canvas, text3,
TEXT3_Y + mTotalAnimatedDistance, textPaintDark);
drawText(canvas, text4,
TEXT4_Y + mTotalAnimatedDistance, textPaintDark);
canvas.restore();
/* The bounds of the bottom area where the text should be light */
final int bottomLeft = 0;
final int bottomTop = selectorBottom - SELECTOR_ARROW_HEIGHT;
final int bottomRight = selectorRight;
final int bottomBottom = mMeasuredHeight;
/*
* Draw the 3rd, 4th and 5th in white text, clip it so it only draws
* in the area below the selector.
*/
canvas.save();
canvas.clipRect(bottomLeft, bottomTop, bottomRight, bottomBottom);
drawText(canvas, text3,
TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
drawText(canvas, text4,
TEXT4_Y + mTotalAnimatedDistance, textPaintLight);
drawText(canvas, text5,
TEXT5_Y + mTotalAnimatedDistance, textPaintLight);
canvas.restore();
} else {
drawText(canvas, mText3, TEXT3_Y, textPaintDark);
}
if (mIsAnimationRunning) {
if ((Math.abs(mTotalAnimatedDistance) + mDistanceOfEachAnimation) > SCROLL_DISTANCE) {
mTotalAnimatedDistance = 0;
if (mScrollMode == SCROLL_MODE_UP) {
int oldPos = mCurrentSelectedPos;
int newPos = getNewIndex(1);
if (newPos >= 0) {
mCurrentSelectedPos = newPos;
if (mListener != null) {
mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
}
}
if (newPos < 0 || ((newPos >= mTextList.length - 1) && !mWrapAround)) {
mStopAnimation = true;
}
calculateTextPositions();
} else if (mScrollMode == SCROLL_MODE_DOWN) {
int oldPos = mCurrentSelectedPos;
int newPos = getNewIndex(-1);
if (newPos >= 0) {
mCurrentSelectedPos = newPos;
if (mListener != null) {
mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
}
}
if (newPos < 0 || (newPos == 0 && !mWrapAround)) {
mStopAnimation = true;
}
calculateTextPositions();
}
if (mStopAnimation) {
final int previousScrollMode = mScrollMode;
/* No longer scrolling, we wait till the current animation
* completes then we stop.
*/
mIsAnimationRunning = false;
mStopAnimation = false;
mScrollMode = SCROLL_MODE_NONE;
/* If the current selected item is an empty string
* scroll past it.
*/
if ("".equals(mTextList[mCurrentSelectedPos])) {
mScrollMode = previousScrollMode;
scroll();
mStopAnimation = true;
}
}
} else {
if (mScrollMode == SCROLL_MODE_UP) {
mTotalAnimatedDistance -= mDistanceOfEachAnimation;
} else if (mScrollMode == SCROLL_MODE_DOWN) {
mTotalAnimatedDistance += mDistanceOfEachAnimation;
}
}
if (mDelayBetweenAnimations > 0) {
postInvalidateDelayed(mDelayBetweenAnimations);
} else {
invalidate();
}
}
| protected void | onFocusChanged(boolean gainFocus, int direction, android.graphics.Rect previouslyFocusedRect)
if (gainFocus) {
setBackgroundDrawable(mBackgroundFocused);
mSelector = mSelectorFocused;
} else {
setBackgroundDrawable(null);
mSelector = mSelectorNormal;
mSelectorY = mSelectorDefaultY;
}
| public boolean | onKeyDown(int keyCode, android.view.KeyEvent event)
/* This is a bit confusing, when we get the key event
* DPAD_DOWN we actually roll the spinner up. When the
* key event is DPAD_UP we roll the spinner down.
*/
if ((keyCode == KeyEvent.KEYCODE_DPAD_UP) && canScrollDown()) {
mScrollMode = SCROLL_MODE_DOWN;
scroll();
mStopAnimation = true;
return true;
} else if ((keyCode == KeyEvent.KEYCODE_DPAD_DOWN) && canScrollUp()) {
mScrollMode = SCROLL_MODE_UP;
scroll();
mStopAnimation = true;
return true;
}
return super.onKeyDown(keyCode, event);
| public boolean | onTouchEvent(android.view.MotionEvent event)
final int action = event.getAction();
final int y = (int) event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
requestFocus();
mDownY = y;
isDraggingSelector = (y >= mSelectorY) && (y <= (mSelectorY + mSelector.getIntrinsicHeight()));
break;
case MotionEvent.ACTION_MOVE:
if (isDraggingSelector) {
int top = mSelectorDefaultY + (y - mDownY);
if (top <= mSelectorMinY && canScrollDown()) {
mSelectorY = mSelectorMinY;
mStopAnimation = false;
if (mScrollMode != SCROLL_MODE_DOWN) {
mScrollMode = SCROLL_MODE_DOWN;
scroll();
}
} else if (top >= mSelectorMaxY && canScrollUp()) {
mSelectorY = mSelectorMaxY;
mStopAnimation = false;
if (mScrollMode != SCROLL_MODE_UP) {
mScrollMode = SCROLL_MODE_UP;
scroll();
}
} else {
mSelectorY = top;
mStopAnimation = true;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
default:
mSelectorY = mSelectorDefaultY;
mStopAnimation = true;
invalidate();
break;
}
return true;
| private void | scroll()
if (mIsAnimationRunning) {
return;
}
mTotalAnimatedDistance = 0;
mIsAnimationRunning = true;
invalidate();
| public void | setItems(java.lang.String[] textList)
mTextList = textList;
calculateTextPositions();
| public void | setOnChangeListener(com.android.internal.widget.VerticalTextSpinner$OnChangedListener listener)
mListener = listener;
| public void | setScrollInterval(long interval)
mScrollInterval = interval;
calculateAnimationValues();
| public void | setSelectedPos(int selectedPos)
mCurrentSelectedPos = selectedPos;
calculateTextPositions();
postInvalidate();
| public void | setWrapAround(boolean wrap)
mWrapAround = wrap;
|
|