您的位置:首页 > 移动开发 > IOS开发

自定义时间选择控件(仿ios滚动效果)

2016-09-04 11:09 405 查看
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<String> 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<String> 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<String> 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<String> createHourString() {
List<String> wheelString = new ArrayList<>();
for (int i = 0; i < 24; i++) {
wheelString.add(String.format("%02d" + "时", i));
}
return wheelString;
}

private static List<String> createMinuteString() {
List<String> wheelString = new ArrayList<>();
for (int i = 0; i < 60; i++) {
wheelString.add(String.format("%02d" + "分", i));
}
return wheelString;
}

private static List<String> createYearString() {
List<String> wheelString = new ArrayList<>();
for (int i = minYear; i <= maxYear; i++) {
wheelString.add(Integer.toString(i));
}
return wheelString;
}

private static List<String> createMonthString() {
List<String> wheelString = new ArrayList<>();
for (int i = 1; i <= 12; i++) {
wheelString.add(String.format("%02d" + "月", i));
}
return wheelString;
}

private static List<String> createDayString() {
List<String> wheelString = new ArrayList<>();
for (int i = 1; i <= 31; i++) {
wheelString.add(String.format("%02d" + "日", i));
}
return wheelString;
}

private static List<String> createSimpleDayString() {
List<String> wheelString = new ArrayList<>();
wheelString.add("一天后");
wheelString.add("两天后");
wheelString.add("三天后");
return wheelString;
}

private static List<String> createSetWarnTimeString() {
List<String> 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
<com.example.view.timeview.WheelView
android:id="@+id/select_time_simple_wheel"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_weight="1" />4.在Java文件中设置mWheelView.setWheelStyle(WheelStyle.STYLE_YEAR);就可以显示WheelStyle类中设置的类型了。这个类中的样式种类读者可以根据自己的需要自行添加。
5.获取当前选择的项也很简单mWheelView.getCurrentItem();就能获取到控件的当前选择的项。获取到所在的项以后剩下的就是逻辑操作了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: