diff --git a/app/src/main/java/com/wp/demo/MainActivity.java b/app/src/main/java/com/wp/demo/MainActivity.java index c5a668f..589eb30 100644 --- a/app/src/main/java/com/wp/demo/MainActivity.java +++ b/app/src/main/java/com/wp/demo/MainActivity.java @@ -38,7 +38,7 @@ public void onBirthPicked(int year, int month, int day) { @Override public void onClick(View view) { DataPicker.pickFutureDate(MainActivity.this, new Date(System.currentTimeMillis()), - DateWheelPicker.TYPE_ALL, View.VISIBLE, new DataPicker.OnDatePickListener() { + DateWheelPicker.TYPE_ALL, View.VISIBLE, 100, new DataPicker.OnDatePickListener() { @Override public void onDatePicked(int year, int month, int day, int hour, int minute, int second) { Toast.makeText(MainActivity.this, year + "-" + (month + 1) + "-" + day + " " + hour + ":" + minute, Toast.LENGTH_SHORT).show(); @@ -89,6 +89,30 @@ private List getTextList() { data.add("阿朱"); data.add("王菇凉"); + data.add("杨过2"); + data.add("张无忌2"); + data.add("郭靖2"); + data.add("乔峰2"); + data.add("令狐冲2"); + data.add("赵敏2"); + data.add("东方不败2"); + data.add("小龙女2"); + data.add("黄蓉2"); + data.add("阿朱2"); + data.add("王菇凉2"); + + data.add("杨过3"); + data.add("张无忌3"); + data.add("郭靖3"); + data.add("乔峰3"); + data.add("令狐冲3"); + data.add("赵敏3"); + data.add("东方不败3"); + data.add("小龙女3"); + data.add("黄蓉3"); + data.add("阿朱3"); + data.add("王菇凉3"); + return data; } } diff --git a/library/src/main/java/com/wheelpicker/DataPicker.java b/library/src/main/java/com/wheelpicker/DataPicker.java index fad0e25..8df05e6 100644 --- a/library/src/main/java/com/wheelpicker/DataPicker.java +++ b/library/src/main/java/com/wheelpicker/DataPicker.java @@ -5,6 +5,7 @@ import android.graphics.drawable.ColorDrawable; import android.view.View; + import com.wheelpicker.core.AbstractWheelPicker; import com.wheelpicker.core.OnWheelPickedListener; import com.wheelpicker.widget.TextWheelPicker; @@ -84,6 +85,7 @@ public void onDatePicked(int year, int month, int day, int hour, int minute, int mDay = dd; } picker.setCurrentDate(mYear, mMonth, mDay); + picker.notifyDataSetChanged(); int padding = context.getResources().getDimensionPixelOffset(R.dimen.px20); picker.setPadding(0, padding, 0, padding); @@ -181,6 +183,7 @@ public void onDatePicked(int year, int month, int day, int hour, int minute, int picker.setCurrentTime(mHour, mMinute, mSecond); picker.setCurrentDate(mYear, mMonth, mDay); + picker.notifyDataSetChanged(); int padding = context.getResources().getDimensionPixelOffset(R.dimen.px20); picker.setPadding(0, padding, 0, padding); @@ -199,14 +202,15 @@ public void onClick(View v) { } /** - * 选择未来时间,默认当前时间到100年后 + * 选择未来时间,默认100年后 * * @param context * @param currentDate + * @param year 往后推多少年 * @param pickListener */ - public static void pickFutureDate(Context context, Date currentDate, int whichWheelPick, - int visibility, final OnDatePickListener pickListener) { + public static void pickFutureDate(Context context, Date currentDate, int whichWheelPick, int visibility, + int year, final OnDatePickListener pickListener) { BottomSheet bottomSheet = new BottomSheet(context); final DateWheelPicker picker = new DateWheelPicker(context); picker.setWheelPickerVisibility(whichWheelPick, visibility); @@ -232,10 +236,16 @@ public void onDatePicked(int year, int month, int day, int hour, int minute, int mYear = year; mMonth = month; mDay = day; + mHour = hour; + mMinute = minute; + mSecond = second; } }); - picker.setDateRange(dy, dy + 100); + if (year <= 0) { + year = 100; + } + picker.setDateRange(dy, dy + year); //after set onDatePickerLister if (currentDate != null) { calendar.setTime(currentDate); @@ -253,9 +263,9 @@ public void onDatePicked(int year, int month, int day, int hour, int minute, int mMinute = mm; mSecond = ss; } - picker.setCurrentTime(mHour, mMinute, mSecond); picker.setCurrentDate(mYear, mMonth, mDay); + picker.notifyDataSetChanged(); int padding = context.getResources().getDimensionPixelOffset(R.dimen.px20); picker.setPadding(0, padding, 0, padding); @@ -286,7 +296,7 @@ public static void pickFutureDate(Context context, Date currentDate, int days, BottomSheet bottomSheet = new BottomSheet(context); FutureTimePicker picker = new FutureTimePicker(context); - java.util.Calendar calendar = java.util.Calendar.getInstance(); + Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); picker.setBackgroundDrawable(new ColorDrawable(Color.WHITE)); diff --git a/library/src/main/java/com/wheelpicker/DateWheelPicker.java b/library/src/main/java/com/wheelpicker/DateWheelPicker.java index 1a54e40..d561443 100644 --- a/library/src/main/java/com/wheelpicker/DateWheelPicker.java +++ b/library/src/main/java/com/wheelpicker/DateWheelPicker.java @@ -5,7 +5,6 @@ import android.view.Gravity; import android.widget.LinearLayout; - import com.wheelpicker.core.AbstractWheelPicker; import com.wheelpicker.core.OnWheelPickedListener; import com.wheelpicker.widget.TextWheelPicker; @@ -40,7 +39,7 @@ public class DateWheelPicker extends LinearLayout implements OnWheelPickedListen public final static int TYPE_ALL = TYPE_YEAR | TYPE_MONTH | TYPE_DAY | TYPE_HOUR | TYPE_MINUTE | TYPE_SECOND; //年月日 - public final static int TYPE_YY_MM_DD = TYPE_HOUR | TYPE_SECOND | TYPE_MINUTE; + public final static int TYPE_YY_MM_DD = TYPE_YEAR | TYPE_MONTH | TYPE_DAY; //时分秒 public final static int TYPE_HH_MM_SS = TYPE_HOUR | TYPE_SECOND | TYPE_MINUTE; @@ -279,6 +278,7 @@ public void setCurrentDate(int year, int month, int day) { mSelectedMonth = month; mSelectedDay = day; + //更新月份和天数 if (mCurrYear == mSelectedYear) { if (mMode == MODE_BIRTHDAY) { updateMaxMonths(mCurrMonth); @@ -298,15 +298,7 @@ public void setCurrentDate(int year, int month, int day) { int monthIndex = Math.max(0, mMonths.indexOf((month + 1) + mMonthStr)); int dayIndex = Math.max(0, mDays.indexOf(day + mDayStr)); - setDateItemIndex(yearIndex, monthIndex, dayIndex); - - mMonthPickerAdapter.setData(mMonths); - mDayPickerAdapter.setData(mDays); - - if (mOnDatePickListener != null) { - mOnDatePickListener.onDatePicked(mSelectedYear, mSelectedMonth, mSelectedDay, - mSelectedHour, mSelectedMinute, mSelectedSecond); - } + setDateItemIndexWithoutReLayout(yearIndex, monthIndex, dayIndex); } public void setCurrentTime(int hour, int minute, int second) { @@ -320,10 +312,9 @@ public void setCurrentTime(int hour, int minute, int second) { if (mMode == MODE_PENDING) { updateMinHour(mCurrHour); - //updateMinMinute(mCurrMinute); - //updateMinSecond(mCurrSecond); + updateMinMinute(mCurrMinute); //TODO - updateMaxMinute(mCurrMinute); + //updateMinSecond(mCurrSecond); updateMaxSecond(mCurrSecond); } else { updateMaxHour(mCurrHour); @@ -333,7 +324,12 @@ public void setCurrentTime(int hour, int minute, int second) { int hourIndex = Math.max(0, mHours.indexOf(hour + mHourStr)); int minuteIndex = Math.max(0, mMinutes.indexOf(minute + mMinuteStr)); int secondIndex = Math.max(0, mSeconds.indexOf(second + mSecondStr)); - setTimeItemIndex(hourIndex, minuteIndex, secondIndex); + setTimeItemIndexWithoutReLayout(hourIndex, minuteIndex, secondIndex); + } + + public void notifyDataSetChanged() { + //年月日市时分秒是联动的,所以只需要通知年的数据变化 + mYearPickerAdapter.notifyDataSetChanged(); } private void setDateItemIndex(int yearIndex, int monthIndex, int dayIndex) { @@ -348,6 +344,18 @@ private void setTimeItemIndex(int hourIndex, int minuteIndex, int secondIndex) { mSecondWheelPicker.setCurrentItem(secondIndex); } + private void setDateItemIndexWithoutReLayout(int yearIndex, int monthIndex, int dayIndex) { + mYearWheelPicker.setCurrentItem(yearIndex); + mMonthWheelPicker.setCurrentItem(monthIndex); + mDayWheelPicker.setCurrentItem(dayIndex); + } + + private void setTimeItemIndexWithoutReLayout(int hourIndex, int minuteIndex, int secondIndex) { + mHourWheelPicker.setCurrentItemWithoutReLayout(hourIndex); + mMinuteWheelPicker.setCurrentItemWithoutReLayout(minuteIndex); + mSecondWheelPicker.setCurrentItemWithoutReLayout(secondIndex); + } + public void setTextSize(int textSize) { if (textSize < 0) { return; @@ -431,7 +439,7 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d boolean changed = false; if (mMode == MODE_PENDING) { - if (index == 0) { + if (mSelectedYear == mCurrYear) { //current year updateMinMonths(mCurrMonth); } else { @@ -444,7 +452,7 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d int monthIndex = Math.max(0, mMonths.indexOf((mSelectedMonth + 1) + mMonthStr)); mMonthWheelPicker.setCurrentItemWithoutReLayout(monthIndex); } else { - if (index == mYears.size() - 1) { + if (mSelectedYear == mCurrYear && mMode == MODE_BIRTHDAY) { //current year updateMaxMonths(mCurrMonth); } else { @@ -463,7 +471,7 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d mSelectedMonth = month; } if (mMode == MODE_PENDING) { - if (index == 0 && mSelectedYear == mCurrYear) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth) { //current month correctMinDays(mCurrDay); } else { @@ -473,7 +481,7 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d int dayIndex = Math.max(0, mDays.indexOf(mSelectedDay + mDayStr)); mDayWheelPicker.setCurrentItemWithoutReLayout(dayIndex); } else { - if (index == mMonths.size() - 1 && mSelectedYear == mCurrYear) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mMode == MODE_BIRTHDAY) { //current month updateMaxDays(mCurrDay); } else { @@ -485,7 +493,7 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d case TYPE_DAY: mSelectedDay = getCurrentDate(data, mDayStr); if (mMode == MODE_PENDING) { - if (index == 0 && mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay) { //current day updateMinHour(mCurrHour); } else { @@ -495,7 +503,8 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d int hourIndex = Math.max(0, mHours.indexOf(mSelectedHour + mHourStr)); mHourWheelPicker.setCurrentItemWithoutReLayout(hourIndex); } else { - if (index == mMonths.size() - 1 && mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay + && mMode == MODE_BIRTHDAY) { //current month updateMaxHour(mCurrHour); } else { @@ -505,13 +514,55 @@ public void onWheelSelected(AbstractWheelPicker wheelPicker, int index, Object d mHourPickerAdapter.setData(mHours); break; case TYPE_HOUR: - mSelectedHour = getCurrentDate(data, mDayStr); + mSelectedHour = getCurrentDate(data, mHourStr); + if (mMode == MODE_PENDING) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay + && mSelectedHour == mCurrHour) { + //current hour + updateMinMinute(mCurrMinute); + } else { + updateMaxMinute(60); + } + + int minuteIndex = Math.max(0, mMinutes.indexOf(mSelectedMinute + mMinuteStr)); + mMinuteWheelPicker.setCurrentItemWithoutReLayout(minuteIndex); + } else { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay + && mSelectedHour == mCurrHour && mMode == MODE_BIRTHDAY) { + //current month + updateMaxMinute(mCurrMinute); + } else { + updateMaxMinute(60); + } + } + mMinutePickerAdapter.setData(mMinutes); break; case TYPE_MINUTE: - mSelectedMinute = getCurrentDate(data, mDayStr); + mSelectedMinute = getCurrentDate(data, mMinuteStr); + if (mMode == MODE_PENDING) { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay + && mSelectedHour == mCurrHour && mSelectedMinute == mCurrMinute) { + //current minute + updateMinSecond(mCurrSecond); + } else { + updateMaxSecond(60); + } + + int secondIndex = Math.max(0, mSeconds.indexOf(mSelectedSecond + mSecondStr)); + mSecondWheelPicker.setCurrentItemWithoutReLayout(secondIndex); + } else { + if (mSelectedYear == mCurrYear && mSelectedMonth == mCurrMonth && mSelectedDay == mCurrDay + && mSelectedHour == mCurrHour && mSelectedMinute == mCurrMinute && mMode == MODE_BIRTHDAY) { + //current month + updateMaxSecond(mCurrSecond); + } else { + updateMaxSecond(60); + } + } + mSecondPickerAdapter.setData(mSeconds); break; case TYPE_SECOND: - mSelectedSecond = getCurrentDate(data, mDayStr); + mSelectedSecond = getCurrentDate(data, mSecondStr); break; default: break; diff --git a/library/src/main/java/com/wheelpicker/core/AbstractWheelPicker.java b/library/src/main/java/com/wheelpicker/core/AbstractWheelPicker.java index 74c06c9..ade2379 100644 --- a/library/src/main/java/com/wheelpicker/core/AbstractWheelPicker.java +++ b/library/src/main/java/com/wheelpicker/core/AbstractWheelPicker.java @@ -15,357 +15,378 @@ import com.wheelpicker.R; + +/* + * Copyright (C) 2017 重庆呼我出行网络科技有限公司 + * 版权所有 + * + * 功能描述: + * + * 作者:huangyong + * 创建时间:2017/11/26 + * + * 修改人: + * 修改描述: + * 修改日期 + */ public abstract class AbstractWheelPicker extends View { - private static final int VELOCITY_TRACKER_UNITS_DEFAULT = 600; - - private static final int DEFAULT_INDEX = 0; - private static final int DEFAULT_COUNT = 5; - private static final int DEFAULT_SPACE = 20; - private static final int DEFAULT_COLOR = 0xFF000000; - - protected VelocityTracker mTracker; - - public static final int SHADOW_LEFT = 0; - public static final int SHADOW_MIDDLE = 1; - public static final int SHADOW_RIGHT = 2; - protected static final int SHADOW_MAX = 100; - - // 滚轮是偏右还是左 - protected int mShadowGravity = SHADOW_RIGHT; - protected float mShadowFactor = 0.4f; //0 ~ 1.0f; - - protected Paint mPaint; - protected Paint mLinePaint; - - protected int mWheelContentWidth; - protected int mWheelContentHeight; - - protected int mViewWidth; - protected int mViewHeight; - - protected Rect mBounds; - protected float mWheelCenterX; - protected float mWheelCenterY; - protected float mWheelCenterTextY; - - /** Default count of visible items */ - protected int mVisibleItemCount; - protected int mItemSpace; - protected int mCurrItemIndex; - protected int mColor; - protected int mLineColor; - protected int mLineStrokeWidth; - - protected int mItemSartIndex; - protected int mItemEndIndex; - - protected int mItemMaxWidth; - protected int mItemMaxHeight; - - protected boolean mIgnorePadding; - protected T mAdapter; - protected AdapterDataSetObserver mDataSetObserver; - - protected float mOldX; - protected float mOldY; - protected float mCurrentX; - protected float mCurrentY; - protected float mDeltaX; - protected float mDeltaY; - - public AbstractWheelPicker(Context context) { - super(context); - init(null); - } - - public AbstractWheelPicker(Context context, AttributeSet attrs) { - super(context, attrs); - init(attrs); - } - - public AbstractWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(attrs); - } - - private void init(AttributeSet attrs) { - obtainAttrs(attrs); - instantiation(); - computeWheelSize(); - } - - protected void obtainAttrs(AttributeSet attrs) { - if (attrs == null) { - mColor = DEFAULT_COLOR; - mLineColor = Color.LTGRAY; - mCurrItemIndex = DEFAULT_INDEX; - mVisibleItemCount = DEFAULT_COUNT; - mItemSpace = DEFAULT_SPACE; - mLineStrokeWidth = 1; - } else { - TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WheelPicker); - - mCurrItemIndex = a.getInt(R.styleable.WheelPicker_wheel_item_index, DEFAULT_INDEX); - mVisibleItemCount = a.getInt(R.styleable.WheelPicker_wheel_visible_item_count, DEFAULT_COUNT); - mItemSpace = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_space, DEFAULT_SPACE); - mColor = a.getColor(R.styleable.WheelPicker_wheel_text_color, DEFAULT_COLOR); - mLineColor = a.getColor(R.styleable.WheelPicker_wheel_line_color, Color.LTGRAY); - mLineStrokeWidth = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_line_width, 1); - a.recycle(); - } - } - - protected void instantiation() { - mCurrentX = 0; - mCurrentY = 0; - - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); - mPaint.setColor(mColor); - mPaint.setTextSize(70); - - mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); - mLinePaint.setColor(mLineColor); - mLinePaint.setStyle(Style.FILL); - mLinePaint.setStrokeWidth(mLineStrokeWidth); - - mBounds = new Rect(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int modeWidth = MeasureSpec.getMode(widthMeasureSpec); - int modeHeight = MeasureSpec.getMode(heightMeasureSpec); - - int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); - int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); - - int resultWidth = mWheelContentWidth; - int resultHeight = mWheelContentHeight; - - resultWidth += (getPaddingLeft() + getPaddingRight()); - resultHeight += (getPaddingTop() + getPaddingBottom()); - resultWidth = measureSize(modeWidth, sizeWidth, resultWidth); - resultHeight = measureSize(modeHeight, sizeHeight, resultHeight); - - mViewWidth = resultWidth; - mViewHeight = resultHeight; - - setMeasuredDimension(resultWidth, resultHeight); - } - - protected int measureSize(int mode, int sizeExpect, int sizeActual) { - int realSize; - if (mode == MeasureSpec.EXACTLY) { - realSize = sizeExpect; - } else { - realSize = sizeActual; - if (mode == MeasureSpec.AT_MOST) { - realSize = Math.min(realSize, sizeExpect); - } - } - return realSize; - } - - @Override - protected void onSizeChanged(int w, int h, int oldW, int oldH) { - mBounds.set(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom()); - - mWheelCenterX = mBounds.centerX(); - mWheelCenterY = mBounds.centerY(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - if (mAdapter != null && mDataSetObserver != null) { - mAdapter.unregisterDataSetObserver(mDataSetObserver); - mDataSetObserver = null; - } - } - - @Override - protected void onDraw(Canvas canvas) { - drawBackground(canvas); - - canvas.save(); - canvas.clipRect(mBounds); - drawItems(canvas); - canvas.restore(); - - drawForeground(canvas); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (null == mTracker) { - mTracker = VelocityTracker.obtain(); - } - mTracker.addMovement(event); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mOldX = event.getX(); - mOldY = event.getY(); - onTouchDown(event); - break; - case MotionEvent.ACTION_MOVE: - mDeltaX = event.getX() - mOldX; - mDeltaY = event.getY() - mOldY; - mOldX = event.getX(); - mOldY = event.getY(); - - onTouchMove(event); - break; - case MotionEvent.ACTION_UP: - mTracker.computeCurrentVelocity(VELOCITY_TRACKER_UNITS_DEFAULT); - onTouchUp(event); - - mTracker.recycle(); - mTracker = null; - break; - case MotionEvent.ACTION_CANCEL: - getParent().requestDisallowInterceptTouchEvent(false); - mTracker.recycle(); - mTracker = null; - onTouchCancel(event); - - break; - } - return true; - - } - - public void setCurrentItem(int index) { - mCurrItemIndex = index; - requestComputeLayout(); - } - - public void setCurrentItemWithoutReLayout(int index) { - mCurrItemIndex = index; - } - - public int getCurrentItem() { - return mCurrItemIndex; - } - - public void setItemSpace(int space) { - mItemSpace = space; - if (mAdapter != null && !mAdapter.isEmpty()) { - requestComputeLayout(); - } - } - - public void setVisibleItemCount(int count) { - mVisibleItemCount = count; - if (mAdapter != null && !mAdapter.isEmpty()) { - requestComputeLayout(); - } - } - - public void setShadowGravity(int gravity) { - mShadowGravity = gravity; - } - - public void setShadowFactor(float factor) { - if (factor > 1.0) { - factor = 1.0f; - } - - if (factor < 0) { - factor = 0; - } - - mShadowFactor = factor; - } - - public synchronized void setAdapter(T adapter) { - if (adapter == null) { - return; - } - - if (mAdapter != null && mDataSetObserver != null) { - mAdapter.unregisterDataSetObserver(mDataSetObserver); - mDataSetObserver = null; - } - - mAdapter = adapter; - if (mCurrItemIndex > mAdapter.getCount() || mCurrItemIndex < 0) { - mCurrItemIndex = 0; - } - - if (mDataSetObserver == null) { - mDataSetObserver = new AdapterDataSetObserver(); - mAdapter.registerDataSetObserver(mDataSetObserver); + private static final int VELOCITY_TRACKER_UNITS_DEFAULT = 600; + + private static final int DEFAULT_INDEX = 0; + private static final int DEFAULT_COUNT = 5; + private static final int DEFAULT_SPACE = 20; + private static final int DEFAULT_COLOR = 0xFF000000; + + protected VelocityTracker mTracker; + + public static final int SHADOW_LEFT = 0; + public static final int SHADOW_MIDDLE = 1; + public static final int SHADOW_RIGHT = 2; + protected static final int SHADOW_MAX = 100; + + // 滚轮是偏右还是左 + protected int mShadowGravity = SHADOW_RIGHT; + protected float mShadowFactor = 0.4f; //0 ~ 1.0f; + + protected Paint mPaint; + protected Paint mLinePaint; + + protected int mWheelContentWidth; + protected int mWheelContentHeight; + + protected int mViewWidth; + protected int mViewHeight; + + protected Rect mBounds; + protected float mWheelCenterX; + protected float mWheelCenterY; + protected float mWheelCenterTextY; + + /** + * Default count of visible items + */ + protected int mVisibleItemCount; + protected int mItemSpace; + protected int mCurrItemIndex; + protected int mColor; + protected int mLineColor; + protected int mLineStrokeWidth; + + protected int mItemSartIndex; + protected int mItemEndIndex; + + protected int mItemMaxWidth; + protected int mItemMaxHeight; + + protected boolean mIgnorePadding; + protected T mAdapter; + protected AdapterDataSetObserver mDataSetObserver; + + protected float mOldX; + protected float mOldY; + protected float mCurrentX; + protected float mCurrentY; + protected float mDeltaX; + protected float mDeltaY; + + public AbstractWheelPicker(Context context) { + super(context); + init(null); + } + + public AbstractWheelPicker(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public AbstractWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } + + private void init(AttributeSet attrs) { + obtainAttrs(attrs); + instantiation(); + computeWheelSize(); + } + + protected void obtainAttrs(AttributeSet attrs) { + if (attrs == null) { + mColor = DEFAULT_COLOR; + mLineColor = Color.LTGRAY; + mCurrItemIndex = DEFAULT_INDEX; + mVisibleItemCount = DEFAULT_COUNT; + mItemSpace = DEFAULT_SPACE; + mLineStrokeWidth = 1; + } else { + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WheelPicker); + + mCurrItemIndex = a.getInt(R.styleable.WheelPicker_wheel_item_index, DEFAULT_INDEX); + mVisibleItemCount = a.getInt(R.styleable.WheelPicker_wheel_visible_item_count, DEFAULT_COUNT); + mItemSpace = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_space, DEFAULT_SPACE); + mColor = a.getColor(R.styleable.WheelPicker_wheel_text_color, DEFAULT_COLOR); + mLineColor = a.getColor(R.styleable.WheelPicker_wheel_line_color, Color.LTGRAY); + mLineStrokeWidth = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_line_width, 1); + a.recycle(); } - - requestComputeLayout(); - } + } - protected void updateItemIndexRange() { - if (mAdapter != null && !mAdapter.isEmpty()) { - mItemSartIndex = Math.max(0, mCurrItemIndex - mVisibleItemCount / 2 - 1); - mItemEndIndex = Math.min(mCurrItemIndex + mVisibleItemCount / 2 + 1, mAdapter.getCount() - 1); - } - } - - public void requestComputeLayout() { - if ((mAdapter != null && mCurrItemIndex >= mAdapter.getCount())) { - mCurrItemIndex = mAdapter.getCount() - 1; - } + protected void instantiation() { + mCurrentX = 0; + mCurrentY = 0; - resetScroll(); - initItemSize(); - computeWheelSize(); - updateItemIndexRange(); - postInvalidate(); - } + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mPaint.setColor(mColor); + mPaint.setTextSize(70); - /** ==============abstract method============== */ - protected abstract void initItemSize(); + mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mLinePaint.setColor(mLineColor); + mLinePaint.setStyle(Style.FILL); + mLinePaint.setStrokeWidth(mLineStrokeWidth); - protected abstract void computeWheelSize(); - - protected abstract void resetScroll(); + mBounds = new Rect(); + } - protected abstract void drawBackground(Canvas canvas); + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int modeWidth = MeasureSpec.getMode(widthMeasureSpec); + int modeHeight = MeasureSpec.getMode(heightMeasureSpec); - protected abstract void drawItems(Canvas canvas); + int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); + int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); - protected abstract void drawForeground(Canvas canvas); + int resultWidth = mWheelContentWidth; + int resultHeight = mWheelContentHeight; - protected abstract void onTouchDown(MotionEvent event); + resultWidth += (getPaddingLeft() + getPaddingRight()); + resultHeight += (getPaddingTop() + getPaddingBottom()); + resultWidth = measureSize(modeWidth, sizeWidth, resultWidth); + resultHeight = measureSize(modeHeight, sizeHeight, resultHeight); - protected abstract void onTouchMove(MotionEvent event); + mViewWidth = resultWidth; + mViewHeight = resultHeight; - protected abstract void onTouchUp(MotionEvent event); + setMeasuredDimension(resultWidth, resultHeight); + } + + protected int measureSize(int mode, int sizeExpect, int sizeActual) { + int realSize; + if (mode == MeasureSpec.EXACTLY) { + realSize = sizeExpect; + } else { + realSize = sizeActual; + if (mode == MeasureSpec.AT_MOST) { + realSize = Math.min(realSize, sizeExpect); + } + } + return realSize; + } + + @Override + protected void onSizeChanged(int w, int h, int oldW, int oldH) { + mBounds.set(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom()); - protected abstract void onTouchCancel(MotionEvent event); - /** ==============abstract method============== */ + mWheelCenterX = mBounds.centerX(); + mWheelCenterY = mBounds.centerY(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (mAdapter != null && mDataSetObserver != null) { + mAdapter.unregisterDataSetObserver(mDataSetObserver); + mDataSetObserver = null; + } + } - protected void onWheelSelected(int index) { + @Override + protected void onDraw(Canvas canvas) { + drawBackground(canvas); + + canvas.save(); + canvas.clipRect(mBounds); + drawItems(canvas); + canvas.restore(); + + drawForeground(canvas); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (null == mTracker) { + mTracker = VelocityTracker.obtain(); + } + mTracker.addMovement(event); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mOldX = event.getX(); + mOldY = event.getY(); + onTouchDown(event); + break; + case MotionEvent.ACTION_MOVE: + mDeltaX = event.getX() - mOldX; + mDeltaY = event.getY() - mOldY; + mOldX = event.getX(); + mOldY = event.getY(); + + onTouchMove(event); + break; + case MotionEvent.ACTION_UP: + mTracker.computeCurrentVelocity(VELOCITY_TRACKER_UNITS_DEFAULT); + onTouchUp(event); + + mTracker.recycle(); + mTracker = null; + break; + case MotionEvent.ACTION_CANCEL: + getParent().requestDisallowInterceptTouchEvent(false); + mTracker.recycle(); + mTracker = null; + onTouchCancel(event); + + break; + } + return true; + + } + + public void setCurrentItem(int index) { + mCurrItemIndex = index; + requestComputeLayout(); + } + + public void setCurrentItemWithoutReLayout(int index) { + mCurrItemIndex = index; + } + + public int getCurrentItem() { + return mCurrItemIndex; + } + + public void setItemSpace(int space) { + mItemSpace = space; + if (mAdapter != null && !mAdapter.isEmpty()) { + requestComputeLayout(); + } + } + + public void setVisibleItemCount(int count) { + mVisibleItemCount = count; + if (mAdapter != null && !mAdapter.isEmpty()) { + requestComputeLayout(); + } + } + + public void setShadowGravity(int gravity) { + mShadowGravity = gravity; + } + + public void setShadowFactor(float factor) { + if (factor > 1.0) { + factor = 1.0f; + } + + if (factor < 0) { + factor = 0; + } + + mShadowFactor = factor; + } + + public synchronized void setAdapter(T adapter) { + if (adapter == null) { + return; + } + + if (mAdapter != null && mDataSetObserver != null) { + mAdapter.unregisterDataSetObserver(mDataSetObserver); + mDataSetObserver = null; + } + + mAdapter = adapter; + if (mCurrItemIndex > mAdapter.getCount() || mCurrItemIndex < 0) { + mCurrItemIndex = 0; + } + + if (mDataSetObserver == null) { + mDataSetObserver = new AdapterDataSetObserver(); + mAdapter.registerDataSetObserver(mDataSetObserver); + } + + requestComputeLayout(); + } + + protected void updateItemIndexRange() { + if (mAdapter != null && !mAdapter.isEmpty()) { + mItemSartIndex = Math.max(0, mCurrItemIndex - mVisibleItemCount / 2 - 1); + mItemEndIndex = Math.min(mCurrItemIndex + mVisibleItemCount / 2 + 1, mAdapter.getCount() - 1); + } + } + + public void requestComputeLayout() { + if ((mAdapter != null && mCurrItemIndex >= mAdapter.getCount())) { + mCurrItemIndex = mAdapter.getCount() - 1; + } + + resetScroll(); + initItemSize(); + computeWheelSize(); + updateItemIndexRange(); + postInvalidate(); + } + + /** + * ==============abstract method============== + */ + protected abstract void initItemSize(); + + protected abstract void computeWheelSize(); + + protected abstract void resetScroll(); + + protected abstract void drawBackground(Canvas canvas); + + protected abstract void drawItems(Canvas canvas); + + protected abstract void drawForeground(Canvas canvas); + + protected abstract void onTouchDown(MotionEvent event); + + protected abstract void onTouchMove(MotionEvent event); + + protected abstract void onTouchUp(MotionEvent event); + + protected abstract void onTouchCancel(MotionEvent event); + + /** + * ==============abstract method============== + */ + + protected void onWheelSelected(int index) { + + } - } - class AdapterDataSetObserver extends DataSetObserver { @Override public void onChanged() { - int count = 0; - if (mAdapter != null) { - count = mAdapter.getCount(); - } - if (mCurrItemIndex > count - 1) { - mCurrItemIndex = count - 1; - } - onWheelSelected(mCurrItemIndex); - requestComputeLayout(); + int count = 0; + if (mAdapter != null) { + count = mAdapter.getCount(); + } + if (mCurrItemIndex > count - 1) { + mCurrItemIndex = count - 1; + } + onWheelSelected(mCurrItemIndex); + requestComputeLayout(); } @Override public void onInvalidated() { - invalidate(); + invalidate(); } } - + } diff --git a/library/src/main/java/com/wheelpicker/core/OSUtils.java b/library/src/main/java/com/wheelpicker/core/OSUtils.java new file mode 100644 index 0000000..2504aaf --- /dev/null +++ b/library/src/main/java/com/wheelpicker/core/OSUtils.java @@ -0,0 +1,198 @@ +package com.wheelpicker.core; + +import android.text.TextUtils; + +import java.io.IOException; +import java.lang.reflect.Method; + +/* + * Copyright (C) 2017 重庆呼我出行网络科技有限公司 + * 版权所有 + * + * 功能描述: + * 作者:huangyong + * 创建时间:2018/4/19 + * + * 修改人: + * 修改描述: + * 修改日期 + */ +public class OSUtils { + private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; + private static final String KEY_EMUI_VERSION_NAME = "ro.build.version.emui"; + private static final String KEY_DISPLAY = "ro.build.display.id"; + + /** + * 判断是否为miui + * Is miui boolean. + * + * @return the boolean + */ + public static boolean isMIUI() { + String property = getSystemProperty(KEY_MIUI_VERSION_NAME, ""); + return !TextUtils.isEmpty(property); + } + + /** + * 判断miui版本是否大于等于6 + * Is miui 6 later boolean. + * + * @return the boolean + */ + public static boolean isMIUI6Later() { + String version = getMIUIVersion(); + int num; + if ((!version.isEmpty())) { + try { + num = Integer.valueOf(version.substring(1)); + return num >= 6; + } catch (NumberFormatException e) { + return false; + } + } else + return false; + } + + /** + * 获得miui的版本 + * Gets miui version. + * + * @return the miui version + */ + public static String getMIUIVersion() { + return isMIUI() ? getSystemProperty(KEY_MIUI_VERSION_NAME, "") : ""; + } + + /** + * 判断是否为emui + * Is emui boolean. + * + * @return the boolean + */ + public static boolean isEMUI() { + String property = getSystemProperty(KEY_EMUI_VERSION_NAME, ""); + return !TextUtils.isEmpty(property); + } + + /** + * 得到emui的版本 + * Gets emui version. + * + * @return the emui version + */ + public static String getEMUIVersion() { + return isEMUI() ? getSystemProperty(KEY_EMUI_VERSION_NAME, "") : ""; + } + + /** + * 判断是否为emui3.1版本 + * Is emui 3 1 boolean. + * + * @return the boolean + */ + public static boolean isEMUI3_1() { + String property = getEMUIVersion(); + if ("EmotionUI 3".equals(property) || property.contains("EmotionUI_3.1")) { + return true; + } + return false; + } + + /** + * 判断是否为emui3.0版本 + * Is emui 3 1 boolean. + * + * @return the boolean + */ + public static boolean isEMUI3_0() { + String property = getEMUIVersion(); + if (property.contains("EmotionUI_3.0")) { + return true; + } + return false; + } + + /** + * 判断是否为flymeOS + * Is flyme os boolean. + * + * @return the boolean + */ + public static boolean isFlymeOS() { + return getFlymeOSFlag().toLowerCase().contains("flyme"); + } + + /** + * 判断flymeOS的版本是否大于等于4 + * Is flyme os 4 later boolean. + * + * @return the boolean + */ + public static boolean isFlymeOS4Later() { + String version = getFlymeOSVersion(); + int num; + if (!version.isEmpty()) { + try { + if (version.toLowerCase().contains("os")) { + num = Integer.valueOf(version.substring(9, 10)); + } else { + num = Integer.valueOf(version.substring(6, 7)); + } + return num >= 4; + } catch (NumberFormatException e) { + return false; + } + } + return false; + } + + /** + * 判断flymeOS的版本是否等于5 + * Is flyme os 5 boolean. + * + * @return the boolean + */ + public static boolean isFlymeOS5() { + String version = getFlymeOSVersion(); + int num; + if (!version.isEmpty()) { + try { + if (version.toLowerCase().contains("os")) { + num = Integer.valueOf(version.substring(9, 10)); + } else { + num = Integer.valueOf(version.substring(6, 7)); + } + return num == 5; + } catch (NumberFormatException e) { + return false; + } + } + return false; + } + + + /** + * 得到flymeOS的版本 + * Gets flyme os version. + * + * @return the flyme os version + */ + public static String getFlymeOSVersion() { + return isFlymeOS() ? getSystemProperty(KEY_DISPLAY, "") : ""; + } + + private static String getFlymeOSFlag() { + return getSystemProperty(KEY_DISPLAY, ""); + } + + private static String getSystemProperty(String key, String defaultValue) { + try { + Class clz = Class.forName("android.os.SystemProperties"); + Method get = clz.getMethod("get", String.class, String.class); + return (String) get.invoke(clz, key, defaultValue); + } catch (Exception e) { + e.printStackTrace(); + } + return defaultValue; + } +} diff --git a/library/src/main/java/com/wheelpicker/core/ScrollWheelPicker.java b/library/src/main/java/com/wheelpicker/core/ScrollWheelPicker.java index 8b9527a..7e1c95f 100644 --- a/library/src/main/java/com/wheelpicker/core/ScrollWheelPicker.java +++ b/library/src/main/java/com/wheelpicker/core/ScrollWheelPicker.java @@ -11,274 +11,291 @@ import com.wheelpicker.anim.Animation; +/* + * Copyright (C) 2017 重庆呼我出行网络科技有限公司 + * 版权所有 + * + * 功能描述: + * + * 作者:huangyong + * 创建时间:2017/11/26 + * + * 修改人: + * 修改描述: + * 修改日期 + */ public abstract class ScrollWheelPicker extends AbstractWheelPicker { - /** - * Idle - */ - public static final int SCROLL_STATE_IDLE = 0; - /** - * Down - */ - public static final int SCROLL_STATE_DOWN = 1; - - /** - * Dragging - */ - public static final int SCROLL_STATE_DRAGGING = 2; - - /** - * Scrolling - */ - public static final int SCROLL_STATE_SCROLLING = 3; - - public static final int VETTAICL = 1 << 1; - public static final int HORIZENTAL = 1 << 2; - - private static final int CORRECT_ANIMATION_DURATION = 250; - private static final float MOVE_FACTOR = 0.4F; - - protected static int mOrientation = VETTAICL; - protected int mOverOffset; - - protected WheelPickerImpl mWheelPickerImpl; - - private CorrectAnimRunnable mCorrectRunnable; - private FlingRunnable mFlingRunnable; - private TransLateAnim mAnimController; - - private int mMinScrollOffset; - private int mMaxScrollOffset; - - private int mScrollState = SCROLL_STATE_IDLE; - - public ScrollWheelPicker(Context context) { - super(context); - } - - public ScrollWheelPicker(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ScrollWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void instantiation() { - super.instantiation(); - - mWheelPickerImpl = new WheelPickerImpl(mOrientation); - init(); - } - - private void init() { - mAnimController = new TransLateAnim(); - mFlingRunnable = new FlingRunnable(getContext()); - mCorrectRunnable = new CorrectAnimRunnable(); - } - - protected void setOrientation(int orientation) { - mOrientation = orientation; - } - - public void setScrollRange(int minOffset, int maxOffset) { - mMinScrollOffset = minOffset; - mMaxScrollOffset = maxOffset; - } - - @Override + /** + * Idle + */ + public static final int SCROLL_STATE_IDLE = 0; + /** + * Down + */ + public static final int SCROLL_STATE_DOWN = 1; + + /** + * Dragging + */ + public static final int SCROLL_STATE_DRAGGING = 2; + + /** + * Scrolling + */ + public static final int SCROLL_STATE_SCROLLING = 3; + + public static final int VETTAICL = 1 << 1; + public static final int HORIZENTAL = 1 << 2; + + private static final int CORRECT_ANIMATION_DURATION = 250; + private static final float MOVE_FACTOR = 0.4F; + + protected static int mOrientation = VETTAICL; + protected int mOverOffset; + + protected WheelPickerImpl mWheelPickerImpl; + + private CorrectAnimRunnable mCorrectRunnable; + private FlingRunnable mFlingRunnable; + private TransLateAnim mAnimController; + + private int mMinScrollOffset; + private int mMaxScrollOffset; + + private int mScrollState = SCROLL_STATE_IDLE; + + public ScrollWheelPicker(Context context) { + super(context); + } + + public ScrollWheelPicker(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ScrollWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void instantiation() { + super.instantiation(); + + mWheelPickerImpl = new WheelPickerImpl(mOrientation); + init(); + } + + private void init() { + mAnimController = new TransLateAnim(); + mFlingRunnable = new FlingRunnable(getContext()); + mCorrectRunnable = new CorrectAnimRunnable(); + } + + protected void setOrientation(int orientation) { + mOrientation = orientation; + } + + public void setScrollRange(int minOffset, int maxOffset) { + mMinScrollOffset = minOffset; + mMaxScrollOffset = maxOffset; + } + + @Override protected void resetScroll() { - if (mFlingRunnable != null) { + if (mFlingRunnable != null) { mFlingRunnable.resetScroller(getContext()); } } @Override - protected void onTouchDown(MotionEvent event) { - mFlingRunnable.stop(); - mCorrectRunnable.stop(); - mScrollState = SCROLL_STATE_DOWN; - } - - @Override - protected void onTouchMove(MotionEvent event) { - mScrollState = SCROLL_STATE_DRAGGING; - mCurrentX = (mCurrentX + mDeltaX); - mCurrentY = (mCurrentY + mDeltaY * MOVE_FACTOR); - - onScrolling(mCurrentX, mCurrentY, false); - } - - @Override - protected void onTouchUp(MotionEvent event) { - mScrollState = SCROLL_STATE_SCROLLING; - mFlingRunnable.fling(); - } - - @Override - protected void onTouchCancel(MotionEvent event) { - mFlingRunnable.stop(); - mScrollState = SCROLL_STATE_IDLE; - } - - /** - * Fling animation - * - */ - private class FlingRunnable implements Runnable { - protected WheelScroller mScroller; - - private FlingRunnable(Context context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - mScroller = new OverScrollerCompat(context); - } else { - mScroller = new ScrollerCompat(context); - } - } - - public void run() { - mScroller.computeScrollOffset(); - if (!mScroller.isFinished()) { - ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); - } else { - mCurrentX = mScroller.getFinalX(); - mCurrentY = mScroller.getFinalY(); - } - - onScrolling(mScroller.getCurrX(), mScroller.getCurrY(), - mScrollState == SCROLL_STATE_SCROLLING && mScroller.isFinished()); - } - - public void stop() { - if (!mScroller.isFinished()) - mScroller.abortAnimation(); - } - - public void fling() { - if (mOrientation == HORIZENTAL) { - mScroller.fling((int) (mCurrentX), 0, (int) mTracker.getXVelocity(), 0, mMinScrollOffset, mMaxScrollOffset, 0, 0, mOverOffset, 0); - } else { - mScroller.fling(0, (int) (mCurrentY), 0, (int) mTracker.getYVelocity(), 0, 0, mMinScrollOffset, mMaxScrollOffset, 0, mOverOffset); - } - ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); - } - - public void resetScroller(Context context) { - if (mCurrentX == 0 && mCurrentY == 0) { - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - mScroller.startScroll(x, y, -x, -y, 10); //scroll back in short time - } else { - mScroller.setFinalX(0); - mScroller.setFinalY(0); - } - - mCurrentX = 0; - mCurrentY = 0; - } - } - - /** - * start correction animation - * @param transLateX - * @param transLateY - */ - protected void startCorrectAnimation(float transLateX, float transLateY) { - if (mAnimController == null) { - mAnimController = new TransLateAnim(); - } else { - mAnimController.forceStop(); - } - if (mOrientation == HORIZENTAL) { - if(transLateX == 0) { - mScrollState = SCROLL_STATE_IDLE; - return; - } - } else { - if (transLateY == 0) { - mScrollState = SCROLL_STATE_IDLE; - return; - } - } - - mAnimController.setTransLate(transLateX, transLateY); - - ViewCompat.postOnAnimation(ScrollWheelPicker.this, mCorrectRunnable); - mAnimController.start(); - } - - /** - * stop correction animation - */ - protected void stopCorrectAnimation() { - mCorrectRunnable.stop(); - } - - /** - * The animation runnable of correcting the location - */ - private class CorrectAnimRunnable implements Runnable { - - public void run() { - boolean running = mAnimController.calculate(SystemClock.uptimeMillis()); - if (running) { - onScrolling(mCurrentX, mCurrentY, false); - ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); - } else { - mCurrentX = mAnimController.getFinalX(); - mCurrentY = mAnimController.getFinalY(); - onScrolling(mCurrentX, mCurrentY, true); - - mScrollState = SCROLL_STATE_IDLE; - } - } - - public void stop() { - mAnimController.forceStop(); - } - } - - /** - * Translate animation - */ - private class TransLateAnim extends Animation { - private float mStartX; - private float mStartY; - private float mTransLateX; - private float mTransLateY; - - public TransLateAnim() { - setDuration(CORRECT_ANIMATION_DURATION); - setInterpolator(new DecelerateInterpolator()); - } - - public void setTransLate(float transLateX, float transLateY) { - mTransLateX = transLateX; - mTransLateY = transLateY; - mStartX = mCurrentX; - mStartY = mCurrentY; - } - - public float getFinalX() { - return mStartX + mCurrentX; - } - - public float getFinalY() { - return mStartY + mTransLateY; - } - - protected void onCalculate(float factor) { - if (mOrientation == HORIZENTAL) { - mCurrentX = (mStartX + (int) (factor * mTransLateX)); - } else { - mCurrentY = (mStartY + factor * mTransLateY); - } - } - } - - protected abstract void onScrolling(float offsetX, float offsetY, boolean isFinshed); + protected void onTouchDown(MotionEvent event) { + mFlingRunnable.stop(); + mCorrectRunnable.stop(); + mScrollState = SCROLL_STATE_DOWN; + } + + @Override + protected void onTouchMove(MotionEvent event) { + mScrollState = SCROLL_STATE_DRAGGING; + mCurrentX = (mCurrentX + mDeltaX); + mCurrentY = (mCurrentY + mDeltaY * MOVE_FACTOR); + + onScrolling(mCurrentX, mCurrentY, false); + } + + @Override + protected void onTouchUp(MotionEvent event) { + mScrollState = SCROLL_STATE_SCROLLING; + mFlingRunnable.fling(); + } + + @Override + protected void onTouchCancel(MotionEvent event) { + mFlingRunnable.stop(); + mScrollState = SCROLL_STATE_IDLE; + } + + /** + * Fling animation + */ + private class FlingRunnable implements Runnable { + protected WheelScroller mScroller; + + private FlingRunnable(Context context) { + if (OSUtils.isEMUI()) { + mScroller = new ScrollerCompat(context); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + mScroller = new OverScrollerCompat(context); + } else { + mScroller = new ScrollerCompat(context); + } + } + } + + public void run() { + mScroller.computeScrollOffset(); + if (!mScroller.isFinished()) { + ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); + } else { + mCurrentX = mScroller.getFinalX(); + mCurrentY = mScroller.getFinalY(); + } + + onScrolling(mScroller.getCurrX(), mScroller.getCurrY(), + mScrollState == SCROLL_STATE_SCROLLING && mScroller.isFinished()); + } + + public void stop() { + if (!mScroller.isFinished()) + mScroller.abortAnimation(); + } + + public void fling() { + if (mOrientation == HORIZENTAL) { + mScroller.fling((int) (mCurrentX), 0, (int) mTracker.getXVelocity(), 0, mMinScrollOffset, mMaxScrollOffset, 0, 0, mOverOffset, 0); + } else { + mScroller.fling(0, (int) (mCurrentY), 0, (int) mTracker.getYVelocity(), 0, 0, mMinScrollOffset, mMaxScrollOffset, 0, mOverOffset); + } + ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); + } + + public void resetScroller(Context context) { + if (mCurrentX == 0 && mCurrentY == 0) { + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + mScroller.startScroll(x, y, -x, -y, 10); //scroll back in short time + } else { + mScroller.setFinalX(0); + mScroller.setFinalY(0); + } + + mCurrentX = 0; + mCurrentY = 0; + } + } + + /** + * start correction animation + * + * @param transLateX + * @param transLateY + */ + protected void startCorrectAnimation(float transLateX, float transLateY) { + if (mAnimController == null) { + mAnimController = new TransLateAnim(); + } else { + mAnimController.forceStop(); + } + if (mOrientation == HORIZENTAL) { + if (transLateX == 0) { + mScrollState = SCROLL_STATE_IDLE; + return; + } + } else { + if (transLateY == 0) { + mScrollState = SCROLL_STATE_IDLE; + return; + } + } + + mAnimController.setTransLate(transLateX, transLateY); + + ViewCompat.postOnAnimation(ScrollWheelPicker.this, mCorrectRunnable); + mAnimController.start(); + } + + /** + * stop correction animation + */ + protected void stopCorrectAnimation() { + mCorrectRunnable.stop(); + } + + /** + * The animation runnable of correcting the location + */ + private class CorrectAnimRunnable implements Runnable { + + public void run() { + boolean running = mAnimController.calculate(SystemClock.uptimeMillis()); + if (running) { + onScrolling(mCurrentX, mCurrentY, false); + ViewCompat.postOnAnimation(ScrollWheelPicker.this, this); + } else { + mCurrentX = mAnimController.getFinalX(); + mCurrentY = mAnimController.getFinalY(); + onScrolling(mCurrentX, mCurrentY, true); + + mScrollState = SCROLL_STATE_IDLE; + } + } + + public void stop() { + mAnimController.forceStop(); + } + } + + /** + * Translate animation + */ + private class TransLateAnim extends Animation { + private float mStartX; + private float mStartY; + private float mTransLateX; + private float mTransLateY; + + public TransLateAnim() { + setDuration(CORRECT_ANIMATION_DURATION); + setInterpolator(new DecelerateInterpolator()); + } + + public void setTransLate(float transLateX, float transLateY) { + mTransLateX = transLateX; + mTransLateY = transLateY; + mStartX = mCurrentX; + mStartY = mCurrentY; + } + + public float getFinalX() { + return mStartX + mCurrentX; + } + + public float getFinalY() { + return mStartY + mTransLateY; + } + + protected void onCalculate(float factor) { + if (mOrientation == HORIZENTAL) { + mCurrentX = (mStartX + (int) (factor * mTransLateX)); + } else { + mCurrentY = (mStartY + factor * mTransLateY); + } + } + } + + protected abstract void onScrolling(float offsetX, float offsetY, boolean isFinshed); } diff --git a/library/src/main/java/com/wheelpicker/widget/TextWheelPicker.java b/library/src/main/java/com/wheelpicker/widget/TextWheelPicker.java index c15b8b9..0d8e1ba 100644 --- a/library/src/main/java/com/wheelpicker/widget/TextWheelPicker.java +++ b/library/src/main/java/com/wheelpicker/widget/TextWheelPicker.java @@ -11,249 +11,260 @@ import com.wheelpicker.core.OnWheelPickedListener; -/** - * The wheel picker for text +/* + * Copyright (C) 2017 重庆呼我出行网络科技有限公司 + * 版权所有 + * + * 功能描述:The wheel picker for text + * + * 作者:huangyong + * 创建时间:2017/11/26 + * + * 修改人: + * 修改描述: + * 修改日期 */ public class TextWheelPicker extends AbstractTextWheelPicker { - private final static String TAG = "TextWheelPicker"; - private final static float DEPTH_FACTOR = 0.6F; //0 ~ 1.0F - private final Camera mCamera = new Camera(); - private final Matrix mRotateMatrix = new Matrix(); - private final Matrix mDepthMatrix = new Matrix(); - - private int mRadius; - - private int mOldOffsetItemIndex = 0; - private int mOffsetItemIndex = 0; - private float mOffsetItemDelta = 0; - - private float mShadowOffset = 0; - private float mLineOffset = 0; - - private float mRelRadius; - - private OnWheelPickedListener mOnWheelPickedListener; - - public TextWheelPicker(Context context) { - super(context); - } - - public TextWheelPicker(Context context, int id) { - super(context); - setId(id); - } - - public TextWheelPicker(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public TextWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void computeWheelSize() { - mRadius = mWheelPickerImpl.computeRadius(mVisibleItemCount, mItemSpace, mItemMaxWidth, mItemMaxHeight); - mUnitDegree = (int) (180 * 1.0F / mVisibleItemCount); - - mWheelContentWidth = mWheelPickerImpl.getWheelWidth(mRadius, mItemMaxWidth); - mWheelContentHeight = mWheelPickerImpl.getWheelHeight(mRadius, mItemMaxHeight); - - mLineOffset = mItemMaxHeight / 2 + mItemSpace * 0.8f; - - mShadowOffset = SHADOW_MAX * mShadowFactor; - mOverOffset = 90; + private final static String TAG = "TextWheelPicker"; + private final static float DEPTH_FACTOR = 0.6F; //0 ~ 1.0F + private final Camera mCamera = new Camera(); + private final Matrix mRotateMatrix = new Matrix(); + private final Matrix mDepthMatrix = new Matrix(); + + private int mRadius; + + private int mOldOffsetItemIndex = 0; + private int mOffsetItemIndex = 0; + private float mOffsetItemDelta = 0; + + private float mShadowOffset = 0; + private float mLineOffset = 0; + + private float mRelRadius; + + private OnWheelPickedListener mOnWheelPickedListener; + + public TextWheelPicker(Context context) { + super(context); + } + + public TextWheelPicker(Context context, int id) { + super(context); + setId(id); + } + + public TextWheelPicker(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public TextWheelPicker(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void computeWheelSize() { + mRadius = mWheelPickerImpl.computeRadius(mVisibleItemCount, mItemSpace, mItemMaxWidth, mItemMaxHeight); + mUnitDegree = (int) (180 * 1.0F / mVisibleItemCount); + + mWheelContentWidth = mWheelPickerImpl.getWheelWidth(mRadius, mItemMaxWidth); + mWheelContentHeight = mWheelPickerImpl.getWheelHeight(mRadius, mItemMaxHeight); + + mLineOffset = mItemMaxHeight / 2 + mItemSpace * 0.8f; + + mShadowOffset = SHADOW_MAX * mShadowFactor; + mOverOffset = 90; mRelRadius = mRadius * DEPTH_FACTOR; - + if (mAdapter != null) { mOldOffsetItemIndex = 0; - + if (mCurrItemIndex < 0) { - mCurrItemIndex = 0; + mCurrItemIndex = 0; } - + if (mCurrItemIndex >= mAdapter.getCount()) { - mCurrItemIndex = mAdapter.getCount() - 1; + mCurrItemIndex = mAdapter.getCount() - 1; } - - setScrollRange(-(mAdapter.getCount() - 1 - mCurrItemIndex) * mUnitDegree, mCurrItemIndex * mUnitDegree); + + setScrollRange(-(mAdapter.getCount() - 1 - mCurrItemIndex) * mUnitDegree, mCurrItemIndex * mUnitDegree); + } + } + + @Override + protected void drawBackground(Canvas canvas) { + if (mAdapter != null && !mAdapter.isEmpty()) { + canvas.drawLine(0, mWheelCenterY - mLineOffset, mViewWidth, + mWheelCenterY - mLineOffset, mLinePaint); + canvas.drawLine(0, mWheelCenterY + mLineOffset, mViewWidth, + mWheelCenterY + mLineOffset, mLinePaint); + } + } + + @Override + protected void drawItems(Canvas canvas) { + if (mAdapter == null || mAdapter.isEmpty()) { + return; } - } - - @Override - protected void drawBackground(Canvas canvas) { - if (mAdapter != null && !mAdapter.isEmpty()) { - canvas.drawLine(0, mWheelCenterY - mLineOffset , mViewWidth, - mWheelCenterY - mLineOffset, mLinePaint); - canvas.drawLine(0, mWheelCenterY + mLineOffset, mViewWidth, - mWheelCenterY + mLineOffset, mLinePaint); - } - } - - @Override - protected void drawItems(Canvas canvas) { - if (mAdapter == null || mAdapter.isEmpty()) { - return; - } - - for (int i = mItemSartIndex; i <= mItemEndIndex; i++) { - float rotateDegree = mUnitDegree * (i - mCurrItemIndex) + mOffsetItemDelta; - if (rotateDegree > 90 || rotateDegree < -90) { - continue; - } - - //为了避免角度太小计算产生误差,所以进行一个校正 - if (Math.abs(rotateDegree) < 0.1f) { - if (rotateDegree < 0) { - rotateDegree = -0.1f; - } else { - rotateDegree = 0.1f; - } - } - - float space = computeSpace(rotateDegree, mRadius); - float relDegree = Math.abs(rotateDegree) / 90; - canvas.save(); - mCamera.save(); - mRotateMatrix.reset(); - - //apply gravity - if (mShadowGravity == SHADOW_RIGHT) { - mCamera.translate(-mShadowOffset, 0, 0); - } else if (mShadowGravity == SHADOW_LEFT) { - mCamera.translate(mShadowOffset, 0, 0); - } - //rotate - mWheelPickerImpl.rotateCamera(mCamera, rotateDegree); - mCamera.getMatrix(mRotateMatrix); - mCamera.restore(); - mWheelPickerImpl.matrixToCenter(mRotateMatrix, space, mWheelCenterX, mWheelCenterY); - //apply gravity - if (mShadowGravity == SHADOW_RIGHT) { - mRotateMatrix.postTranslate(mShadowOffset, 0); - } else if (mShadowGravity == SHADOW_LEFT) { - mRotateMatrix.postTranslate(-mShadowOffset, 0); - } - - float depth = computeDepth(rotateDegree, mRelRadius); - mCamera.save(); - mDepthMatrix.reset(); - mCamera.translate(0, 0, depth); - mCamera.getMatrix(mDepthMatrix); - mCamera.restore(); - mWheelPickerImpl.matrixToCenter(mDepthMatrix, space, mWheelCenterX, mWheelCenterY); - - mRotateMatrix.postConcat(mDepthMatrix); - canvas.concat(mRotateMatrix); - - if (i == getHighLightItem(mCurrItemIndex)) { - mPaint.setAlpha(255); - } else { - mPaint.setAlpha(128 - (int)(128 * relDegree)); - } - draw(canvas, mPaint, mAdapter.getItemText(i), space, mWheelCenterX, mWheelCenterTextY); - canvas.restore(); - } - - } - - @Override - protected void drawForeground(Canvas canvas) { - - } - - public void setOnWheelPickedListener(OnWheelPickedListener listener) { - mOnWheelPickedListener = listener; - } - - @Override - protected void onWheelSelected(int index) { - if (mAdapter != null && index > -1 && index < mAdapter.getCount()) { - if (mOnWheelPickedListener != null) { - mOnWheelPickedListener.onWheelSelected(this, index, mAdapter.getItemText(index)); - } - } else { - Log.i(TAG, "error index:"+index); - } - } - - @Override - public void onScrolling(float offsetX, float offsetY, boolean isFinshed) { - mOffsetItemIndex = (int)(offsetY / mUnitDegree); - mOffsetItemDelta = offsetY % mUnitDegree; - if (mOffsetItemIndex != mOldOffsetItemIndex) { - mCurrItemIndex = mCurrItemIndex - (mOffsetItemIndex - mOldOffsetItemIndex); - } - - mOldOffsetItemIndex = mOffsetItemIndex; - updateItemIndexRange(); - postInvalidate(); - - if (isFinshed) { - correctLocation(mOffsetItemIndex, 0, mOffsetItemDelta); - if (Math.abs(mOffsetItemDelta) < 0.01f ) { - onWheelSelected(mCurrItemIndex); - } - } - } - - @Override - protected void draw(Canvas canvas, Paint paint, String data, float space, float x, float y) { - canvas.drawText(getDrawText(data), x, y + space, paint); - } - - @Override - public int getCurrentItem() { - int currentItem = super.getCurrentItem(); - if (currentItem < 0) { - return 0; - } - - if (mAdapter == null) { - return currentItem; - } - - if (currentItem >= mAdapter.getCount()) { - currentItem = mAdapter.getCount() - 1; - } - - return currentItem; - } - - /** - * 获取高亮显示的item索引 - * @param item - * @return - */ - private int getHighLightItem (int item) { - if (mOffsetItemDelta > 0) { - if (mOffsetItemDelta > mUnitDegree / 2) { - return item - 1; - } else { - return item; - } - } else { - if (Math.abs(mOffsetItemDelta) > mUnitDegree / 2) - return item + 1; - else - return item; - } - } - - private String getDrawText(String data) { - if (data == null) { - return data; - } - - float itemWidth = mItemMaxWidth; - int viewWidth = getMeasuredWidth(); - int len = data.length(); - while (itemWidth > viewWidth && len > 0) { - mPaint.getTextBounds(data, 0, --len, mItemBounds); - itemWidth = mItemBounds.width(); - } - - return data.substring(0, len); - } + + for (int i = mItemSartIndex; i <= mItemEndIndex; i++) { + float rotateDegree = mUnitDegree * (i - mCurrItemIndex) + mOffsetItemDelta; + if (rotateDegree > 90 || rotateDegree < -90) { + continue; + } + + //为了避免角度太小计算产生误差,所以进行一个校正 + if (Math.abs(rotateDegree) < 0.1f) { + if (rotateDegree < 0) { + rotateDegree = -0.1f; + } else { + rotateDegree = 0.1f; + } + } + + float space = computeSpace(rotateDegree, mRadius); + float relDegree = Math.abs(rotateDegree) / 90; + canvas.save(); + mCamera.save(); + mRotateMatrix.reset(); + + //apply gravity + if (mShadowGravity == SHADOW_RIGHT) { + mCamera.translate(-mShadowOffset, 0, 0); + } else if (mShadowGravity == SHADOW_LEFT) { + mCamera.translate(mShadowOffset, 0, 0); + } + //rotate + mWheelPickerImpl.rotateCamera(mCamera, rotateDegree); + mCamera.getMatrix(mRotateMatrix); + mCamera.restore(); + mWheelPickerImpl.matrixToCenter(mRotateMatrix, space, mWheelCenterX, mWheelCenterY); + //apply gravity + if (mShadowGravity == SHADOW_RIGHT) { + mRotateMatrix.postTranslate(mShadowOffset, 0); + } else if (mShadowGravity == SHADOW_LEFT) { + mRotateMatrix.postTranslate(-mShadowOffset, 0); + } + + float depth = computeDepth(rotateDegree, mRelRadius); + mCamera.save(); + mDepthMatrix.reset(); + mCamera.translate(0, 0, depth); + mCamera.getMatrix(mDepthMatrix); + mCamera.restore(); + mWheelPickerImpl.matrixToCenter(mDepthMatrix, space, mWheelCenterX, mWheelCenterY); + + mRotateMatrix.postConcat(mDepthMatrix); + canvas.concat(mRotateMatrix); + + if (i == getHighLightItem(mCurrItemIndex)) { + mPaint.setAlpha(255); + } else { + mPaint.setAlpha(128 - (int) (128 * relDegree)); + } + draw(canvas, mPaint, mAdapter.getItemText(i), space, mWheelCenterX, mWheelCenterTextY); + canvas.restore(); + } + + } + + @Override + protected void drawForeground(Canvas canvas) { + + } + + public void setOnWheelPickedListener(OnWheelPickedListener listener) { + mOnWheelPickedListener = listener; + } + + @Override + protected void onWheelSelected(int index) { + if (mAdapter != null && index > -1 && index < mAdapter.getCount()) { + if (mOnWheelPickedListener != null) { + mOnWheelPickedListener.onWheelSelected(this, index, mAdapter.getItemText(index)); + } + } else { + Log.i(TAG, "error index:" + index); + } + } + + @Override + public void onScrolling(float offsetX, float offsetY, boolean isFinshed) { + mOffsetItemIndex = (int) (offsetY / mUnitDegree); + mOffsetItemDelta = offsetY % mUnitDegree; + if (mOffsetItemIndex != mOldOffsetItemIndex) { + mCurrItemIndex = mCurrItemIndex - (mOffsetItemIndex - mOldOffsetItemIndex); + } + + mOldOffsetItemIndex = mOffsetItemIndex; + updateItemIndexRange(); + postInvalidate(); + + if (isFinshed) { + correctLocation(mOffsetItemIndex, 0, mOffsetItemDelta); + if (Math.abs(mOffsetItemDelta) < 0.01f) { + onWheelSelected(mCurrItemIndex); + } + } + } + + @Override + protected void draw(Canvas canvas, Paint paint, String data, float space, float x, float y) { + canvas.drawText(getDrawText(data), x, y + space, paint); + } + + @Override + public int getCurrentItem() { + int currentItem = super.getCurrentItem(); + if (currentItem < 0) { + return 0; + } + + if (mAdapter == null) { + return currentItem; + } + + if (currentItem >= mAdapter.getCount()) { + currentItem = mAdapter.getCount() - 1; + } + + return currentItem; + } + + /** + * 获取高亮显示的item索引 + * + * @param item + * @return + */ + private int getHighLightItem(int item) { + if (mOffsetItemDelta > 0) { + if (mOffsetItemDelta > mUnitDegree / 2) { + return item - 1; + } else { + return item; + } + } else { + if (Math.abs(mOffsetItemDelta) > mUnitDegree / 2) + return item + 1; + else + return item; + } + } + + private String getDrawText(String data) { + if (data == null) { + return data; + } + + float itemWidth = mItemMaxWidth; + int viewWidth = getMeasuredWidth(); + int len = data.length(); + while (itemWidth > viewWidth && len > 0) { + mPaint.getTextBounds(data, 0, --len, mItemBounds); + itemWidth = mItemBounds.width(); + } + + return data.substring(0, len); + } }