1.先上自定义的控件:
/**
* 滚轮选择器
* author LH
* data 2016/8/20 17:26
*/
public class WheelView extends View {
public static final String TAG = "WheelView";
/**
* 自动回滚到中间的速度
*/
public static final float SPEED = 2;
/**
* 除选中item外,上下各需要显示的备选项数目
*/
public static final int SHOW_SIZE = 1;
private Context context;
private List itemList;
private int itemCount;
/**
* item高度
*/
private int itemHeight = 50;
/**
* 选中的位置,这个位置是mDataList的中心位置,一直不变
*/
private int currentItem;
private Paint selectPaint;
private Paint mPaint;
// 画背景图中单独的画笔
private Paint centerLinePaint;
private float centerY;
private float centerX;
private float mLastDownY;
/**
* 滑动的距离
*/
private float mMoveLen = 0;
private boolean isInit = false;
private SelectListener mSelectListener;
private Timer timer;
private MyTimerTask mTask;
Handler updateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (Math.abs(mMoveLen) < SPEED) {
// 如果偏移量少于最少偏移量
mMoveLen = 0;
if (null != timer) {
timer.cancel();
timer.purge();
timer = null;
}
if (mTask != null) {
mTask.cancel();
mTask = null;
performSelect();
}
} else {
// 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
}
invalidate();
}
};
public WheelView(Context context) {
super(context);
init(context);
}
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void setOnSelectListener(SelectListener listener) {
mSelectListener = listener;
}
public void setWheelStyle(int style) {
itemList = WheelStyle.getItemList(context, style);
if (itemList != null) {
itemCount = itemList.size();
resetCurrentSelect();
invalidate();
} else {
Log.i(TAG, "item is null");
}
}
public void setWheelItemList(List itemList) {
this.itemList = itemList;
if (itemList != null) {
itemCount = itemList.size();
resetCurrentSelect();
} else {
Log.i(TAG, "item is null");
}
}
private void resetCurrentSelect() {
if (currentItem < 0) {
currentItem = 0;
}
while (currentItem >= itemCount) {
currentItem--;
}
if (currentItem >= 0 && currentItem < itemCount) {
invalidate();
} else {
Log.i(TAG, "current item is invalid");
}
}
public int getItemCount() {
return itemCount;
}
/**
* 选择选中的item的index
* author LH
* data 2016/9/4 11:09
*/
public void setCurrentItem(int selected) {
currentItem = selected;
resetCurrentSelect();
}
public int getCurrentItem() {
return currentItem;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mViewHeight = getMeasuredHeight();
int mViewWidth = getMeasuredWidth();
centerX = (float) (mViewWidth / 2.0);
centerY = (float) (mViewHeight / 2.0);
isInit = true;
invalidate();
}
private void init(Context context) {
this.context = context;
timer = new Timer();
itemList = new ArrayList<>();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Style.FILL);
mPaint.setTextAlign(Align.CENTER);
mPaint.setColor(getResources().getColor(R.color.wheel_unselect_text));
int size1 = (int) (SupportDisplay.getLayoutScale()*22+0.5);
mPaint.setTextSize(size1);
selectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
selectPaint.setStyle(Style.FILL);
selectPaint.setTextAlign(Align.CENTER);
selectPaint.setColor(getResources().getColor(R.color.color_1a1a1a));
int size2 = (int) (SupportDisplay.getLayoutScale()*24+0.5);
selectPaint.setTextSize(size2);
centerLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
centerLinePaint.setStyle(Style.FILL);
centerLinePaint.setTextAlign(Align.CENTER);
centerLinePaint.setColor(getResources().getColor(R.color.wheel_unselect_text));
// 绘制背景
setBackground(null);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInit) {
drawData(canvas);
}
}
private void drawData(Canvas canvas) {
// 先绘制选中的text再往上往下绘制其余的text
if (!itemList.isEmpty()) {
// 绘制中间data
drawCenterText(canvas);
// 绘制上方data
for (int i = 1; i < SHOW_SIZE + 1; i++) {
drawOtherText(canvas, i, -1);
}
// 绘制下方data
for (int i = 1; i < SHOW_SIZE + 1; i++) {
drawOtherText(canvas, i, 1);
}
}
}
private void drawCenterText(Canvas canvas) {
// text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
float y = centerY + mMoveLen;
FontMetricsInt fmi = selectPaint.getFontMetricsInt();
float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
canvas.drawText(itemList.get(currentItem), centerX, baseline, selectPaint);
}
/**
* 绘制文本
* author LH
* data 2016/9/4 11:10
* @param canvas 画布
* @param position 距离mCurrentSelected的差值
* @param type 1表示向下绘制,-1表示向上绘制
*/
private void drawOtherText(Canvas canvas, int position, int type) {
int index = currentItem + type * position;
if (index >= itemCount) {
index = index - itemCount;
}
if (index < 0) {
index = index + itemCount;
}
String text = itemList.get(index);
int itemHeight = getHeight() / (SHOW_SIZE * 2 + 1);
float d = itemHeight * position + type * mMoveLen;
float y = centerY + type * d;
FontMetricsInt fmi = mPaint.getFontMetricsInt();
float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
canvas.drawText(text, centerX, baseline, mPaint);
}
@Override
public void setBackground(Drawable background) {
background = new Drawable() {
@Override
public void draw(Canvas canvas) {
itemHeight = getHeight() / (SHOW_SIZE * 2 + 1);
int width = getWidth();
canvas.drawLine(0, itemHeight, width, itemHeight, centerLinePaint);
canvas.drawLine(0, itemHeight * 2, width, itemHeight * 2, centerLinePaint);
centerLinePaint.setColor(getResources().getColor(R.color.wheel_bg));
Rect topRect = new Rect(0, 0, width, itemHeight);
canvas.drawRect(topRect, centerLinePaint);
Rect bottomRect = new Rect(0, itemHeight * 2, width, itemHeight * 3);
canvas.drawRect(bottomRect, centerLinePaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
};
super.setBackground(background);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
doDown(event);
break;
case MotionEvent.ACTION_MOVE:
doMove(event);
break;
case MotionEvent.ACTION_UP:
doUp();
break;
default:
break;
}
return true;
}
private void doDown(MotionEvent event) {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
mLastDownY = event.getY();
}
private void doMove(MotionEvent event) {
mMoveLen += (event.getY() - mLastDownY);
if (mMoveLen > itemHeight / 2) {
// 往下滑超过离开距离
mMoveLen = mMoveLen - itemHeight;
currentItem--;
if (currentItem < 0) {
currentItem = itemCount - 1;
}
} else if (mMoveLen < -itemHeight / 2) {
// 往上滑超过离开距离
mMoveLen = mMoveLen + itemHeight;
currentItem++;
if (currentItem >= itemCount) {
currentItem = 0;
}
}
mLastDownY = event.getY();
invalidate();
}
private void doUp() {
// 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
if (Math.abs(mMoveLen) < 0.0001) {
mMoveLen = 0;
return;
}
if (mTask != null) {
mTask.cancel();
mTask = null;
}
if (null == timer) {
timer = new Timer();
}
mTask = new MyTimerTask(updateHandler);
timer.schedule(mTask, 0, 10);
}
class MyTimerTask extends TimerTask {
Handler handler;
public MyTimerTask(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
handler.sendMessage(handler.obtainMessage());
}
}
private void performSelect() {
if (mSelectListener != null) {
mSelectListener.onSelect(currentItem, itemList.get(currentItem));
} else {
Log.i(TAG, "null listener");
}
}
public interface SelectListener {
void onSelect(int index, String text);
}
}
2.然后是时间选择控件的样式工具类
/**
* 时间选择样式
* author LH
* data 2016/9/4 11:05
*/
public class WheelStyle {
public static final int minYear = 1980;
public static final int maxYear = 2020;
/**
* Wheel Style Hour
*/
public static final int STYLE_HOUR = 1;
/**
* Wheel Style Minute
*/
public static final int STYLE_MINUTE = 2;
/**
* Wheel Style Year
*/
public static final int STYLE_YEAR = 3;
/**
* Wheel Style Month
*/
public static final int STYLE_MONTH = 4;
/**
* Wheel Style Day
*/
public static final int STYLE_DAY = 5;
/**
* Wheel Style Simple Day
*/
public static final int STYLE_SIMPLE_DAY = 6;
/**
* Wheel Style Set Warn
*/
public static final int STYLE_SET_WARN = 7;
/**
* Wheel Style Work Answer
*/
public static final int STYLE_WORK_ANSWER = 8;
private WheelStyle() {
}
public static List getItemList(Context context, int Style) {
if (Style == STYLE_HOUR) {
return createHourString();
} else if (Style == STYLE_MINUTE) {
return createMinuteString();
} else if (Style == STYLE_YEAR) {
return createYearString();
} else if (Style == STYLE_MONTH) {
return createMonthString();
} else if (Style == STYLE_DAY) {
return createDayString();
} else if (Style == STYLE_SIMPLE_DAY) {
return createSimpleDayString();
} else if (Style == STYLE_SET_WARN) {
return createSetWarnTimeString();
} else {
throw new IllegalArgumentException("style is illegal");
}
}
private static List createHourString() {
List wheelString = new ArrayList<>();
for (int i = 0; i < 24; i++) {
wheelString.add(String.format("%02d" + "时", i));
}
return wheelString;
}
private static List createMinuteString() {
List wheelString = new ArrayList<>();
for (int i = 0; i < 60; i++) {
wheelString.add(String.format("%02d" + "分", i));
}
return wheelString;
}
private static List createYearString() {
List wheelString = new ArrayList<>();
for (int i = minYear; i <= maxYear; i++) {
wheelString.add(Integer.toString(i));
}
return wheelString;
}
private static List createMonthString() {
List wheelString = new ArrayList<>();
for (int i = 1; i <= 12; i++) {
wheelString.add(String.format("%02d" + "月", i));
}
return wheelString;
}
private static List createDayString() {
List wheelString = new ArrayList<>();
for (int i = 1; i <= 31; i++) {
wheelString.add(String.format("%02d" + "日", i));
}
return wheelString;
}
private static List createSimpleDayString() {
List wheelString = new ArrayList<>();
wheelString.add("一天后");
wheelString.add("两天后");
wheelString.add("三天后");
return wheelString;
}
private static List createSetWarnTimeString() {
List wheelString = new ArrayList<>();
wheelString.add("30分钟");
wheelString.add("60分钟");
wheelString.add("90分钟");
wheelString.add("120分钟");
return wheelString;
}
/**
* 计算闰月
*
* @param month
* @return
*/
private static boolean isLeapMonth(int month) {
return month == 1 || month == 3 || month == 5 || month == 7
|| month == 8 || month == 10 || month == 12;
}
/**
* 计算闰年
*
* @param year
* @return
*/
private static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
}
3.使用的xml
4.在Java文件中设置
mWheelView
.setWheelStyle(WheelStyle.
STYLE_YEAR
);就可以显示WheelStyle类中设置的类型了。这个类中的样式种类读者可以根据自己的需要自行添加。
5.获取当前选择的项也很简单mWheelView.getCurrentItem();就能获取到控件的当前选择的项。获取到所在的项以后剩下的就是逻辑操作了。