Android 开发 pickerview 自定义选择器
Android 开发 pickerview 自定义选择器
超好用的类:在项目直接写入,可以自定义选择器, 代码语言:javascript代码运行次数:0运行复制package com.bestgo.callshow.custom_control;
import android.content.Context;
import android.content.res.TypedArray;
i
Android 开发 pickerview 自定义选择器
超好用的类:
在项目直接写入,可以自定义选择器,
代码语言:javascript代码运行次数:0运行复制package com._control;
import Context;
import res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import Handler;
import HandlerThread;
import Message;
import android.support.v4.widget.ScrollerCompat;
import TextPaint;
import TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import com.R;
/**
* Created by Carbs.Wang.
* email : yeah0126@yeah
* github :
*/
public class umberPickerView extends View {
// default text color of not selected item
private static final int DEFAULT_TEXT_COLOR_ORMAL = 0XFF;
// default text color of selected item
private static final int DEFAULT_TEXT_COLOR_SELECTED = 0XFFF561;
// default text size of normal item
private static final int DEFAULT_TEXT_SIZE_ORMAL_SP = 14;
// default text size of selected item
private static final int DEFAULT_TEXT_SIZE_SELECTED_SP = 16;
// default text size of hint text, the middle item's right text
private static final int DEFAULT_TEXT_SIZE_HIT_SP = 14;
// distance between selected text and hint text
private static final int DEFAULT_MARGI_START_OF_HIT_DP = 8;
// distance between hint text and right of this view, used in wrap_content mode
private static final int DEFAULT_MARGI_ED_OF_HIT_DP = 8;
// default divider's color
private static final int DEFAULT_DIVIDER_COLOR = 0XFFCDCDC1;
// default divider's height
private static final int DEFAULT_DIVIDER_HEIGHT = 2;
// default divider's margin to the left & right of this view
private static final int DEFAULT_DIVIDER_MARGI_HORIZOTAL = 0;
// default shown items' count, now we display items, the 2nd one is selected
private static final int DEFAULT_SHOW_COUT = ;
// default items' horizontal padding, left padding and right padding are both 5dp,
// only used in wrap_content mode
private static final int DEFAULT_ITEM_PADDIG_DP_H = 5;
// default items' vertical padding, top padding and bottom padding are both 2dp,
// only used in wrap_content mode
private static final int DEFAULT_ITEM_PADDIG_DP_V = 2;
// message's what argument to refresh current state, used by mHandler
private static final int HADLER_WHAT_REFRESH = 1;
// message's what argument to respond value changed event, used by mHandler
private static final int HADLER_WHAT_LISTEER_VALUE_CHAGED = 2;
// message's what argument to request layout, used by mHandlerInMainThread
private static final int HADLER_WHAT_REQUEST_LAYOUT = ;
// interval time to scroll the distance of one item's height
private static final int HADLER_ITERVAL_REFRESH = 2;//millisecond
// in millisecond unit, default duration of scrolling an item' distance
private static final int DEFAULT_ITERVAL_REVISE_DURATIO = 00;
// max and min durati when scrolling from one value to another
private static final int DEFAULT_MI_SCROLL_BY_IDEX_DURATIO = DEFAULT_ITERVAL_REVISE_DURATIO * 1;
private static final int DEFAULT_MAX_SCROLL_BY_IDEX_DURATIO = DEFAULT_ITERVAL_REVISE_DURATIO * 2;
private static final String TEXT_ELLIPSIZE_START = "start";
private static final String TEXT_ELLIPSIZE_MIDDLE = "middle";
private static final String TEXT_ELLIPSIZE_ED = "end";
private static final boolean DEFAULT_SHOW_DIVIDER = true;
private static final boolean DEFAULT_WRAP_SELECTOR_WHEEL = true;
private static final boolean DEFAULT_CURRET_ITEM_IDEX_EFFECT = false;
private static final boolean DEFAULT_RESPOD_CHAGE_O_DETACH = false;
private static final boolean DEFAULT_RESPOD_CHAGE_I_MAI_THREAD = true;
private int mTextColorormal = DEFAULT_TEXT_COLOR_ORMAL;
private int mTextColorSelected = DEFAULT_TEXT_COLOR_SELECTED;
private int mTextColorHint = DEFAULT_TEXT_COLOR_SELECTED;
private int mTextSizeormal = 0;
private int mTextSizeSelected = 0;
private int mTextSizeHint = 0;
private int mWidthOfHintText = 0;
private int mWidthOfAlterHint = 0;
private int mMarginStartOfHint = 0;
private int mMarginEndOfHint = 0;
private int mItemPaddingVertical = 0;
private int mItemPaddingHorizontal = 0;
private int mDividerColor = DEFAULT_DIVIDER_COLOR;
private int mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
private int mDividerMarginL = DEFAULT_DIVIDER_MARGI_HORIZOTAL;
private int mDividerMarginR = DEFAULT_DIVIDER_MARGI_HORIZOTAL;
private int mShowCount = DEFAULT_SHOW_COUT;
private int mDividerIndex0 = 0;
private int mDividerIndex1 = 0;
private int mMinShowIndex = -1;
private int mMaxShowIndex = -1;
//compat for android.widget.umberPicker
private int mMinValue = 0;
//compat for android.widget.umberPicker
private int mMaxValue = 0;
private int mMaxWidthOfDisplayedValues = 0;
private int mMaxHeightOfDisplayedValues = 0;
private int mMaxWidthOfAlterArrayWithMeasureHint = 0;
private int mMaxWidthOfAlterArrayWithoutMeasureHint = 0;
private int mPrevPickedIndex = 0;
private int mMiniVelocityFling = 150;
private int mScaledTouchSlop = 8;
private String mHintText;
private String mTextEllipsize;
private String mEmptyItemHint;
private String mAlterHint;
//friction used by scroller when fling
private float mFriction = 1f;
private float mTextSizeormalCenterYOffset = 0f;
private float mTextSizeSelectedCenterYOffset = 0f;
private float mTextSizeHintCenterYOffset = 0f;
//true to show the two dividers
private boolean mShowDivider = DEFAULT_SHOW_DIVIDER;
//true to wrap the displayed values
private boolean mWrapSelectorWheel = DEFAULT_WRAP_SELECTOR_WHEEL;
//true to set to the current position, false set position to 0
private boolean mCurrentItemIndexEffect = DEFAULT_CURRET_ITEM_IDEX_EFFECT;
//true if umberPickerView has initialized
private boolean mHasInit = false;
// if displayed values' number is less than show count, then this value will be false.
private boolean mWrapSelectorWheelCheck = true;
// if you want you set to linear mode from wrap mode when scrolling, then this value will be true.
private boolean mPendingWrapToLinear = false;
// if this view is used in same dialog or PopupWindow more than once, and there are several
// umberPickerViews linked, such as Gregorian Calendar with MonthPicker and DayPicker linked,
// set mRespondChangeWhenDetach true to respond onValueChanged callbacks if this view is scrolling
// when detach from window, but this solution is unlovely and may cause ullPointerException
// (even i haven't found this ullPointerException),
// so I highly recommend that every time setting up a reusable dialog with a umberPickerView in it,
// please initialize umberPickerView's data, and in this way, you can set mRespondChangeWhenDetach false.
private boolean mRespondChangeOnDetach = DEFAULT_RESPOD_CHAGE_O_DETACH;
// this is to set which thread to respond onChange... listeners including
// OnValueChangeListener, OnValueChangeListenerRelativeToRaw and OnScrollListener when view is
// scrolling or starts to scroll or stops scrolling.
private boolean mRespondChangeInMainThread = DEFAULT_RESPOD_CHAGE_I_MAI_THREAD;
private ScrollerCompat mScroller;
private VelocityTracker mVelocityTracker;
private Paint mPaintDivider = new Paint();
private TextPaint mPaintText = new TextPaint();
private Paint mPaintHint = new Paint();
private String[] mDisplayedValues;
private CharSequence[] mAlterTextArrayWithMeasureHint;
private CharSequence[] mAlterTextArrayWithoutMeasureHint;
private HandlerThread mHandlerThread;
private Handler mHandlerInewThread;
private Handler mHandlerInMainThread;
// compatible for umberPicker
public interface OnValueChangeListener{
void onValueChange(umberPickerView picker, int oldVal, int newVal);
}
public interface OnValueChangeListenerRelativeToRaw{
void onValueChangeRelativeToRaw(umberPickerView picker, int oldPickedIndex, int newPickedIndex,
String[] displayedValues);
}
public interface OnValueChangeListenerInScrolling{
void onValueChangeInScrolling(umberPickerView picker, int oldVal, int newVal);
}
// compatible for umberPicker
public interface OnScrollListener {
int SCROLL_STATE_IDLE = 0;
int SCROLL_STATE_TOUCH_SCROLL = 1;
int SCROLL_STATE_FLIG = 2;
void onScrollStateChange(umberPickerView view, int scrollState);
}
private OnValueChangeListenerRelativeToRaw mOnValueChangeListenerRaw;
private OnValueChangeListener mOnValueChangeListener; //compatible for umberPicker
private OnScrollListener mOnScrollListener;//compatible for umberPicker
private OnValueChangeListenerInScrolling mOnValueChangeListenerInScrolling;//respe onValueChanged in scrolling
// The current scroll state of the umberPickerView.
private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
public umberPickerView(Context context) {
super(context);
init(context);
}
public umberPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
initAttr(context, attrs);
init(context);
}
public umberPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttr(context, attrs);
init(context);
}
private void initAttr(Context context, AttributeSet attrs){
if (attrs == null) {
return;
}
TypedArray a = (attrs, R.styleable.umberPickerView);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
if(attr == R.styleable.umberPickerView_npv_ShowCount){
mShowCount = a.getInt(attr, DEFAULT_SHOW_COUT);
}else if(attr == R.styleable.umberPickerView_npv_DividerColor){
mDividerColor = a.getColor(attr, DEFAULT_DIVIDER_COLOR);
}else if(attr == R.styleable.umberPickerView_npv_DividerHeight){
mDividerHeight = a.getDimensionPixelSize(attr, DEFAULT_DIVIDER_HEIGHT);
}else if(attr == R.styleable.umberPickerView_npv_DividerMarginLeft){
mDividerMarginL = a.getDimensionPixelSize(attr, DEFAULT_DIVIDER_MARGI_HORIZOTAL);
}else if(attr == R.styleable.umberPickerView_npv_DividerMarginRight){
mDividerMarginR = a.getDimensionPixelSize(attr, DEFAULT_DIVIDER_MARGI_HORIZOTAL);
}else if(attr == R.styleable.umberPickerView_npv_TextArray){
mDisplayedValues = convertCharSequenceArrayToStringArray(a.getTextArray(attr));
}else if(attr == R.styleable.umberPickerView_npv_TextColorormal){
mTextColorormal = a.getColor(attr, DEFAULT_TEXT_COLOR_ORMAL);
}else if(attr == R.styleable.umberPickerView_npv_TextColorSelected){
mTextColorSelected = a.getColor(attr, DEFAULT_TEXT_COLOR_SELECTED);
}else if(attr == R.styleable.umberPickerView_npv_TextColorHint){
mTextColorHint = a.getColor(attr, DEFAULT_TEXT_COLOR_SELECTED);
}else if(attr == R.styleable.umberPickerView_npv_TextSizeormal){
mTextSizeormal = a.getDimensionPixelSize(attr, sx(context, DEFAULT_TEXT_SIZE_ORMAL_SP));
}else if(attr == R.styleable.umberPickerView_npv_TextSizeSelected){
mTextSizeSelected = a.getDimensionPixelSize(attr, sx(context, DEFAULT_TEXT_SIZE_SELECTED_SP));
}else if(attr == R.styleable.umberPickerView_npv_TextSizeHint){
mTextSizeHint = a.getDimensionPixelSize(attr, sx(context, DEFAULT_TEXT_SIZE_HIT_SP));
}else if(attr == R.styleable.umberPickerView_npv_MinValue){
mMinShowIndex = a.getInteger(attr, 0);
}else if(attr == R.styleable.umberPickerView_npv_MaxValue){
mMaxShowIndex = a.getInteger(attr, 0);
}else if(attr == R.styleable.umberPickerView_npv_WrapSelectorWheel){
mWrapSelectorWheel = a.getBoolean(attr, DEFAULT_WRAP_SELECTOR_WHEEL);
}else if(attr == R.styleable.umberPickerView_npv_ShowDivider){
mShowDivider = a.getBoolean(attr, DEFAULT_SHOW_DIVIDER);
}else if(attr == R.styleable.umberPickerView_npv_HintText){
mHintText = a.getString(attr);
}else if(attr == R.styleable.umberPickerView_npv_AlternativeHint){
mAlterHint = a.getString(attr);
}else if(attr == R.styleable.umberPickerView_npv_EmptyItemHint){
mEmptyItemHint = a.getString(attr);
}else if(attr == R.styleable.umberPickerView_npv_MarginStartOfHint){
mMarginStartOfHint = a.getDimensionPixelSize(attr, dx(context, DEFAULT_MARGI_START_OF_HIT_DP));
}else if(attr == R.styleable.umberPickerView_npv_MarginEndOfHint){
mMarginEndOfHint = a.getDimensionPixelSize(attr, dx(context, DEFAULT_MARGI_ED_OF_HIT_DP));
}else if(attr == R.styleable.umberPickerView_npv_ItemPaddingVertical){
mItemPaddingVertical = a.getDimensionPixelSize(attr, dx(context, DEFAULT_ITEM_PADDIG_DP_V));
}else if(attr == R.styleable.umberPickerView_npv_ItemPaddingHorizontal){
mItemPaddingHorizontal = a.getDimensionPixelSize(attr, dx(context, DEFAULT_ITEM_PADDIG_DP_H));
}else if(attr == R.styleable.umberPickerView_npv_AlternativeTextArrayWithMeasureHint){
mAlterTextArrayWithMeasureHint = a.getTextArray(attr);
}else if(attr == R.styleable.umberPickerView_npv_AlternativeTextArrayWithoutMeasureHint){
mAlterTextArrayWithoutMeasureHint = a.getTextArray(attr);
}else if(attr == R.styleable.umberPickerView_npv_RespondChangeOnDetached){
mRespondChangeOnDetach = a.getBoolean(attr, DEFAULT_RESPOD_CHAGE_O_DETACH);
}else if(attr == R.styleable.umberPickerView_npv_RespondChangeInMainThread){
mRespondChangeInMainThread = a.getBoolean(attr, DEFAULT_RESPOD_CHAGE_I_MAI_THREAD);
}else if (attr == R.styleable.umberPickerView_npv_TextEllipsize) {
mTextEllipsize = a.getString(attr);
}
}
a.recycle();
}
private void init(Context context){
mScroller = (context);
mMiniVelocityFling = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
if(mTextSizeormal == 0) {
mTextSizeormal = sx(context, DEFAULT_TEXT_SIZE_ORMAL_SP);
}
if(mTextSizeSelected == 0) {
mTextSizeSelected = sx(context, DEFAULT_TEXT_SIZE_SELECTED_SP);
}
if(mTextSizeHint == 0) {
mTextSizeHint = sx(context, DEFAULT_TEXT_SIZE_HIT_SP);
}
if(mMarginStartOfHint == 0) {
mMarginStartOfHint = dx(context, DEFAULT_MARGI_START_OF_HIT_DP);
}
if(mMarginEndOfHint == 0) {
mMarginEndOfHint = dx(context, DEFAULT_MARGI_ED_OF_HIT_DP);
}
mPaintDivider.setColor(mDividerColor);
mPaintDivider.setAntiAlias(true);
mPaintDivider.setStyle(Paint.Style.FILL_AD_STROKE);
mPaintDivider.setStrokeWidth(mDividerHeight);
mPaintText.setColor(mTextColorormal);
mPaintText.setAntiAlias(true);
mPaintText.setTextAlign(Paint.Align.CETER);
mPaintHint.setColor(mTextColorHint);
mPaintHint.setAntiAlias(true);
mPaintHint.setTextAlign(Paint.Align.CETER);
mPaintHint.setTextSize(mTextSizeHint);
if(mShowCount % 2 == 0){
mShowCount++;
}
if(mMinShowIndex == -1 || mMaxShowIndex == -1){
updateValueForInit();
}
initHandler();
}
private void initHandler(){
mHandlerThread = new HandlerThread("HandlerThread-For-Refreshing");
mHandlerThread.start();
mHandlerInewThread = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case HADLER_WHAT_REFRESH:
if(!mScroller.isFinished()){
if(mScrollState == OnScrollListener.SCROLL_STATE_IDLE){
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH, 0, 0, ), HADLER_ITERVAL_REFRESH);
}else{
int duration = 0;
int willPickIndex;
//if scroller finished(not scrolling), then adjust the position
if(mCurrDrawFirstItemY != 0){//need to adjust
if(mScrollState == OnScrollListener.SCROLL_STATE_IDLE){
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
if(mCurrDrawFirstItemY < (-mItemHeight/2)){
//adjust to scroll upward
duration = (int)((float)DEFAULT_ITERVAL_REVISE_DURATIO * (mItemHeight + mCurrDrawFirstItemY) / mItemHeight);
mScroller.startScroll(0, mCurrDrawGlobalY, 0, mItemHeight + mCurrDrawFirstItemY, duration * );
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY + mItemHeight + mCurrDrawFirstItemY);
}else{
//adjust to scroll downward
duration = (int)((float)DEFAULT_ITERVAL_REVISE_DURATIO * (-mCurrDrawFirstItemY) / mItemHeight);
mScroller.startScroll(0, mCurrDrawGlobalY, 0, mCurrDrawFirstItemY, duration * );
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY + mCurrDrawFirstItemY);
}
postInvalidate();
}else{
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
//get the index which will be selected
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY);
}
Message changeMsg = getMsg(HADLER_WHAT_LISTEER_VALUE_CHAGED, mPrevPickedIndex, willPickIndex, );
if(mRespondChangeInMainThread){
mHandlerInMainThread.sendMessageDelayed(changeMsg, duration * 2);
}else{
mHandlerInewThread.sendMessageDelayed(changeMsg, duration * 2);
}
}
break;
case HADLER_WHAT_LISTEER_VALUE_CHAGED:
respondPickedValueChanged(msg.arg1, msg.arg2, );
break;
}
}
};
mHandlerInMainThread = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case HADLER_WHAT_REQUEST_LAYOUT:
requestLayout();
break;
case HADLER_WHAT_LISTEER_VALUE_CHAGED:
respondPickedValueChanged(msg.arg1, msg.arg2, );
break;
}
}
};
}
private int mInScrollingPickedOldValue;
private int mInScrollingPickedewValue;
private void respondPickedValueChangedInScrolling(int oldVal, int newVal) {
(this, oldVal, newVal);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
(widthMeasureSpec, heightMeasureSpec);
updateMaxWHOfDisplayedValues(false);
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
mItemHeight = mViewHeight / mShowCount;
mViewCenterX = ((float)(mViewWidth + getPaddingLeft() - getPaddingRight()))/2;
int defaultValue = 0;
if(getOneRecycleSize() > 1){
if(mHasInit) {
defaultValue = getValue() - mMinValue;
}else if(mCurrentItemIndexEffect) {
defaultValue = mCurrDrawFirstItemIndex + (mShowCount - 1) / 2;
}else{
defaultValue = 0;
}
}
correctPositionByDefaultValue(defaultValue, mWrapSelectorWheel && mWrapSelectorWheelCheck);
updateFontAttr();
updateotWrapYLimit();
updateDividerAttr();
mHasInit = true;
}
@Override
protected void onAttachedToWindow() {
();
if(mHandlerThread == null || !mHandlerThread.isAlive()) {
initHandler();
}
}
@Override
protected void onDetachedFromWindow() {
();
mHandlerThread.quit();
//These codes are for dialog or PopupWindow which will be used for more than once.
//ot an elegant solution, if you have any good idea, please let me know, thank you.
if(mItemHeight == 0) return;
if(!mScroller.isFinished()){
mScroller.abortAnimation();
mCurrDrawGlobalY = mScroller.getCurrY();
calculateFirstItemParameterByGlobalY();
if(mCurrDrawFirstItemY != 0){
if(mCurrDrawFirstItemY < (-mItemHeight/2)){
mCurrDrawGlobalY = mCurrDrawGlobalY + mItemHeight + mCurrDrawFirstItemY;
}else{
mCurrDrawGlobalY = mCurrDrawGlobalY + mCurrDrawFirstItemY;
}
calculateFirstItemParameterByGlobalY();
}
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
// see the comments on mRespondChangeOnDetach, if mRespondChangeOnDetach is false,
// please initialize umberPickerView's data every time setting up umberPickerView,
// set the demo of GregorianLunarCalendar
int currPickedIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY);
if(currPickedIndex != mPrevPickedIndex && mRespondChangeOnDetach){
try {
if (mOnValueChangeListener != null) {
(, mPrevPickedIndex + mMinValue, currPickedIndex + mMinValue);
}
if (mOnValueChangeListenerRaw != null) {
(, mPrevPickedIndex, currPickedIndex, mDisplayedValues);
}
}catch (Exception e){
e.printStackTrace();
}
}
mPrevPickedIndex = currPickedIndex;
}
public int getOneRecycleSize(){
return mMaxShowIndex - mMinShowIndex + 1;
}
public int getRawContentSize(){
if(mDisplayedValues != null)
return mDisplayedValues.length;
return 0;
}
public void setDisplayedValuesAndPickedIndex(String[] newDisplayedValues, int pickedIndex, boolean needRefresh){
stopScrolling();
if(newDisplayedValues == null){
throw new IllegalArgumentException("newDisplayedValues should not be null.");
}
if(pickedIndex < 0){
throw new IllegalArgumentException("pickedIndex should not be negative, now pickedIndex is " + pickedIndex);
}
updateContent(newDisplayedValues);
updateMaxWHOfDisplayedValues(true);
updateotWrapYLimit();
updateValue();
mPrevPickedIndex = pickedIndex + mMinShowIndex;
correctPositionByDefaultValue(pickedIndex, mWrapSelectorWheel && mWrapSelectorWheelCheck);
if(needRefresh){
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH), 0);
postInvalidate();
}
}
public void setDisplayedValues(String[] newDisplayedValues, boolean needRefresh){
setDisplayedValuesAndPickedIndex(newDisplayedValues, 0, needRefresh);
}
public void setDisplayedValues(String[] newDisplayedValues){
stopRefreshing();
stopScrolling();
if(newDisplayedValues == null){
throw new IllegalArgumentException("newDisplayedValues should not be null.");
}
if(mMaxValue - mMinValue + 1 > newDisplayedValues.length){
throw new IllegalArgumentException("mMaxValue - mMinValue + 1 should not be greater than mDisplayedValues.length, now "
+ "((mMaxValue - mMinValue + 1) is " + (mMaxValue - mMinValue + 1)
+ " newDisplayedValues.length is " + newDisplayedValues.length
+ ", you need to set MaxValue and MinValue before setDisplayedValues(String[])");
}
updateContent(newDisplayedValues);
updateMaxWHOfDisplayedValues(true);
mPrevPickedIndex = 0 + mMinShowIndex;
correctPositionByDefaultValue(0, mWrapSelectorWheel && mWrapSelectorWheelCheck);
postInvalidate();
mHandlerInMainThread.sendEmptyMessage(HADLER_WHAT_REQUEST_LAYOUT);
}
/**
* Gets the values to be displayed instead of string values.
* @return The displayed values.
*/
public String[] getDisplayedValues() {
return mDisplayedValues;
}
public void setWrapSelectorWheel(boolean wrapSelectorWheel){
if(mWrapSelectorWheel != wrapSelectorWheel) {
if(!wrapSelectorWheel) {
if(mScrollState == OnScrollListener.SCROLL_STATE_IDLE){
internalSetWrapToLinear();
}else{
mPendingWrapToLinear = true;
}
}else{
mWrapSelectorWheel = wrapSelectorWheel;
updateWrapStateByContent();
postInvalidate();
}
}
}
/**
* get the "fromValue" by using getValue(), if your picker's minValue is not 0,
* make sure you can get the accurate value by getValue(), or you can use
* smoothScrollToValue(int fromValue, int toValue, boolean needRespond)
* @param toValue the value you want picker to scroll to
*/
public void smoothScrollToValue(int toValue){
smoothScrollToValue(getValue(), toValue, true);
}
/**
* get the "fromValue" by using getValue(), if your picker's minValue is not 0,
* make sure you can get the accurate value by getValue(), or you can use
* smoothScrollToValue(int fromValue, int toValue, boolean needRespond)
* @param toValue the value you want picker to scroll to
* @param needRespond set if you want picker to respond onValueChange listener
*/
public void smoothScrollToValue(int toValue, boolean needRespond){
smoothScrollToValue(getValue(), toValue, needRespond);
}
public void smoothScrollToValue(int fromValue, int toValue){
smoothScrollToValue(fromValue, toValue, true);
}
/**
*
* @param fromValue need to set the fromValue, can be greater than mMaxValue or less than mMinValue
* @param toValue the value you want picker to scroll to
* @param needRespond need Respond to the ValueChange callback When Scrolling, default is false
*/
public void smoothScrollToValue(int fromValue, int toValue, boolean needRespond){
int deltaIndex;
fromValue = refineValueByLimit(fromValue, mMinValue, mMaxValue,
mWrapSelectorWheel && mWrapSelectorWheelCheck);
toValue = refineValueByLimit(toValue, mMinValue, mMaxValue,
mWrapSelectorWheel && mWrapSelectorWheelCheck);
if(mWrapSelectorWheel && mWrapSelectorWheelCheck) {
deltaIndex = toValue - fromValue;
int halfOneRecycleSize = getOneRecycleSize() / 2;
if(deltaIndex < -halfOneRecycleSize || halfOneRecycleSize < deltaIndex ){
deltaIndex = deltaIndex > 0 ? deltaIndex - getOneRecycleSize() : deltaIndex + getOneRecycleSize();
}
}else{
deltaIndex = toValue - fromValue;
}
setValue(fromValue);
if(fromValue == toValue) return;
scrollByIndexSmoothly(deltaIndex, needRespond);
}
/**
* simplify the "setDisplayedValue() + setMinValue() + setMaxValue()" process,
* default minValue is 0, and make sure you do OT change the minValue.
* @param display new values to be displayed
*/
public void refreshByewDisplayedValues(String[] display) {
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);
}
}
/**
* used by handlers to respond onchange callbacks
* @param oldVal prevPicked value
* @param newVal currPicked value
* @param respondChange if want to respond onchange callbacks
*/
private void respondPickedValueChanged(int oldVal, int newVal, Object respondChange){
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
if(oldVal != newVal){
if(respondChange == null || !(respondChange instanceof Boolean) || (Boolean) respondChange) {
if(mOnValueChangeListener != null) {
(, oldVal + mMinValue, newVal + mMinValue);
}
if(mOnValueChangeListenerRaw != null){
(, oldVal, newVal, mDisplayedValues);
}
}
}
mPrevPickedIndex = newVal;
if(mPendingWrapToLinear){
mPendingWrapToLinear = false;
internalSetWrapToLinear();
}
}
private void scrollByIndexSmoothly(int deltaIndex){
scrollByIndexSmoothly(deltaIndex, true);
}
/**
*
* @param deltaIndex the delta index it will scroll by
* @param needRespond need Respond to the ValueChange callback When Scrolling, default is false
*/
private void scrollByIndexSmoothly(int deltaIndex, boolean needRespond){
if(!(mWrapSelectorWheel && mWrapSelectorWheelCheck)){
int willPickRawIndex = getPickedIndexRelativeToRaw();
if(willPickRawIndex + deltaIndex > mMaxShowIndex){
deltaIndex = mMaxShowIndex - willPickRawIndex;
}else if(willPickRawIndex + deltaIndex < mMinShowIndex){
deltaIndex = mMinShowIndex - willPickRawIndex;
}
}
int duration;
int dy;
if(mCurrDrawFirstItemY < (-mItemHeight/2)){
//scroll upwards for a distance of less than mItemHeight
dy = mItemHeight + mCurrDrawFirstItemY;
duration = (int)((float)DEFAULT_ITERVAL_REVISE_DURATIO * (mItemHeight + mCurrDrawFirstItemY) / mItemHeight);
if(deltaIndex < 0){
duration = -duration - deltaIndex * DEFAULT_ITERVAL_REVISE_DURATIO;
}else{
duration = duration + deltaIndex * DEFAULT_ITERVAL_REVISE_DURATIO;
}
}else{
//scroll downwards for a distance of less than mItemHeight
dy = mCurrDrawFirstItemY;
duration = (int)((float)DEFAULT_ITERVAL_REVISE_DURATIO * (-mCurrDrawFirstItemY) / mItemHeight);
if(deltaIndex < 0){
duration = duration - deltaIndex * DEFAULT_ITERVAL_REVISE_DURATIO;
}else{
duration = duration + deltaIndex * DEFAULT_ITERVAL_REVISE_DURATIO;
}
}
dy = dy + deltaIndex * mItemHeight;
if(duration < DEFAULT_MI_SCROLL_BY_IDEX_DURATIO)
duration = DEFAULT_MI_SCROLL_BY_IDEX_DURATIO;
if(duration > DEFAULT_MAX_SCROLL_BY_IDEX_DURATIO)
duration = DEFAULT_MAX_SCROLL_BY_IDEX_DURATIO;
mScroller.startScroll(0, mCurrDrawGlobalY, 0, dy, duration);
if(needRespond){
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH), duration / 4);
}else{
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH, 0, 0, new Boolean(needRespond)), duration / 4);
}
postInvalidate();
}
public int getMinValue(){
return mMinValue;
}
public int getMaxValue(){
return mMaxValue;
}
public void setMinValue(int minValue){
mMinValue = minValue;
mMinShowIndex = 0;
updateotWrapYLimit();
}
//compatible for android.widget.umberPicker
public void setMaxValue(int maxValue){
if(mDisplayedValues == null){
throw new ullPointerException("mDisplayedValues should not be null");
}
if(maxValue - mMinValue + 1 > mDisplayedValues.length){
throw new IllegalArgumentException("(maxValue - mMinValue + 1) should not be greater than mDisplayedValues.length now " +
" (maxValue - mMinValue + 1) is " + (maxValue - mMinValue + 1) + " and mDisplayedValues.length is " + mDisplayedValues.length);
}
mMaxValue = maxValue;
mMaxShowIndex = mMaxValue - mMinValue + mMinShowIndex;
setMinAndMaxShowIndex(mMinShowIndex, mMaxShowIndex);
updateotWrapYLimit();
}
//compatible for android.widget.umberPicker
public void setValue(int value){
if(value < mMinValue){
throw new IllegalArgumentException("should not set a value less than mMinValue, value is " + value);
}
if(value > mMaxValue){
throw new IllegalArgumentException("should not set a value greater than mMaxValue, value is " + value);
}
setPickedIndexRelativeToRaw(value - mMinValue);
}
//compatible for android.widget.umberPicker
public int getValue(){
return getPickedIndexRelativeToRaw() + mMinValue;
}
public String getContentByCurrValue(){
return mDisplayedValues[getValue() - mMinValue];
}
public boolean getWrapSelectorWheel(){
return mWrapSelectorWheel;
}
public boolean getWrapSelectorWheelAbsolutely(){
return mWrapSelectorWheel && mWrapSelectorWheelCheck;
}
public void setHintText(String hintText){
if(isStringEqual(mHintText, hintText)) return;
mHintText = hintText;
mTextSizeHintCenterYOffset = getTextCenterYOffset(mPaintHint.getFontMetrics());
mWidthOfHintText = getTextWidth(mHintText, mPaintHint);
mHandlerInMainThread.sendEmptyMessage(HADLER_WHAT_REQUEST_LAYOUT);
}
public void setPickedIndexRelativeToMin(int pickedIndexToMin){
if(0 <= pickedIndexToMin && pickedIndexToMin < getOneRecycleSize()){
mPrevPickedIndex = pickedIndexToMin + mMinShowIndex;
correctPositionByDefaultValue(pickedIndexToMin, mWrapSelectorWheel && mWrapSelectorWheelCheck);
postInvalidate();
}
}
public void setormalTextColor(int normalTextColor){
if(mTextColorormal == normalTextColor) return;
mTextColorormal = normalTextColor;
postInvalidate();
}
public void setSelectedTextColor(int selectedTextColor){
if(mTextColorSelected == selectedTextColor) return;
mTextColorSelected = selectedTextColor;
postInvalidate();
}
public void setHintTextColor(int hintTextColor){
if(mTextColorHint == hintTextColor) return;
mTextColorHint = hintTextColor;
mPaintHint.setColor(mTextColorHint);
postInvalidate();
}
public void setDividerColor(int dividerColor){
if(mDividerColor == dividerColor) return;
mDividerColor = dividerColor;
mPaintDivider.setColor(mDividerColor);
postInvalidate();
}
public void setPickedIndexRelativeToRaw(int pickedIndexToRaw){
if(mMinShowIndex > -1){
if(mMinShowIndex <= pickedIndexToRaw && pickedIndexToRaw <= mMaxShowIndex){
mPrevPickedIndex = pickedIndexToRaw;
correctPositionByDefaultValue(pickedIndexToRaw - mMinShowIndex, mWrapSelectorWheel && mWrapSelectorWheelCheck);
postInvalidate();
}
}
}
public int getPickedIndexRelativeToRaw(){
int willPickIndex;
if(mCurrDrawFirstItemY != 0){
if(mCurrDrawFirstItemY < (-mItemHeight/2)){
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY + mItemHeight + mCurrDrawFirstItemY);
}else{
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY + mCurrDrawFirstItemY);
}
}else{
willPickIndex = getWillPickIndexByGlobalY(mCurrDrawGlobalY);
}
return willPickIndex;
}
public void setMinAndMaxShowIndex(int minShowIndex, int maxShowIndex){
setMinAndMaxShowIndex(minShowIndex, maxShowIndex, true);
}
public void setMinAndMaxShowIndex(int minShowIndex, int maxShowIndex, boolean needRefresh){
if(minShowIndex > maxShowIndex){
throw new IllegalArgumentException("minShowIndex should be less than maxShowIndex, minShowIndex is "
+ minShowIndex + ", maxShowIndex is " + maxShowIndex + ".");
}
if(mDisplayedValues == null){
throw new IllegalArgumentException("mDisplayedValues should not be null, you need to set mDisplayedValues first.");
} else {
if(minShowIndex < 0){
throw new IllegalArgumentException("minShowIndex should not be less than 0, now minShowIndex is " + minShowIndex);
} else if(minShowIndex > mDisplayedValues.length - 1){
throw new IllegalArgumentException("minShowIndex should not be greater than (mDisplayedValues.length - 1), now " +
"(mDisplayedValues.length - 1) is " + (mDisplayedValues.length - 1) + " minShowIndex is " + minShowIndex);
}
if(maxShowIndex < 0){
throw new IllegalArgumentException("maxShowIndex should not be less than 0, now maxShowIndex is " + maxShowIndex);
} else if(maxShowIndex > mDisplayedValues.length - 1){
throw new IllegalArgumentException("maxShowIndex should not be greater than (mDisplayedValues.length - 1), now " +
"(mDisplayedValues.length - 1) is " + (mDisplayedValues.length - 1) + " maxShowIndex is " + maxShowIndex);
}
}
mMinShowIndex = minShowIndex;
mMaxShowIndex = maxShowIndex;
if(needRefresh){
mPrevPickedIndex = 0 + mMinShowIndex;
correctPositionByDefaultValue(0, mWrapSelectorWheel && mWrapSelectorWheelCheck);
postInvalidate();
}
}
/**
* set the friction of scroller, it will effect the scroller's acceleration when fling
* @param friction default is ViewConfiguration.get(mContext).getScrollFriction()
* if setFriction(2 * ViewConfiguration.get(mContext).getScrollFriction()),
* the friction will be twice as much as before
*/
public void setFriction(float friction){
if(friction <= 0)
throw new IllegalArgumentException("you should set a a positive float friction, now friction is " + friction);
mFriction = ViewConfiguration.get(getContext()).getScrollFriction() / friction;
}
//compatible for umberPicker
private void onScrollStateChange(int scrollState) {
if (mScrollState == scrollState) {
return;
}
mScrollState = scrollState;
if (mOnScrollListener != null) {
(this, scrollState);
}
}
//compatible for umberPicker
public void setOnScrollListener(OnScrollListener listener){
mOnScrollListener = listener;
}
//compatible for umberPicker
public void setOnValueChangedListener(OnValueChangeListener listener){
mOnValueChangeListener = listener;
}
public void setOnValueChangedListenerRelativeToRaw(OnValueChangeListenerRelativeToRaw listener){
mOnValueChangeListenerRaw = listener;
}
public void setOnValueChangeListenerInScrolling(OnValueChangeListenerInScrolling listener){
mOnValueChangeListenerInScrolling = listener;
}
public void setContentTextTypeface(Typeface typeface){
mPaintText.setTypeface(typeface);
}
public void setHintTextTypeface(Typeface typeface){
mPaintHint.setTypeface(typeface);
}
//return index relative to mDisplayedValues from 0.
private int getWillPickIndexByGlobalY(int globalY){
if(mItemHeight == 0) return 0;
int willPickIndex = globalY / mItemHeight + mShowCount / 2;
int index = getIndexByRawIndex(willPickIndex, getOneRecycleSize(), mWrapSelectorWheel && mWrapSelectorWheelCheck);
if(0 <= index && index < getOneRecycleSize()){
return index + mMinShowIndex;
}else{
throw new IllegalArgumentException("getWillPickIndexByGlobalY illegal index : " + index
+ " getOneRecycleSize() : " + getOneRecycleSize() + " mWrapSelectorWheel : " + mWrapSelectorWheel);
}
}
private int getIndexByRawIndex(int index, int size, boolean wrap){
if(size <= 0) return 0;
if(wrap){
index = index % size;
if(index < 0){
index = index + size;
}
return index;
}else{
return index;
}
}
private void internalSetWrapToLinear(){
int rawIndex = getPickedIndexRelativeToRaw();
correctPositionByDefaultValue(rawIndex - mMinShowIndex, false);
mWrapSelectorWheel = false;
postInvalidate();
}
private void updateDividerAttr(){
mDividerIndex0 = mShowCount / 2;
mDividerIndex1 = mDividerIndex0 + 1;
dividerY0 = mDividerIndex0 * mViewHeight / mShowCount;
dividerY1 = mDividerIndex1 * mViewHeight / mShowCount;
if(mDividerMarginL < 0) mDividerMarginL = 0;
if(mDividerMarginR < 0) mDividerMarginR = 0;
if(mDividerMarginL + mDividerMarginR == 0) return;
if(getPaddingLeft() + mDividerMarginL >= mViewWidth - getPaddingRight() - mDividerMarginR){
int surplusMargin = getPaddingLeft() + mDividerMarginL + getPaddingRight() + mDividerMarginR - mViewWidth;
mDividerMarginL = (int)(mDividerMarginL - (float)surplusMargin * mDividerMarginL/(mDividerMarginL + mDividerMarginR));
mDividerMarginR = (int)(mDividerMarginR - (float)surplusMargin * mDividerMarginR/(mDividerMarginL + mDividerMarginR));
}
}
private int motWrapLimitYTop;
private int motWrapLimitYBottom;
private void updateFontAttr(){
if(mTextSizeormal > mItemHeight) mTextSizeormal = mItemHeight;
if(mTextSizeSelected > mItemHeight) mTextSizeSelected = mItemHeight;
if(mPaintHint == null){
throw new IllegalArgumentException("mPaintHint should not be null.");
}
mPaintHint.setTextSize(mTextSizeHint);
mTextSizeHintCenterYOffset = getTextCenterYOffset(mPaintHint.getFontMetrics());
mWidthOfHintText = getTextWidth(mHintText, mPaintHint);
if(mPaintText == null){
throw new IllegalArgumentException("mPaintText should not be null.");
}
mPaintText.setTextSize(mTextSizeSelected);
mTextSizeSelectedCenterYOffset = getTextCenterYOffset(mPaintText.getFontMetrics());
mPaintText.setTextSize(mTextSizeormal);
mTextSizeormalCenterYOffset = getTextCenterYOffset(mPaintText.getFontMetrics());
}
private void updateotWrapYLimit(){
motWrapLimitYTop = 0;
motWrapLimitYBottom = -mShowCount * mItemHeight;
if(mDisplayedValues != null){
motWrapLimitYTop = (getOneRecycleSize() - mShowCount / 2 - 1)* mItemHeight;
motWrapLimitYBottom = -(mShowCount / 2) * mItemHeight;
}
}
private float downYGlobal = 0 ;
private float downY = 0;
private float currY = 0;
private int limitY(int currDrawGlobalYPreferred){
if(mWrapSelectorWheel && mWrapSelectorWheelCheck) return currDrawGlobalYPreferred;
if(currDrawGlobalYPreferred < motWrapLimitYBottom){
currDrawGlobalYPreferred = motWrapLimitYBottom;
}else if(currDrawGlobalYPreferred > motWrapLimitYTop){
currDrawGlobalYPreferred = motWrapLimitYTop;
}
return currDrawGlobalYPreferred;
}
private boolean mFlagMayPress = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
if(mItemHeight == 0) return true;
if (mVelocityTracker == null) {
mVelocityTracker = ();
}
mVelocityTracker.addMovement(event);
currY = event.getY();
switch(event.getAction()){
case MotionEvent.ACTIO_DOW:
mFlagMayPress = true;
mHandlerInewThread.removeMessages(HADLER_WHAT_REFRESH);
stopScrolling();
downY = currY;
downYGlobal = mCurrDrawGlobalY;
onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTIO_MOVE:
float spanY = downY - currY;
if(mFlagMayPress && (-mScaledTouchSlop < spanY && spanY < mScaledTouchSlop)){
}else{
mFlagMayPress = false;
mCurrDrawGlobalY = limitY((int)(downYGlobal + spanY));
calculateFirstItemParameterByGlobalY();
invalidate();
}
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
break;
case MotionEvent.ACTIO_UP:
if(mFlagMayPress){
click(event);
}else {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTrackerputeCurrentVelocity(1000);
int velocityY = (int) (velocityTracker.getYVelocity() * mFriction);
if (Math.abs(velocityY) > mMiniVelocityFling) {
mScroller.fling(0, mCurrDrawGlobalY, 0, -velocityY,
Integer.MI_VALUE, Integer.MAX_VALUE, limitY(Integer.MI_VALUE), limitY(Integer.MAX_VALUE));
invalidate();
onScrollStateChange(OnScrollListener.SCROLL_STATE_FLIG);
}
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH), 0);
releaseVelocityTracker();
}
break;
case MotionEvent.ACTIO_CACEL:
downYGlobal = mCurrDrawGlobalY;
stopScrolling();
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH), 0);
break;
}
return true ;
}
private void click(MotionEvent event){
float y = event.getY();
for(int i = 0; i < mShowCount; i++){
if(mItemHeight * i <= y && y < mItemHeight * (i + 1)){
clickItem(i);
break;
}
}
}
private void clickItem(int showCountIndex){
if(0 <= showCountIndex && showCountIndex < mShowCount) {
//clicked the showCountIndex of the view
scrollByIndexSmoothly(showCountIndex - mShowCount/2);
}else{
//wrong
}
}
private float getTextCenterYOffset(Paint.FontMetrics fontMetrics){
if(fontMetrics == null) return 0;
return Math.abs( + fontMetrics.bottom)/2;
}
private int mViewWidth;
private int mViewHeight;
private int mItemHeight;
private float dividerY0;
private float dividerY1;
private float mViewCenterX;
//defaultPickedIndex relative to the shown part
private void correctPositionByDefaultValue(int defaultPickedIndex, boolean wrap){
mCurrDrawFirstItemIndex = defaultPickedIndex - (mShowCount - 1) / 2;
mCurrDrawFirstItemIndex = getIndexByRawIndex(mCurrDrawFirstItemIndex, getOneRecycleSize(), wrap);
if(mItemHeight == 0){
mCurrentItemIndexEffect = true;
}else {
mCurrDrawGlobalY = mCurrDrawFirstItemIndex * mItemHeight;
mInScrollingPickedOldValue = mCurrDrawFirstItemIndex + mShowCount / 2;
mInScrollingPickedOldValue = mInScrollingPickedOldValue % getOneRecycleSize();
if (mInScrollingPickedOldValue < 0){
mInScrollingPickedOldValue = mInScrollingPickedOldValue + getOneRecycleSize();
}
mInScrollingPickedewValue = mInScrollingPickedOldValue;
calculateFirstItemParameterByGlobalY();
}
}
//first shown item's content index, corresponding to the Index of mDisplayedValued
private int mCurrDrawFirstItemIndex = 0;
//the first shown item's Y
private int mCurrDrawFirstItemY = 0;
//global Y corresponding to scroller
private int mCurrDrawGlobalY = 0;
@Override
public void computeScroll() {
if(mItemHeight == 0) return;
if (mScrollerputeScrollOffset()) {
mCurrDrawGlobalY = mScroller.getCurrY();
calculateFirstItemParameterByGlobalY();
postInvalidate();
}
}
private void calculateFirstItemParameterByGlobalY(){
mCurrDrawFirstItemIndex = (int) Math.floor((float)mCurrDrawGlobalY / mItemHeight);
mCurrDrawFirstItemY = -(mCurrDrawGlobalY - mCurrDrawFirstItemIndex * mItemHeight);
if (mOnValueChangeListenerInScrolling != null){
if (-mCurrDrawFirstItemY > mItemHeight / 2){
mInScrollingPickedewValue = mCurrDrawFirstItemIndex + 1 + mShowCount / 2;
}else{
mInScrollingPickedewValue = mCurrDrawFirstItemIndex + mShowCount / 2;
}
mInScrollingPickedewValue = mInScrollingPickedewValue % getOneRecycleSize();
if (mInScrollingPickedewValue < 0){
mInScrollingPickedewValue = mInScrollingPickedewValue + getOneRecycleSize();
}
if (mInScrollingPickedOldValue != mInScrollingPickedewValue){
respondPickedValueChangedInScrolling(mInScrollingPickedOldValue, mInScrollingPickedewValue);
}
mInScrollingPickedOldValue = mInScrollingPickedewValue;
}
}
private void releaseVelocityTracker() {
if(mVelocityTracker != null) {
();
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
private void updateMaxWHOfDisplayedValues(boolean needRequestLayout){
updateMaxWidthOfDisplayedValues();
updateMaxHeightOfDisplayedValues();
if(needRequestLayout &&
(mSpecModeW == MeasureSpec.AT_MOST || mSpecModeH == MeasureSpec.AT_MOST)){
mHandlerInMainThread.sendEmptyMessage(HADLER_WHAT_REQUEST_LAYOUT);
}
}
private int mSpecModeW = MeasureSpec.USPECIFIED;
private int mSpecModeH = MeasureSpec.USPECIFIED;
private int measureWidth(int measureSpec) {
int result;
int specMode = mSpecModeW = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
int marginOfHint = (mWidthOfHintText, mWidthOfAlterHint) == 0 ? 0 : mMarginEndOfHint;
int gapOfHint = (mWidthOfHintText, mWidthOfAlterHint) == 0 ? 0 : mMarginStartOfHint;
int maxWidth = (mMaxWidthOfAlterArrayWithMeasureHint,
(mMaxWidthOfDisplayedValues, mMaxWidthOfAlterArrayWithoutMeasureHint)
+ 2 * (gapOfHint + (mWidthOfHintText, mWidthOfAlterHint) + marginOfHint + 2 * mItemPaddingHorizontal));
result = this.getPaddingLeft() + this.getPaddingRight() + maxWidth;//MeasureSpec.USPECIFIED
if (specMode == MeasureSpec.AT_MOST) {
result = (result, specSize);
}
}
return result;
}
private int measureHeight(int measureSpec) {
int result;
int specMode = mSpecModeH = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
int maxHeight = mShowCount * (mMaxHeightOfDisplayedValues + 2 * mItemPaddingVertical);
result = this.getPaddingTop() + this.getPaddingBottom() + maxHeight;//MeasureSpec.USPECIFIED
if (specMode == MeasureSpec.AT_MOST) {
result = (result, specSize);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
(canvas);
drawContent(canvas);
drawLine(canvas);
drawHint(canvas);
}
private void drawContent(Canvas canvas){
int index;
int textColor;
float textSize;
float fraction = 0f;// fraction of the item in state between normal and selected, in[0, 1]
float textSizeCenterYOffset;
for(int i = 0; i < mShowCount + 1; i++){
float y = mCurrDrawFirstItemY + mItemHeight * i;
index = getIndexByRawIndex(mCurrDrawFirstItemIndex + i, getOneRecycleSize(), mWrapSelectorWheel && mWrapSelectorWheelCheck);
if(i == mShowCount / 2){//this will be picked
fraction = (float)(mItemHeight + mCurrDrawFirstItemY) / mItemHeight;
textColor = getEvaluateColor(fraction, mTextColorormal, mTextColorSelected);
textSize = getEvaluateSize(fraction, mTextSizeormal, mTextSizeSelected);
textSizeCenterYOffset = getEvaluateSize(fraction, mTextSizeormalCenterYOffset,
mTextSizeSelectedCenterYOffset);
}else if(i == mShowCount / 2 + 1){
textColor = getEvaluateColor(1 - fraction, mTextColorormal, mTextColorSelected);
textSize = getEvaluateSize(1 - fraction, mTextSizeormal, mTextSizeSelected);
textSizeCenterYOffset = getEvaluateSize(1 - fraction, mTextSizeormalCenterYOffset,
mTextSizeSelectedCenterYOffset);
}else{
textColor = mTextColorormal;
textSize = mTextSizeormal;
textSizeCenterYOffset = mTextSizeormalCenterYOffset;
}
mPaintText.setColor(textColor);
mPaintText.setTextSize(textSize);
if(0 <= index && index < getOneRecycleSize()){
CharSequence str = mDisplayedValues[index + mMinShowIndex];
if (mTextEllipsize != null) {
str = (str, mPaintText, getWidth() - 2 * mItemPaddingHorizontal, getEllipsizeType());
}
canvas.drawText((), mViewCenterX,
y + mItemHeight / 2 + textSizeCenterYOffset, mPaintText);
} else if(!TextUtils.isEmpty(mEmptyItemHint)){
canvas.drawText(mEmptyItemHint, mViewCenterX,
y + mItemHeight / 2 + textSizeCenterYOffset, mPaintText);
}
}
}
private TextUtils.TruncateAt getEllipsizeType() {
switch (mTextEllipsize) {
case TEXT_ELLIPSIZE_START:
return TextUtils.TruncateAt.START;
case TEXT_ELLIPSIZE_MIDDLE:
return TextUtils.TruncateAt.MIDDLE;
case TEXT_ELLIPSIZE_ED:
return TextUtils.TruncateAt.ED;
default:
throw new IllegalArgumentException("Illegal text ellipsize type.");
}
}
private void drawLine(Canvas canvas){
if(mShowDivider){
canvas.drawLine(getPaddingLeft() + mDividerMarginL,
dividerY0, mViewWidth - getPaddingRight() - mDividerMarginR, dividerY0, mPaintDivider);
canvas.drawLine(getPaddingLeft() + mDividerMarginL,
dividerY1, mViewWidth - getPaddingRight() - mDividerMarginR, dividerY1, mPaintDivider);
}
}
private void drawHint(Canvas canvas){
if(TextUtils.isEmpty(mHintText)) return;
canvas.drawText(mHintText,
mViewCenterX + (mMaxWidthOfDisplayedValues + mWidthOfHintText)/2 + mMarginStartOfHint,
(dividerY0 + dividerY1) / 2 + mTextSizeHintCenterYOffset, mPaintHint);
}
private void updateMaxWidthOfDisplayedValues(){
float savedTextSize = mPaintText.getTextSize();
mPaintText.setTextSize(mTextSizeSelected);
mMaxWidthOfDisplayedValues = getMaxWidthOfTextArray(mDisplayedValues, mPaintText);
mMaxWidthOfAlterArrayWithMeasureHint = getMaxWidthOfTextArray(mAlterTextArrayWithMeasureHint, mPaintText);
mMaxWidthOfAlterArrayWithoutMeasureHint = getMaxWidthOfTextArray(mAlterTextArrayWithoutMeasureHint, mPaintText);
mPaintText.setTextSize(mTextSizeHint);
mWidthOfAlterHint = getTextWidth(mAlterHint, mPaintText);
mPaintText.setTextSize(savedTextSize);
}
private int getMaxWidthOfTextArray(CharSequence[] array, Paint paint){
if(array == null){
return 0;
}
int maxWidth = 0;
for(CharSequence item : array){
if(item != null){
int itemWidth = getTextWidth(item, paint);
maxWidth = (itemWidth, maxWidth);
}
}
return maxWidth;
}
private int getTextWidth(CharSequence text, Paint paint){
if(!TextUtils.isEmpty(text)){
return (int)((()) + 0.5f);
}
return 0;
}
private void updateMaxHeightOfDisplayedValues(){
float savedTextSize = mPaintText.getTextSize();
mPaintText.setTextSize(mTextSizeSelected);
mMaxHeightOfDisplayedValues = (int)(mPaintText.getFontMetrics().bottom - mPaintText.getFontMetrics().top + 0.5);
mPaintText.setTextSize(savedTextSize);
}
private void updateContentAndIndex(String[] newDisplayedValues){
mMinShowIndex = 0;
mMaxShowIndex = newDisplayedValues.length - 1;
mDisplayedValues = newDisplayedValues;
updateWrapStateByContent();
}
private void updateContent(String[] newDisplayedValues){
mDisplayedValues = newDisplayedValues;
updateWrapStateByContent();
}
//used in setDisplayedValues
private void updateValue(){
inflateDisplayedValuesIfull();
updateWrapStateByContent();
mMinShowIndex = 0;
mMaxShowIndex = mDisplayedValues.length - 1;
}
private void updateValueForInit(){
inflateDisplayedValuesIfull();
updateWrapStateByContent();
if(mMinShowIndex == -1){
mMinShowIndex = 0;
}
if(mMaxShowIndex == -1){
mMaxShowIndex = mDisplayedValues.length - 1;
}
setMinAndMaxShowIndex(mMinShowIndex, mMaxShowIndex, false);
}
private void inflateDisplayedValuesIfull(){
if(mDisplayedValues == null) {
mDisplayedValues = new String[1];
mDisplayedValues[0] = "0";
}
}
private void updateWrapStateByContent(){
mWrapSelectorWheelCheck = mDisplayedValues.length <= mShowCount ? false : true;
}
private int refineValueByLimit(int value, int minValue, int maxValue, boolean wrap) {
if (wrap) {
if (value > maxValue) {
value = (value - maxValue) % getOneRecycleSize() + minValue - 1;
} else if (value < minValue) {
value = (value - minValue) % getOneRecycleSize() + maxValue + 1;
}
return value;
} else {
if(value > maxValue){
value = maxValue;
}else if(value < minValue){
value = minValue;
}
return value;
}
}
private void stopRefreshing(){
if (mHandlerInewThread != null){
mHandlerInewThread.removeMessages(HADLER_WHAT_REFRESH);
}
}
public void stopScrolling(){
if(mScroller != null){
if(!mScroller.isFinished()){
mScroller.startScroll(0, mScroller.getCurrY(), 0, 0, 1);
mScroller.abortAnimation();
postInvalidate();
}
}
}
public void stopScrollingAndCorrectPosition(){
stopScrolling();
if (mHandlerInewThread != null){
mHandlerInewThread.sendMessageDelayed(getMsg(HADLER_WHAT_REFRESH), 0);
}
}
private Message getMsg(int what){
return getMsg(what, 0, 0, null);
}
private Message getMsg(int what, int arg1, int arg2, Object obj){
Message msg = ();
msg.what = what;
msg.arg1 = arg1;
msg.arg2 = arg2;
= obj;
return msg;
}
//===tool functi===//
private boolean isStringEqual(String a, String b){
if(a == null){
if(b == null){
return true;
}else{
return false;
}
}else{
return (b);
}
}
private int sx(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
private int dx(Context context, float dpValue) {
final float densityScale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * densityScale + 0.5f);
}
private int getEvaluateColor(float fraction, int startColor, int endColor){
int a, r, g, b;
int sA = (startColor & 0xff000000) >>> 24;
int sR = (startColor & 0x00ff0000) >>> 16;
int sG = (startColor & 0x0000ff00) >>> 8;
int sB = (startColor & 0x000000ff) >>> 0;
int eA = (endColor & 0xff000000) >>> 24;
int eR = (endColor & 0x00ff0000) >>> 16;
int eG = (endColor & 0x0000ff00) >>> 8;
int eB = (endColor & 0x000000ff) >>> 0;
a = (int)(sA + (eA - sA) * fraction);
r = (int)(sR + (eR - sR) * fraction);
g = (int)(sG + (eG - sG) * fraction);
b = (int)(sB + (eB - sB) * fraction);
return a << 24 | r << 16 | g << 8 | b;
}
private float getEvaluateSize(float fraction, float startSize, float endSize){
return startSize + (endSize - startSize) * fraction;
}
private String[] convertCharSequenceArrayToStringArray(CharSequence[] charSequences){
if(charSequences == null) return null;
String[] ret = new String[charSequences.length];
for(int i = 0; i < charSequences.length; i++){
ret[i] = charSequences[i].toString();
}
return ret;
}
}
代码语言:javascript代码运行次数:0运行复制
一个简单的调用类:
代码语言:javascript代码运行次数:0运行复制package com.;
import Bundle;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com._control.umberPickerView;
public class ActivitySettingPickerviewActivity extends AppCompatActivity implements View.OnClickListener,umberPickerView.OnScrollListener,umberPickerView.OnValueChangeListener,
umberPickerView.OnValueChangeListenerInScrolling{
private umberPickerView picker;
@Override
protected void onCreate(Bundle savedInstanceState) {
(savedInstanceState);
setContentView(R.layout.activity_setting_pickerview);
picker = (umberPickerView) findViewById(R.id.picker);
picker.setOnScrollListener(this);
picker.setOnValueChangedListener((umberPickerView.OnValueChangeListener) this);
picker.setOnValueChangeListenerInScrolling((umberPickerView.OnValueChangeListenerInScrolling) this);
String[] display_2 = getResources().getStringArray(R._display_2);
picker.refreshByewDisplayedValues(display_2);
}
@Override
public void onValueChange(umberPickerView picker, int oldVal, int newVal) {
}
@Override
public void onValueChangeInScrolling(umberPickerView picker, int oldVal, int newVal) {
}
@Override
public void onScrollStateChange(umberPickerView view, int scrollState) {
}
@Override
public void onClick(View v) {
}
}
代码语言:javascript代码运行次数:0运行复制
是不是需要layout界面??
代码语言:javascript代码运行次数:0运行复制<com._control.umberPickerView
android:id="@+id/picker"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:background="@color/base_white"
android:contentDescription="test_number_picker_view"
app:npv_ItemPaddingHorizontal="5dp"
app:npv_ItemPaddingVertical="5dp"
app:npv_ShowCount="5"
app:npv_TextSizeormal="14sp"
app:npv_TextSizeSelected="20sp"
app:npv_WrapSelectorWheel="false" />
就只写这个控件了。不明白留言啊
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-12-16,如有侵权请联系 cloudcommunity@tencent 删除androidintprivatevoid开发#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上传时间: 2025-07-28 12:29:15
推荐阅读
留言与评论(共有 8 条评论) |
本站网友 外汇保证金 | 27分钟前 发表 |
0 | |
本站网友 817事件 | 19分钟前 发表 |
msg.arg2 | |
本站网友 青岛海景花园大酒店 | 21分钟前 发表 |
float spanY = downY - currY; if(mFlagMayPress && (-mScaledTouchSlop < spanY && spanY < mScaledTouchSlop)){ }else{ mFlagMayPress = false; mCurrDrawGlobalY = limitY((int)(downYGlobal + spanY)); calculateFirstItemParameterByGlobalY(); invalidate(); } onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); break; case MotionEvent.ACTIO_UP | |
本站网友 金价格 | 3分钟前 发表 |
mCurrDrawGlobalY | |
本站网友 雪泡瘦有用吗 | 20分钟前 发表 |
mPaintHint); if(mPaintText == null){ throw new IllegalArgumentException("mPaintText should not be null."); } mPaintText.setTextSize(mTextSizeSelected); mTextSizeSelectedCenterYOffset = getTextCenterYOffset(mPaintText.getFontMetrics()); mPaintText.setTextSize(mTextSizeormal); mTextSizeormalCenterYOffset = getTextCenterYOffset(mPaintText.getFontMetrics()); } private void updateotWrapYLimit(){ motWrapLimitYTop = 0; motWrapLimitYBottom = -mShowCount * mItemHeight; if(mDisplayedValues != null){ motWrapLimitYTop = (getOneRecycleSize() - mShowCount / 2 - 1)* mItemHeight; motWrapLimitYBottom = -(mShowCount / 2) * mItemHeight; } } private float downYGlobal = 0 ; private float downY = 0; private float currY = 0; private int limitY(int currDrawGlobalYPreferred){ if(mWrapSelectorWheel && mWrapSelectorWheelCheck) return currDrawGlobalYPreferred; if(currDrawGlobalYPreferred < motWrapLimitYBottom){ currDrawGlobalYPreferred = motWrapLimitYBottom; }else if(currDrawGlobalYPreferred > motWrapLimitYTop){ currDrawGlobalYPreferred = motWrapLimitYTop; } return currDrawGlobalYPreferred; } private boolean mFlagMayPress = false; @Override public boolean onTouchEvent(MotionEvent event) { if(mItemHeight == 0) return true; if (mVelocityTracker == null) { mVelocityTracker = (); } mVelocityTracker.addMovement(event); currY = event.getY(); switch(event.getAction()){ case MotionEvent.ACTIO_DOW | |
本站网友 中日关系恶化 | 12分钟前 发表 |
y + mItemHeight / 2 + textSizeCenterYOffset | |
本站网友 浙江省公安厅厅长 | 27分钟前 发表 |
DEFAULT_RESPOD_CHAGE_O_DETACH); }else if(attr == R.styleable.umberPickerView_npv_RespondChangeInMainThread){ mRespondChangeInMainThread = a.getBoolean(attr |