总共分为六步:
第一步 : 定义一个WheelPicker 类把下面代码拷贝进去
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;
import com.example.myapplication.R;
import java.util.Arrays;
import java.util.List;
/**
* 滚轮选择器
* <p>
* WheelPicker
*
* @author AigeStudio 2015-12-12
* @author AigeStudio 2016-06-17
* 更新项目结构
* <p>
* New project structure
* @version 1.1.0
*/
public class WheelPicker extends View implements IDebug, IWheelPicker, Runnable {
/**
* 滚动状态标识值
*
* @see OnWheelChangeListener#onWheelScrollStateChanged(int)
*/
public static final int SCROLL_STATE_IDLE = 0, SCROLL_STATE_DRAGGING = 1,
SCROLL_STATE_SCROLLING = 2;
/**
* 数据项对齐方式标识值
*
* @see #setItemAlign(int)
*/
public static final int ALIGN_CENTER = 0, ALIGN_LEFT = 1, ALIGN_RIGHT = 2;
private static final String TAG = WheelPicker.class.getSimpleName();
private final Handler mHandler = new Handler();
private Paint mPaint;
private Scroller mScroller;
private VelocityTracker mTracker;
/**
* Determines whether the current scrolling animation is triggered by touchEvent or setSelectedItemPosition.
* User added eventListeners will only be fired after touchEvents.
*/
private boolean isTouchTriggered;
/**
* 相关监听器
*
* @see OnWheelChangeListener,OnItemSelectedListener
*/
private OnItemSelectedListener mOnItemSelectedListener;
private OnWheelChangeListener mOnWheelChangeListener;
private Rect mRectDrawn;
private Rect mRectIndicatorHead, mRectIndicatorFoot;
private Rect mRectCurrentItem;
private Camera mCamera;
private Matrix mMatrixRotate, mMatrixDepth;
/**
* 数据源
*/
private List mData;
/**
* 最宽的文本
*
* @see #setMaximumWidthText(String)
*/
private String mMaxWidthText;
/**
* 滚轮选择器中可见的数据项数量和滚轮选择器将会绘制的数据项数量
*
* @see #setVisibleItemCount(int)
*/
private int mVisibleItemCount, mDrawnItemCount;
/**
* 滚轮选择器将会绘制的Item数量的一半
*/
private int mHalfDrawnItemCount;
/**
* 单个文本最大宽高
*/
private int mTextMaxWidth, mTextMaxHeight;
/**
* 数据项文本颜色以及被选中的数据项文本颜色
*
* @see #setItemTextColor(int)
* @see #setSelectedItemTextColor(int)
*/
private int mItemTextColor, mSelectedItemTextColor;
/**
* 数据项文本尺寸
*
* @see #setItemTextSize(int)
*/
private int mItemTextSize;
/**
* 指示器尺寸
*
* @see #setIndicatorSize(int)
*/
private int mIndicatorSize;
/**
* 指示器颜色
*
* @see #setIndicatorColor(int)
*/
private int mIndicatorColor;
/**
* 幕布颜色
*
* @see #setCurtainColor(int)
*/
private int mCurtainColor;
/**
* 数据项之间间距
*
* @see #setItemSpace(int)
*/
private int mItemSpace;
/**
* 数据项对齐方式
*
* @see #setItemAlign(int)
*/
private int mItemAlign;
/**
* 滚轮选择器单个数据项高度以及单个数据项一半的高度
*/
private int mItemHeight, mHalfItemHeight;
/**
* 滚轮选择器内容区域高度的一半
*/
private int mHalfWheelHeight;
/**
* 当前被选中的数据项所显示的数据在数据源中的位置
*
* @see #setSelectedItemPosition(int)
*/
private int mSelectedItemPosition;
/**
* 当前被选中的数据项所显示的数据在数据源中的位置
*
* @see #getCurrentItemPosition()
*/
private int mCurrentItemPosition;
/**
* 滚轮滑动时可以滑动到的最小/最大的Y坐标
*/
private int mMinFlingY, mMaxFlingY;
/**
* 滚轮滑动时的最小/最大速度
*/
private int mMinimumVelocity = 50, mMaximumVelocity = 8000;
/**
* 滚轮选择器中心坐标
*/
private int mWheelCenterX, mWheelCenterY;
/**
* 滚轮选择器绘制中心坐标
*/
private int mDrawnCenterX, mDrawnCenterY;
/**
* 滚轮选择器视图区域在Y轴方向上的偏移值
*/
private int mScrollOffsetY;
/**
* 滚轮选择器中最宽或最高的文本在数据源中的位置
*/
private int mTextMaxWidthPosition;
/**
* 用户手指上一次触摸事件发生时事件Y坐标
*/
private int mLastPointY;
/**
* 手指触摸屏幕时事件点的Y坐标
*/
private int mDownPointY;
/**
* 点击与触摸的切换阀值
*/
private int mTouchSlop = 8;
/**
* 滚轮选择器的每一个数据项文本是否拥有相同的宽度
*
* @see #setSameWidth(boolean)
*/
private boolean hasSameWidth;
/**
* 是否显示指示器
*
* @see #setIndicator(boolean)
*/
private boolean hasIndicator;
/**
* 是否显示幕布
*
* @see #setCurtain(boolean)
*/
private boolean hasCurtain;
/**
* 是否显示空气感效果
*
* @see #setAtmospheric(boolean)
*/
private boolean hasAtmospheric;
/**
* 数据是否循环展示
*
* @see #setCyclic(boolean)
*/
private boolean isCyclic;
/**
* 滚轮是否为卷曲效果
*
* @see #setCurved(boolean)
*/
private boolean isCurved;
/**
* 是否为点击模式
*/
private boolean isClick;
/**
* 是否为强制结束滑动
*/
private boolean isForceFinishScroll;
/**
* Font typeface path from assets
*/
private String fontPath;
private boolean isDebug;
public WheelPicker(Context context) {
this(context, null);
}
public WheelPicker(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WheelPicker);
int idData = a.getResourceId(R.styleable.WheelPicker_wheel_data, 0);
mData = Arrays.asList(getResources()
.getStringArray(idData == 0 ? R.array.WheelArrayDefault : idData));
mItemTextSize = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_text_size,
getResources().getDimensionPixelSize(R.dimen.WheelItemTextSize));
mVisibleItemCount = a.getInt(R.styleable.WheelPicker_wheel_visible_item_count, 7);
mSelectedItemPosition = a.getInt(R.styleable.WheelPicker_wheel_selected_item_position, 0);
hasSameWidth = a.getBoolean(R.styleable.WheelPicker_wheel_same_width, false);
mTextMaxWidthPosition =
a.getInt(R.styleable.WheelPicker_wheel_maximum_width_text_position, -1);
mMaxWidthText = a.getString(R.styleable.WheelPicker_wheel_maximum_width_text);
mSelectedItemTextColor = a.getColor
(R.styleable.WheelPicker_wheel_selected_item_text_color, -1);
mItemTextColor = a.getColor(R.styleable.WheelPicker_wheel_item_text_color, 0xFF888888);
mItemSpace = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_item_space,
getResources().getDimensionPixelSize(R.dimen.WheelItemSpace));
isCyclic = a.getBoolean(R.styleable.WheelPicker_wheel_cyclic, false);
hasIndicator = a.getBoolean(R.styleable.WheelPicker_wheel_indicator, false);
mIndicatorColor = a.getColor(R.styleable.WheelPicker_wheel_indicator_color, 0xFFEE3333);
mIndicatorSize = a.getDimensionPixelSize(R.styleable.WheelPicker_wheel_indicator_size,
getResources().getDimensionPixelSize(R.dimen.WheelIndicatorSize));
hasCurtain = a.getBoolean(R.styleable.WheelPicker_wheel_curtain, false);
mCurtainColor = a.getColor(R.styleable.WheelPicker_wheel_curtain_color, 0x88FFFFFF);
hasAtmospheric = a.getBoolean(R.styleable.WheelPicker_wheel_atmospheric, false);
isCurved = a.getBoolean(R.styleable.WheelPicker_wheel_curved, false);
mItemAlign = a.getInt(R.styleable.WheelPicker_wheel_item_align, ALIGN_CENTER);
fontPath = a.getString(R.styleable.WheelPicker_wheel_font_path);
a.recycle();
// 可见数据项改变后更新与之相关的参数
// Update relevant parameters when the count of visible item changed
updateVisibleItemCount();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.LINEAR_TEXT_FLAG);
mPaint.setTextSize(mItemTextSize);
if (fontPath != null) {
Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontPath);
setTypeface(typeface);
}
// 更新文本对齐方式
// Update alignment of text
updateItemTextAlign();
// 计算文本尺寸
// Correct sizes of text
computeTextSize();
mScroller = new Scroller(getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {
ViewConfiguration conf = ViewConfiguration.get(getContext());
mMinimumVelocity = conf.getScaledMinimumFlingVelocity();
mMaximumVelocity = conf.getScaledMaximumFlingVelocity();
mTouchSlop = conf.getScaledTouchSlop();
}
mRectDrawn = new Rect();
mRectIndicatorHead = new Rect();
mRectIndicatorFoot = new Rect();
mRectCurrentItem = new Rect();
mCamera = new Camera();
mMatrixRotate = new Matrix();
mMatrixDepth = new Matrix();
}
private void updateVisibleItemCount() {
if (mVisibleItemCount < 2)
throw new ArithmeticException("Wheel's visible item count can not be less than 2!");
// 确保滚轮选择器可见数据项数量为奇数
// Be sure count of visible item is odd number
if (mVisibleItemCount % 2 == 0)
mVisibleItemCount += 1;
mDrawnItemCount = mVisibleItemCount + 2;
mHalfDrawnItemCount = mDrawnItemCount / 2;
}
private void computeTextSize() {
mTextMaxWidth = mTextMaxHeight = 0;
if (hasSameWidth) {
mTextMaxWidth = (int) mPaint.measureText(String.valueOf(mData.get(0)));
} else if (isPosInRang(mTextMaxWidthPosition)) {
mTextMaxWidth = (int) mPaint.measureText
(String.valueOf(mData.get(mTextMaxWidthPosition)));
} else if (!TextUtils.isEmpty(mMaxWidthText)) {
mTextMaxWidth = (int) mPaint.measureText(mMaxWidthText);
} else {
for (Object obj : mData) {
String text = String.valueOf(obj);
int width = (int) mPaint.measureText(text);
mTextMaxWidth = Math.max(mTextMaxWidth, width);
}
}
Paint.FontMetrics metrics = mPaint.getFontMetrics();
mTextMaxHeight = (int) (metrics.bottom - metrics.top);
}
private void updateItemTextAlign() {
switch (mItemAlign) {
case ALIGN_LEFT:
mPaint.setTextAlign(Paint.Align.LEFT);
break;
case ALIGN_RIGHT:
mPaint.setTextAlign(Paint.Align.RIGHT);
break;
default:
mPaint.setTextAlign(Paint.Align.CENTER);
break;
}
}
@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);
// 计算原始内容尺寸
// Correct sizes of original content
int resultWidth = mTextMaxWidth;
int resultHeight = mTextMaxHeight * mVisibleItemCount + mItemSpace * (mVisibleItemCount - 1);
// 如果开启弯曲效果则需要重新计算弯曲后的尺寸
// Correct view sizes again if curved is enable
if (isCurved) {
resultHeight = (int) (2 * resultHeight / Math.PI);
}
if (isDebug)
Log.i(TAG, "Wheel's content size is (" + resultWidth + ":" + resultHeight + ")");
// 考虑内边距对尺寸的影响
// Consideration padding influence the view sizes
resultWidth += getPaddingLeft() + getPaddingRight();
resultHeight += getPaddingTop() + getPaddingBottom();
if (isDebug)
Log.i(TAG, "Wheel's size is (" + resultWidth + ":" + resultHeight + ")");
// 考虑父容器对尺寸的影响
// Consideration sizes of parent can influence the view sizes
resultWidth = measureSize(modeWidth, sizeWidth, resultWidth);
resultHeight = measureSize(modeHeight, sizeHeight, resultHeight);
setMeasuredDimension(resultWidth, resultHeight);
}
private 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) {
// 设置内容区域
// Set content region
mRectDrawn.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(),
getHeight() - getPaddingBottom());
if (isDebug)
Log.i(TAG, "Wheel's drawn rect size is (" + mRectDrawn.width() + ":" +
mRectDrawn.height() + ") and location is (" + mRectDrawn.left + ":" +
mRectDrawn.top + ")");
// 获取内容区域中心坐标
// Get the center coordinates of content region
mWheelCenterX = mRectDrawn.centerX();
mWheelCenterY = mRectDrawn.centerY();
// 计算数据项绘制中心
// Correct item drawn center
computeDrawnCenter();
mHalfWheelHeight = mRectDrawn.height() / 2;
mItemHeight = mRectDrawn.height() / mVisibleItemCount;
mHalfItemHeight = mItemHeight / 2;
// 初始化滑动最大坐标
// Initialize fling max Y-coordinates
computeFlingLimitY();
// 计算指示器绘制区域
// Correct region of indicator
computeIndicatorRect();
// 计算当前选中的数据项区域
// Correct region of current select item
computeCurrentItemRect();
}
private void computeDrawnCenter() {
switch (mItemAlign) {
case ALIGN_LEFT:
mDrawnCenterX = mRectDrawn.left;
break;
case ALIGN_RIGHT:
mDrawnCenterX = mRectDrawn.right;
break;
default:
mDrawnCenterX = mWheelCenterX;
break;
}
mDrawnCenterY = (int) (mWheelCenterY - ((mPaint.ascent() + mPaint.descent()) / 2));
}
private void computeFlingLimitY() {
int currentItemOffset = mSelectedItemPosition * mItemHeight;
mMinFlingY = isCyclic ? Integer.MIN_VALUE :
-mItemHeight * (mData.size() - 1) + currentItemOffset;
mMaxFlingY = isCyclic ? Integer.MAX_VALUE : currentItemOffset;
}
private void computeIndicatorRect() {
if (!hasIndicator) return;
int halfIndicatorSize = mIndicatorSize / 2;
int indicatorHeadCenterY = mWheelCenterY + mHalfItemHeight;
int indicatorFootCenterY = mWheelCenterY - mHalfItemHeight;
mRectIndicatorHead.set(mRectDrawn.left, indicatorHeadCenterY - halfIndicatorSize,
mRectDrawn.right, indicatorHeadCenterY + halfIndicatorSize);
mRectIndicatorFoot.set(mRectDrawn.left, indicatorFootCenterY - halfIndicatorSize,
mRectDrawn.right, indicatorFootCenterY + halfIndicatorSize);
}
private void computeCurrentItemRect() {
if (!hasCurtain && mSelectedItemTextColor == -1) return;
mRectCurrentItem.set(mRectDrawn.left, mWheelCenterY - mHalfItemHeight, mRectDrawn.right,
mWheelCenterY + mHalfItemHeight);
}
@Override
protected void onDraw(Canvas canvas) {
if (null != mOnWheelChangeListener)
mOnWheelChangeListener.onWheelScrolled(mScrollOffsetY);
if(mData.size() == 0)
return;
int drawnDataStartPos = -mScrollOffsetY / mItemHeight - mHalfDrawnItemCount;
for (int drawnDataPos = drawnDataStartPos + mSelectedItemPosition,
drawnOffsetPos = -mHalfDrawnItemCount;
drawnDataPos < drawnDataStartPos + mSelectedItemPosition + mDrawnItemCount;
drawnDataPos++, drawnOffsetPos++) {
String data = "";
if (isCyclic) {
int actualPos = drawnDataPos % mData.size();
actualPos = actualPos < 0 ? (actualPos + mData.size()) : actualPos;
data = String.valueOf(mData.get(actualPos));
} else {
if (isPosInRang(drawnDataPos))
data = String.valueOf(mData.get(drawnDataPos));
}
mPaint.setColor(mItemTextColor);
mPaint.setStyle(Paint.Style.FILL);
int mDrawnItemCenterY = mDrawnCenterY + (drawnOffsetPos * mItemHeight) +
mScrollOffsetY % mItemHeight;
int distanceToCenter = 0;
if (isCurved) {
// 计算数据项绘制中心距离滚轮中心的距离比率
// Correct ratio of item's drawn center to wheel center
float ratio = (mDrawnCenterY - Math.abs(mDrawnCenterY - mDrawnItemCenterY) -
mRectDrawn.top) * 1.0F / (mDrawnCenterY - mRectDrawn.top);
// 计算单位
// Correct unit
int unit = 0;
if (mDrawnItemCenterY > mDrawnCenterY)
unit = 1;
else if (mDrawnItemCenterY < mDrawnCenterY)
unit = -1;
float degree = (-(1 - ratio) * 90 * unit);
if (degree < -90) degree = -90;
if (degree > 90) degree = 90;
distanceToCenter = computeSpace((int) degree);
int transX = mWheelCenterX;
switch (mItemAlign) {
case ALIGN_LEFT:
transX = mRectDrawn.left;
break;
case ALIGN_RIGHT:
transX = mRectDrawn.right;
break;
}
int transY = mWheelCenterY - distanceToCenter;
mCamera.save();
mCamera.rotateX(degree);
mCamera.getMatrix(mMatrixRotate);
mCamera.restore();
mMatrixRotate.preTranslate(-transX, -transY);
mMatrixRotate.postTranslate(transX, transY);
mCamera.save();
mCamera.translate(0, 0, computeDepth((int) degree));
mCamera.getMatrix(mMatrixDepth);
mCamera.restore();
mMatrixDepth.preTranslate(-transX, -transY);
mMatrixDepth.postTranslate(transX, transY);
mMatrixRotate.postConcat(mMatrixDepth);
}
if (hasAtmospheric) {
int alpha = (int) ((mDrawnCenterY - Math.abs(mDrawnCenterY - mDrawnItemCenterY)) *
1.0F / mDrawnCenterY * 255);
alpha = alpha < 0 ? 0 : alpha;
mPaint.setAlpha(alpha);
}
// 根据卷曲与否计算数据项绘制Y方向中心坐标
// Correct item's drawn centerY base on curved state
int drawnCenterY = isCurved ? mDrawnCenterY - distanceToCenter : mDrawnItemCenterY;
// 判断是否需要为当前数据项绘制不同颜色
// Judges need to draw different color for current item or not
if (mSelectedItemTextColor != -1) {
canvas.save();
if (isCurved) canvas.concat(mMatrixRotate);
canvas.clipRect(mRectCurrentItem, Region.Op.DIFFERENCE);
canvas.drawText(data, mDrawnCenterX, drawnCenterY, mPaint);
canvas.restore();
mPaint.setColor(mSelectedItemTextColor);
canvas.save();
if (isCurved) canvas.concat(mMatrixRotate);
canvas.clipRect(mRectCurrentItem);
canvas.drawText(data, mDrawnCenterX, drawnCenterY, mPaint);
canvas.restore();
} else {
canvas.save();
canvas.clipRect(mRectDrawn);
if (isCurved) canvas.concat(mMatrixRotate);
canvas.drawText(data, mDrawnCenterX, drawnCenterY, mPaint);
canvas.restore();
}
if (isDebug) {
canvas.save();
canvas.clipRect(mRectDrawn);
mPaint.setColor(0xFFEE3333);
int lineCenterY = mWheelCenterY + (drawnOffsetPos * mItemHeight);
canvas.drawLine(mRectDrawn.left, lineCenterY, mRectDrawn.right, lineCenterY,
mPaint);
mPaint.setColor(0xFF3333EE);
mPaint.setStyle(Paint.Style.STROKE);
int top = lineCenterY - mHalfItemHeight;
canvas.drawRect(mRectDrawn.left, top, mRectDrawn.right, top + mItemHeight, mPaint);
canvas.restore();
}
}
// 是否需要绘制幕布
// Need to draw curtain or not
if (hasCurtain) {
mPaint.setColor(mCurtainColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(mRectCurrentItem, mPaint);
}
// 是否需要绘制指示器
// Need to draw indicator or not
if (hasIndicator) {
mPaint.setColor(mIndicatorColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(mRectIndicatorHead, mPaint);
canvas.drawRect(mRectIndicatorFoot, mPaint);
}
if (isDebug) {
mPaint.setColor(0x4433EE33);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, getPaddingLeft(), getHeight(), mPaint);
canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mPaint);
canvas.drawRect(getWidth() - getPaddingRight(), 0, getWidth(), getHeight(), mPaint);
canvas.drawRect(0, getHeight() - getPaddingBottom(), getWidth(), getHeight(), mPaint);
}
}
private boolean isPosInRang(int position) {
return position >= 0 && position < mData.size();
}
private int computeSpace(int degree) {
return (int) (Math.sin(Math.toRadians(degree)) * mHalfWheelHeight);
}
private int computeDepth(int degree) {
return (int) (mHalfWheelHeight - Math.cos(Math.toRadians(degree)) * mHalfWheelHeight);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouchTriggered = true;
if (null != getParent())
getParent().requestDisallowInterceptTouchEvent(true);
if (null == mTracker)
mTracker = VelocityTracker.obtain();
else
mTracker.clear();
mTracker.addMovement(event);
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
isForceFinishScroll = true;
}
mDownPointY = mLastPointY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(mDownPointY - event.getY()) < mTouchSlop) {
isClick = true;
break;
}
isClick = false;
mTracker.addMovement(event);
if (null != mOnWheelChangeListener)
mOnWheelChangeListener.onWheelScrollStateChanged(SCROLL_STATE_DRAGGING);
// 滚动内容
// Scroll WheelPicker's content
float move = event.getY() - mLastPointY;
if (Math.abs(move) < 1) break;
mScrollOffsetY += move;
mLastPointY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
if (null != getParent())
getParent().requestDisallowInterceptTouchEvent(false);
if (isClick && !isForceFinishScroll) break;
mTracker.addMovement(event);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT)
mTracker.computeCurrentVelocity(1000, mMaximumVelocity);
else
mTracker.computeCurrentVelocity(1000);
// 根据速度判断是该滚动还是滑动
// Judges the WheelPicker is scroll or fling base on current velocity
isForceFinishScroll = false;
int velocity = (int) mTracker.getYVelocity();
if (Math.abs(velocity) > mMinimumVelocity) {
mScroller.fling(0, mScrollOffsetY, 0, velocity, 0, 0, mMinFlingY, mMaxFlingY);
mScroller.setFinalY(mScroller.getFinalY() +
computeDistanceToEndPoint(mScroller.getFinalY() % mItemHeight));
} else {
mScroller.startScroll(0, mScrollOffsetY, 0,
computeDistanceToEndPoint(mScrollOffsetY % mItemHeight));
}
// 校正坐标
// Correct coordinates
if (!isCyclic)
if (mScroller.getFinalY() > mMaxFlingY)
mScroller.setFinalY(mMaxFlingY);
else if (mScroller.getFinalY() < mMinFlingY)
mScroller.setFinalY(mMinFlingY);
mHandler.post(this);
if (null != mTracker) {
mTracker.recycle();
mTracker = null;
}
break;
case MotionEvent.ACTION_CANCEL:
if (null != getParent())
getParent().requestDisallowInterceptTouchEvent(false);
if (null != mTracker) {
mTracker.recycle();
mTracker = null;
}
break;
}
return true;
}
private int computeDistanceToEndPoint(int remainder) {
if (Math.abs(remainder) > mHalfItemHeight)
if (mScrollOffsetY < 0)
return -mItemHeight - remainder;
else
return mItemHeight - remainder;
else
return -remainder;
}
@Override
public void run() {
if (null == mData || mData.size() == 0) return;
if (mScroller.isFinished() && !isForceFinishScroll) {
if (mItemHeight == 0) return;
int position = (-mScrollOffsetY / mItemHeight + mSelectedItemPosition) % mData.size();
position = position < 0 ? position + mData.size() : position;
if (isDebug)
Log.i(TAG, position + ":" + mData.get(position) + ":" + mScrollOffsetY);
mCurrentItemPosition = position;
if (null != mOnItemSelectedListener && isTouchTriggered)
mOnItemSelectedListener.onItemSelected(this, mData.get(position), position);
if (null != mOnWheelChangeListener && isTouchTriggered) {
mOnWheelChangeListener.onWheelSelected(position);
mOnWheelChangeListener.onWheelScrollStateChanged(SCROLL_STATE_IDLE);
}
}
if (mScroller.computeScrollOffset()) {
if (null != mOnWheelChangeListener)
mOnWheelChangeListener.onWheelScrollStateChanged(SCROLL_STATE_SCROLLING);
mScrollOffsetY = mScroller.getCurrY();
postInvalidate();
mHandler.postDelayed(this, 16);
}
}
@Override
public void setDebug(boolean isDebug) {
this.isDebug = isDebug;
}
@Override
public int getVisibleItemCount() {
return mVisibleItemCount;
}
@Override
public void setVisibleItemCount(int count) {
mVisibleItemCount = count;
updateVisibleItemCount();
requestLayout();
}
@Override
public boolean isCyclic() {
return isCyclic;
}
@Override
public void setCyclic(boolean isCyclic) {
this.isCyclic = isCyclic;
computeFlingLimitY();
invalidate();
}
@Override
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
mOnItemSelectedListener = listener;
}
@Override
public int getSelectedItemPosition() {
return mSelectedItemPosition;
}
@Override
public void setSelectedItemPosition(int position) {
setSelectedItemPosition(position, true);
}
public void setSelectedItemPosition(int position, final boolean animated) {
isTouchTriggered = false;
if (animated && mScroller.isFinished()) { // We go non-animated regardless of "animated" parameter if scroller is in motion
int length = getData().size();
int itemDifference = position - mCurrentItemPosition;
if (itemDifference == 0)
return;
if (isCyclic && Math.abs(itemDifference) > (length / 2)) { // Find the shortest path if it's cyclic
itemDifference += (itemDifference > 0) ? -length : length;
}
mScroller.startScroll(0, mScroller.getCurrY(), 0, (-itemDifference) * mItemHeight);
mHandler.post(this);
} else {
if (!mScroller.isFinished())
mScroller.abortAnimation();
position = Math.min(position, mData.size() - 1);
position = Math.max(position, 0);
mSelectedItemPosition = position;
mCurrentItemPosition = position;
mScrollOffsetY = 0;
computeFlingLimitY();
requestLayout();
invalidate();
}
}
@Override
public int getCurrentItemPosition() {
return mCurrentItemPosition;
}
@Override
public List getData() {
return mData;
}
@Override
public void setData(List data) {
if (null == data)
throw new NullPointerException("WheelPicker's data can not be null!");
mData = data;
// 重置位置
if (mSelectedItemPosition > data.size() - 1 || mCurrentItemPosition > data.size() - 1) {
mSelectedItemPosition = mCurrentItemPosition = data.size() - 1;
} else {
mSelectedItemPosition = mCurrentItemPosition;
}
mScrollOffsetY = 0;
computeTextSize();
computeFlingLimitY();
requestLayout();
invalidate();
}
public void setSameWidth(boolean hasSameWidth) {
this.hasSameWidth = hasSameWidth;
computeTextSize();
requestLayout();
invalidate();
}
@Override
public boolean hasSameWidth() {
return hasSameWidth;
}
@Override
public void setOnWheelChangeListener(OnWheelChangeListener listener) {
mOnWheelChangeListener = listener;
}
@Override
public String getMaximumWidthText() {
return mMaxWidthText;
}
@Override
public void setMaximumWidthText(String text) {
if (null == text)
throw new NullPointerException("Maximum width text can not be null!");
mMaxWidthText = text;
computeTextSize();
requestLayout();
invalidate();
}
@Override
public int getMaximumWidthTextPosition() {
return mTextMaxWidthPosition;
}
@Override
public void setMaximumWidthTextPosition(int position) {
if (!isPosInRang(position))
throw new ArrayIndexOutOfBoundsException("Maximum width text Position must in [0, " +
mData.size() + "), but current is " + position);
mTextMaxWidthPosition = position;
computeTextSize();
requestLayout();
invalidate();
}
@Override
public int getSelectedItemTextColor() {
return mSelectedItemTextColor;
}
@Override
public void setSelectedItemTextColor(int color) {
mSelectedItemTextColor = color;
computeCurrentItemRect();
invalidate();
}
@Override
public int getItemTextColor() {
return mItemTextColor;
}
@Override
public void setItemTextColor(int color) {
mItemTextColor = color;
invalidate();
}
@Override
public int getItemTextSize() {
return mItemTextSize;
}
@Override
public void setItemTextSize(int size) {
mItemTextSize = size;
mPaint.setTextSize(mItemTextSize);
computeTextSize();
requestLayout();
invalidate();
}
@Override
public int getItemSpace() {
return mItemSpace;
}
@Override
public void setItemSpace(int space) {
mItemSpace = space;
requestLayout();
invalidate();
}
@Override
public void setIndicator(boolean hasIndicator) {
this.hasIndicator = hasIndicator;
computeIndicatorRect();
invalidate();
}
@Override
public boolean hasIndicator() {
return hasIndicator;
}
@Override
public int getIndicatorSize() {
return mIndicatorSize;
}
@Override
public void setIndicatorSize(int size) {
mIndicatorSize = size;
computeIndicatorRect();
invalidate();
}
@Override
public int getIndicatorColor() {
return mIndicatorColor;
}
@Override
public void setIndicatorColor(int color) {
mIndicatorColor = color;
invalidate();
}
@Override
public void setCurtain(boolean hasCurtain) {
this.hasCurtain = hasCurtain;
computeCurrentItemRect();
invalidate();
}
@Override
public boolean hasCurtain() {
return hasCurtain;
}
@Override
public int getCurtainColor() {
return mCurtainColor;
}
@Override
public void setCurtainColor(int color) {
mCurtainColor = color;
invalidate();
}
@Override
public void setAtmospheric(boolean hasAtmospheric) {
this.hasAtmospheric = hasAtmospheric;
invalidate();
}
@Override
public boolean hasAtmospheric() {
return hasAtmospheric;
}
@Override
public boolean isCurved() {
return isCurved;
}
@Override
public void setCurved(boolean isCurved) {
this.isCurved = isCurved;
requestLayout();
invalidate();
}
@Override
public int getItemAlign() {
return mItemAlign;
}
@Override
public void setItemAlign(int align) {
mItemAlign = align;
updateItemTextAlign();
computeDrawnCenter();
invalidate();
}
@Override
public Typeface getTypeface() {
if (null != mPaint)
return mPaint.getTypeface();
return null;
}
@Override
public void setTypeface(Typeface tf) {
if (null != mPaint)
mPaint.setTypeface(tf);
computeTextSize();
requestLayout();
invalidate();
}
/**
* 滚轮选择器Item项被选中时监听接口
*
* @author AigeStudio 2016-06-17
* 新项目结构
* @version 1.1.0
*/
public interface OnItemSelectedListener {
/**
* 当滚轮选择器数据项被选中时回调该方法
* 滚动选择器滚动停止后会回调该方法并将当前选中的数据和数据在数据列表中对应的位置返回
*
* @param picker 滚轮选择器
* @param data 当前选中的数据
* @param position 当前选中的数据在数据列表中的位置
*/
void onItemSelected(WheelPicker picker, Object data, int position);
}
/**
* 滚轮选择器滚动时监听接口
*
* @author AigeStudio 2016-06-17
* 新项目结构
* <p>
* New project structure
* @since 2016-06-17
*/
public interface OnWheelChangeListener {
/**
* 当滚轮选择器滚动时回调该方法
* 滚轮选择器滚动时会将当前滚动位置与滚轮初始位置之间的偏移距离返回,该偏移距离有正负之分,正值表示
* 滚轮正在往上滚动,负值则表示滚轮正在往下滚动
* <p>
* Invoke when WheelPicker scroll stopped
* WheelPicker will return a distance offset which between current scroll position and
* initial position, this offset is a positive or a negative, positive means WheelPicker is
* scrolling from bottom to top, negative means WheelPicker is scrolling from top to bottom
*
* @param offset 当前滚轮滚动距离上一次滚轮滚动停止后偏移的距离
* <p>
* Distance offset which between current scroll position and initial position
*/
void onWheelScrolled(int offset);
/**
* 当滚轮选择器停止后回调该方法
* 滚轮选择器停止后会回调该方法并将当前选中的数据项在数据列表中的位置返回
* <p>
* Invoke when WheelPicker scroll stopped
* This method will be called when WheelPicker stop and return current selected item data's
* position in list
*
* @param position 当前选中的数据项在数据列表中的位置
* <p>
* Current selected item data's position in list
*/
void onWheelSelected(int position);
/**
* 当滚轮选择器滚动状态改变时回调该方法
* 滚动选择器的状态总是会在静止、拖动和滑动三者之间切换,当状态改变时回调该方法
* <p>
* Invoke when WheelPicker's scroll state changed
* The state of WheelPicker always between idle, dragging, and scrolling, this method will
* be called when they switch
*
* @param state 滚轮选择器滚动状态,其值仅可能为下列之一
* {@link WheelPicker#SCROLL_STATE_IDLE}
* 表示滚动选择器处于静止状态
* {@link WheelPicker#SCROLL_STATE_DRAGGING}
* 表示滚动选择器处于拖动状态
* {@link WheelPicker#SCROLL_STATE_SCROLLING}
* 表示滚动选择器处于滑动状态
* <p>
* State of WheelPicker, only one of the following
* {@link WheelPicker#SCROLL_STATE_IDLE}
* Express WheelPicker in state of idle
* {@link WheelPicker#SCROLL_STATE_DRAGGING}
* Express WheelPicker in state of dragging
* {@link WheelPicker#SCROLL_STATE_SCROLLING}
* Express WheelPicker in state of scrolling
*/
void onWheelScrollStateChanged(int state);
}
}
第二步 : 定义一个接口 IWheelPicker把下面代码拷贝进去
import android.graphics.Typeface;
import java.util.List;
/**
* 滚轮选择器方法接口
* <p>
* Interface of WheelPicker
*
* @author AigeStudio 2015-12-03
* @author AigeStudio 2015-12-08
* @author AigeStudio 2015-12-12
* @author AigeStudio 2016-06-17
* 更新项目结构
* <p>
* New project structure
* @version 1.1.0
*/
public interface IWheelPicker {
/**
* 获取滚轮选择器可见数据项的数量
* <p>
* Get the count of current visible items in WheelPicker
*
* @return 滚轮选择器可见数据项的数量
*/
int getVisibleItemCount();
/**
* 设置滚轮选择器可见数据项数量
* 滚轮选择器的可见数据项数量必须为大于1的整数
* 这里需要注意的是,滚轮选择器会始终显示奇数个数据项,即便你为其设置偶数个数据项,最终也会被转换为奇数
* 默认情况下滚轮选择器可见数据项数量为7
* <p>
* Set the count of current visible items in WheelPicker
* The count of current visible items in WheelPicker must greater than 1
* Notice:count of current visible items in WheelPicker will always is an odd number, even you
* can set an even number for it, it will be change to an odd number eventually
* By default, the count of current visible items in WheelPicker is 7
*
* @param count 滚轮选择器可见数据项数量
*/
void setVisibleItemCount(int count);
/**
* 滚轮选择器数据项是否为循环状态
* <p>
* Whether WheelPicker is cyclic or not
*
* @return 是否为循环状态
*/
boolean isCyclic();
/**
* 设置滚轮选择器数据项是否为循环状态
* 开启数据循环会使滚轮选择器上下滚动不再有边界,会呈现数据首尾相接无限循环的效果
* <p>
* Set whether WheelPicker is cyclic or not
* WheelPicker's items will be end to end and in an infinite loop if setCyclic true, and there
* is no border whit scroll when WheelPicker in cyclic state
*
* @param isCyclic 是否为循环状态
*/
void setCyclic(boolean isCyclic);
/**
* 设置滚轮Item选中监听器
*
* @param listener 滚轮Item选中监听器{@link WheelPicker.OnItemSelectedListener}
*/
void setOnItemSelectedListener(WheelPicker.OnItemSelectedListener listener);
/**
* 获取当前被选中的数据项所显示的数据在数据源中的位置
* 需要注意的是,当滚轮选择器滚动时并不会改变该方法的返回值,该方法会始终返回
* {@link #setSelectedItemPosition(int)}所设置的值,当且仅当调用
* {@link #setSelectedItemPosition(int)}设置新值后,该方法所返回的值才会改变
* 如果你只是想获取滚轮静止时当前被选中的数据项所显示的数据在数据源中的位置,你可以通过
* {@link com.example.myapplication.wheel.WheelPicker.OnItemSelectedListener}回调监听或调用
* {@link #getCurrentItemPosition()}
* <p>
* Get the position of current selected item in data source
* Notice:The value by return will not change when WheelPicker scroll, this method will always
* return the value which {@link #setSelectedItemPosition(int)} set, the value this method
* return will be changed if and only if call the
* {@link #setSelectedItemPosition(int)}
* set a new value
* If you only want to get the position of current selected item in data source, you can get it
* through {@link com.example.myapplication.wheel.WheelPicker.OnItemSelectedListener} or call
* {@link #getCurrentItemPosition()} directly
*
* @return 当前被选中的数据项所显示的数据在数据源中的位置
*/
int getSelectedItemPosition();
/**
* 设置当前被选中的数据项所显示的数据在数据源中的位置
* 调用该方法会导致滚动选择器的位置被重新初始化,什么意思呢?假如你滑动选择到第五个数据项的时候调用该方
* 法重新将当前被选中的数据项所显示的数据在数据源中的位置设置为第三个,那么滚轮选择器会清除掉上一次滚动
* 的相关数据参数,并将重置一系列的数据,重新将第三个数据作为滚轮选择器的起点,这个行为很可能会影响你之
* 前所根据这些参数改变的一些属性,比如
* {@link com.example.myapplication.wheel.WheelPicker.OnWheelChangeListener}和
* {@link com.example.myapplication.wheel.WheelPicker.OnItemSelectedListener}监听器中方法参数的值,因
* 此你总该在调用该方法后考虑到相关影响
* 你总该为该方法传入一个大于等于0小于数据源{@link #getData()}长度
* 的值,否则会抛出异常
* 默认情况下,当前被选中的数据项所显示的数据在数据源中的位置为0
* <p>
* Set the position of current selected item in data source
* Call this method and set a new value may be reinitialize the location of WheelPicker. For
* example, you call this method after scroll the WheelPicker and set selected item position
* with a new value, WheelPicker will clear the related parameters last scroll set and reset
* series of data, and make the position 3 as a new starting point of WheelPicker, this behavior
* maybe influenced some attribute you set last time, such as parameters of method in
* {@link com.example.myapplication.wheel.WheelPicker.OnWheelChangeListener} and
* {@link com.example.myapplication.wheel.WheelPicker.OnItemSelectedListener}, so you must always
* consider the influence when you call this method set a new value
* You should always set a value which greater than or equal to 0 and less than data source's
* length
* By default, position of current selected item in data source is 0
*
* @param position 当前被选中的数据项所显示的数据在数据源中的位置
*/
void setSelectedItemPosition(int position);
/**
* 获取当前被选中的数据项所显示的数据在数据源中的位置
* 与{@link #getSelectedItemPosition()}不同的是,该方法所返回的结果会因为滚轮选择器的改变而改变
* <p>
* Get the position of current selected item in data source
* The difference between {@link #getSelectedItemPosition()}, the value this method return will
* change by WheelPicker scrolled
*
* @return 当前被选中的数据项所显示的数据在数据源中的位置
*/
int getCurrentItemPosition();
/**
* 获取数据列表
* <p>
* Get data source of WheelPicker
*
* @return 数据列表
*/
List getData();
/**
* 设置数据列表
* 数据源可以是任意类型,但是需要注意的是WheelPicker在绘制数据的时候会将数据转换成String类型
* 在没有设置数据源的情况下滚轮选择器会设置一个默认的数据源作为展示
* 为滚轮选择器设置数据源会重置滚轮选择器的各项状态,具体行为参考
* {@link #setSelectedItemPosition(int)}
* <p>
* Set data source of WheelPicker
* The data source can be any type, WheelPicker will change the data to string when it draw the
* item.
* There is a default data source when you not set the data source for WheelPicker.
* Set data source for WheelPicker will reset state of it, you can refer to
* {@link #setSelectedItemPosition(int)} for more details.
*
* @param data 数据列表
*/
void setData(List data);
/**
* 设置数据项是否有相同的宽度
* 滚轮选择器在确定尺寸大小时会通过遍历数据源来计算每一条数据文本的宽度以找到最宽的文本作为滚轮选择器的
* 最终宽度,当数据源的数据非常多时,这个过程可能会消耗大量的时间导致效率降低,而且在大部分数据量多情况
* 下,数据文本大都有相同的宽度,这种情况下调用该方法告诉滚轮选择器数据宽度相同则可以免去上述计算时间,
* 提升效率
* 有些时候,你所加载的数据源确实是每条数据文本的宽度都不同,但是你知道最宽的数据文本在数据源中的位置,
* 这时你可以调用{@link #setMaximumWidthTextPosition(int)}方法告诉滚轮选择器最宽的这条数据文本在数据
* 源的什么位置,滚轮选择器则会根据该位置找到该条数据文本并将其宽度作为滚轮选择器的宽度。如果你不知道位
* 置,但是知道最宽的数据文本,那么你也可以直接通过调用{@link #setMaximumWidthText(String)}告诉滚轮选
* 择器最宽的文本是什么,滚轮选择器会根据这条文本计算宽度并将其作为滚轮选择器的宽度
* <p>
* Set items of WheelPicker if has same width
* WheelPicker will traverse the data source to calculate each data text width to find out the
* maximum text width for the final view width, this process maybe spends a lot of time and
* reduce efficiency when data source has large amount data, in most large amount data case,
* data text always has same width, you can call this method tell to WheelPicker your data
* source has same width to save time and improve efficiency.
* Sometimes the data source you set is positively has different text width, but maybe you know
* the maximum width text's position in data source, then you can call
* {@link #setMaximumWidthTextPosition(int)} tell to WheelPicker where is the maximum width text
* in data source, WheelPicker will calculate its width base on this text which found by
* position. If you don't know the position of maximum width text in data source, but you have
* maximum width text, you can call {@link #setMaximumWidthText(String)} tell to WheelPicker
* what maximum width text is directly, WheelPicker will calculate its width base on this text.
*
* @param hasSameSize 是否有相同的宽度
*/
void setSameWidth(boolean hasSameSize);
/**
* 数据项是否有相同宽度
* <p>
* Whether items has same width or not
*
* @return 是否有相同宽度
*/
boolean hasSameWidth();
/**
* 设置滚轮滚动状态改变监听器
*
* @param listener 滚轮滚动状态改变监听器
* @see com.example.myapplication.wheel.WheelPicker.OnWheelChangeListener
*/
void setOnWheelChangeListener(WheelPicker.OnWheelChangeListener listener);
/**
* 获取最宽的文本
* <p>
* Get maximum width text
*
* @return 最宽的文本
*/
String getMaximumWidthText();
/**
* 设置最宽的文本
* <p>
* Set maximum width text
*
* @param text 最宽的文本
* @see #setSameWidth(boolean)
*/
void setMaximumWidthText(String text);
/**
* 获取最宽的文本在数据源中的位置
* <p>
* Get the position of maximum width text in data source
*
* @return 最宽的文本在数据源中的位置
*/
int getMaximumWidthTextPosition();
/**
* 设置最宽的文本在数据源中的位置
* <p>
* Set the position of maximum width text in data source
*
* @param position 最宽的文本在数据源中的位置
* @see #setSameWidth(boolean)
*/
void setMaximumWidthTextPosition(int position);
/**
* 获取当前选中的数据项文本颜色
* <p>
* Get text color of current selected item
* For example 0xFF123456
*
* @return 当前选中的数据项文本颜色
*/
int getSelectedItemTextColor();
/**
* 设置当前选中的数据项文本颜色
* <p>
* Set text color of current selected item
* For example 0xFF123456
*
* @param color 当前选中的数据项文本颜色,16位颜色值
*/
void setSelectedItemTextColor(int color);
/**
* 获取数据项文本颜色
* <p>
* Get text color of items
* For example 0xFF123456
*
* @return 数据项文本颜色
*/
int getItemTextColor();
/**
* 设置数据项文本颜色
* <p>
* Set text color of items
* For example 0xFF123456
*
* @param color 数据项文本颜色,16位颜色值
*/
void setItemTextColor(int color);
/**
* 获取数据项文本尺寸大小
* <p>
* Get text size of items
* Unit in px
*
* @return 数据项文本尺寸大小
*/
int getItemTextSize();
/**
* 设置数据项文本尺寸大小
* <p>
* Set text size of items
* Unit in px
*
* @param size 设置数据项文本尺寸大小,单位:px
*/
void setItemTextSize(int size);
/**
* 获取滚轮选择器数据项之间间距
* <p>
* Get space between items
* Unit in px
*
* @return 滚轮选择器数据项之间间距
*/
int getItemSpace();
/**
* 设置滚轮选择器数据项之间间距
* <p>
* Set space between items
* Unit in px
*
* @param space 滚轮选择器数据项之间间距,单位:px
*/
void setItemSpace(int space);
/**
* 设置滚轮选择器是否显示指示器
* 如果设置滚轮选择器显示指示器,那么将会在滚轮选择器的当前选中数据项上下显示两根分割线
* 需要注意的是指示器的尺寸并不参与滚轮选择器的尺寸计算,其会绘制在滚轮选择器的上方
* <p>
* Set whether WheelPicker display indicator or not
* WheelPicker will draw two lines above an below current selected item if display indicator
* Notice:Indicator's size will not participate in WheelPicker's size calculation, it will drawn
* above the content
*
* @param hasIndicator 是否有指示器
*/
void setIndicator(boolean hasIndicator);
/**
* 滚轮选择器是否有指示器
* <p>
* Whether WheelPicker display indicator or not
*
* @return 滚轮选择器是否有指示器
*/
boolean hasIndicator();
/**
* 获取滚轮选择器指示器尺寸
* <p>
* Get size of indicator
* Unit in px
*
* @return 滚轮选择器指示器尺寸
*/
int getIndicatorSize();
/**
* 设置滚轮选择器指示器尺寸
* <p>
* Set size of indicator
* Unit in px
*
* @param size 滚轮选择器指示器尺寸,单位:px
*/
void setIndicatorSize(int size);
/**
* 获取滚轮选择器指示器颜色
* <p>
* Get color of indicator
* For example 0xFF123456
*
* @return 滚轮选择器指示器颜色,16位颜色值
*/
int getIndicatorColor();
/**
* 设置滚轮选择器指示器颜色
* <p>
* Set color of indicator
* For example 0xFF123456
*
* @param color 滚轮选择器指示器颜色,16位颜色值
*/
void setIndicatorColor(int color);
/**
* 设置滚轮选择器是否显示幕布
* 设置滚轮选择器显示幕布的话将会在当前选中的项上方绘制一个与当前数据项大小一致的矩形区域并填充指定颜色
* <p>
* Set whether WheelPicker display curtain or not
* WheelPicker will draw a rectangle as big as current selected item and fill specify color
* above content if curtain display
*
* @param hasCurtain 滚轮选择器是否显示幕布
*/
void setCurtain(boolean hasCurtain);
/**
* 滚轮选择器是否显示幕布
* <p>
* Whether WheelPicker display curtain or not
*
* @return 滚轮选择器是否显示幕布
*/
boolean hasCurtain();
/**
* 获取滚轮选择器幕布颜色
* <p>
* Get color of curtain
* For example 0xFF123456
*
* @return 滚轮选择器幕布颜色,16位颜色值
*/
int getCurtainColor();
/**
* 设置滚轮选择器幕布颜色
* <p>
* Set color of curtain
* For example 0xFF123456
*
* @param color 滚轮选择器幕布颜色,16位颜色值
*/
void setCurtainColor(int color);
/**
* 设置滚轮选择器是否有空气感
* 开启空气感的滚轮选择器将呈现中间不透明逐渐向两端透明过度的渐变效果
* <p>
* Set whether WheelPicker has atmospheric or not
* WheelPicker's items will be transparent from center to ends if atmospheric display
*
* @param hasAtmospheric 滚轮选择器是否有空气感
*/
void setAtmospheric(boolean hasAtmospheric);
/**
* 滚轮选择器是否有空气感
* <p>
* Whether WheelPicker has atmospheric or not
*
* @return 滚轮选择器是否有空气感
*/
boolean hasAtmospheric();
/**
* 滚轮选择器是否开启卷曲效果
* <p>
* Whether WheelPicker enable curved effect or not
*
* @return 滚轮选择器是否开启卷曲效果
*/
boolean isCurved();
/**
* 设置滚轮选择器是否开启卷曲效果
* 开启滚轮选择器的滚轮效果会呈现一种滚轮两端向屏幕内弯曲的效果
* 滚轮选择器的卷曲效果依赖于严格的几何模型,一些与尺寸相关的设置在该效果下可能会变得不再有效,例如在卷
* 曲效果下每一条数据项的尺寸大小因为透视关系看起来都不再一样,数据项之间的间隔也会因为卷曲的关系有微妙
* 的视觉差距
* <p>
* Set whether WheelPicker enable curved effect or not
* If setCurved true, WheelPicker will display with curved effect looks like ends bend into
* screen with perspective.
* WheelPicker's curved effect base on strict geometric model, some parameters relate with size
* maybe invalidated, for example each item size looks like different because of perspective in
* curved, the space between items looks like have a little difference
*
* @param isCurved 滚轮选择器是否开启卷曲效果
*/
void setCurved(boolean isCurved);
/**
* 获取滚轮选择器数据项的对齐方式
* <p>
* Get alignment of WheelPicker
*
* @return 滚轮选择器数据项的对齐方式
*/
int getItemAlign();
/**
* 设置滚轮选择器数据项的对齐方式
* 默认对齐方式为居中对齐{@link WheelPicker#ALIGN_CENTER}
* <p>
* Set alignment of WheelPicker
* The default alignment of WheelPicker is {@link WheelPicker#ALIGN_CENTER}
*
* @param align 对齐方式标识值
* 该值仅能是下列值之一:
* {@link WheelPicker#ALIGN_CENTER}
* {@link WheelPicker#ALIGN_LEFT}
* {@link WheelPicker#ALIGN_RIGHT}
*/
void setItemAlign(int align);
/**
* 获取数据项文本字体对象
* <p>
* Get typeface of item text
*
* @return 文本字体对象
*/
Typeface getTypeface();
/**
* 设置数据项文本字体对象
* 数据项文本字体的设置可能会导致滚轮大小的改变
* <p>
* Set typeface of item text
* Set typeface of item text maybe cause WheelPicker size change
*
* @param tf 字体对象
*/
void setTypeface(Typeface tf);
}
第三步 : 定义一个接口 IDebug把下面代码拷贝进去
/**
* 调试模式方法接口
*
* @author AigeStudio
* @since 2011-04-11
*/
public interface IDebug {
/**
* 设置调试模式
* 开启调试模式有可能在一定程度上降低代码执行效率,请务必在正式发布时关闭调试模式
*
* @param isDebug 是否为调试模式
*/
void setDebug(boolean isDebug);
}
第四步 values 文件夹下 建一个 arrays.xml文件 复制下面的代码进去
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="WheelArrayDefault">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>24</item>
</string-array>
<string-array name="WheelArrayWeek">
<item>Monday</item>
<item>Tuesday</item>
<item>Wednesday</item>
<item>Thursday</item>
<item>Friday</item>
<item>Saturday</item>
<item>Sunday</item>
</string-array>
</resources>
第五步 values 文件夹下 建一个 attrs.xml文件 复制下面的代码进去
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WheelPicker">
<attr name="wheel_data" format="reference" />
<attr name="wheel_selected_item_position" format="integer" />
<attr name="wheel_item_text_size" format="dimension" />
<attr name="wheel_item_text_color" format="color" />
<attr name="wheel_selected_item_text_color" format="color" />
<attr name="wheel_same_width" format="boolean" />
<attr name="wheel_maximum_width_text" format="string" />
<attr name="wheel_maximum_width_text_position" format="integer" />
<attr name="wheel_visible_item_count" format="integer" />
<attr name="wheel_item_space" format="dimension" />
<attr name="wheel_cyclic" format="boolean" />
<attr name="wheel_indicator" format="boolean" />
<attr name="wheel_indicator_color" format="color" />
<attr name="wheel_indicator_size" format="dimension" />
<attr name="wheel_curtain" format="boolean" />
<attr name="wheel_curtain_color" format="color" />
<attr name="wheel_atmospheric" format="boolean" />
<attr name="wheel_curved" format="boolean" />
<attr name="wheel_item_align" format="enum">
<enum name="center" value="0" />
<enum name="left" value="1" />
<enum name="right" value="2" />
</attr>
<attr name="wheel_font_path" format="string" />
</declare-styleable>
</resources>
第六步 values 文件夹下 建一个 dimen.xml文件 复制下面的代码进去
<dimen name="WheelItemTextSize">24sp</dimen>
<dimen name="WheelItemSpace">12dp</dimen>
<dimen name="WheelIndicatorSize">2dp</dimen>
<dimen name="WheelMargins">8dp</dimen>
如此变大功告成!