android仿iphone的时间轮的工具demo,Android自定义控件:时间滚轮控件的绘制

背景

Android开发中我们会常常用到类似时间滚轮的控件,这类控件到了UI设计师手中常常会被修改成各种样子,与其从网上荡个类似的Demo漫无目的地修改,不如写个我们自己的demo,对其了如指掌,修改样式自然不成问题。下图是我们的滚轮控件实现效果:

0818b9ca8b590ca3270a3433284dd417.png

原理

我觉得对于看似复杂的控件,我们需要一步一步拆解,将功能拆解开,对应到我们所学的知识点上,然后再将这些知识点组装起来,功能也就自然出来了。

此处我们需要继承一个View,根据Touch事件,将数据按照一定的规则绘制在View上。

这里首先就是要复写View的onTouchEvent方法,捕获手指移动的距离,根据移动距离来设置显示的数据。

同时当我们松手时,应当有一个判断标准来当前中间栏应该显示的数据,并设置一个动画,让这个数据自动移动到中间位置。

关于显示文字大小的变化效果,这里参考了网上的一些代码,使用拉动距离与控件高度一半的关系,此处我们使用了一个开口向下的抛物线的函数。

说了这么多废话,先上一张示意图吧:

0818b9ca8b590ca3270a3433284dd417.png

代码

引用控件

android:layout_width="match_parent" android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="200dp"

android:background="#ff9e9e9e"/>

实现代码

控件代码比较简单,重要部分已做注释,即粘即用

/** * Created by vonchenchen on 2016/3/25 0025. */

public class WheelPicker extends View {

public static final String TAG = "TimePicker";

private Context mContext;

private int mViewHeight;

private int mViewWidth;

/** 中间条目宽度的 */

private int mCenterItemHeight;

private int mCenterY;

private float mLastDownY; //使用偏移量为了

private float mMoveDistanceY = 0;

/** 当前数组索引 */

private int mCurrentDataIndex = 0;

/** 绘制文本画笔 */

private Paint mTextPaint;

/** 绘制直线画笔 */

private Paint mLinePaint;

/** 文字最大尺寸 */

private int mMaxTextSize;

/** 间隔长度比率 */

private float mGapRatio = 0;

/** 是否允许滑动 */

private boolean mIsTouchEnable = true;

/** 是否允许下拉 */

private boolean mIsTouchDownEnable = true;

/** 是否允许上拉 */

private boolean mIsTouchUpEnable = true;

private ArrayList mDataList = new ArrayList();

public WheelPicker(Context context) {

super(context);

init(context);

}

public WheelPicker(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

private void init(Context context){

this.mContext = context;

initData();

mTextPaint = new Paint();

mTextPaint.setStyle(Paint.Style.FILL);

mTextPaint.setTextAlign(Paint.Align.CENTER);

mTextPaint.setColor(0xff1f1f1f);

mLinePaint = new Paint();

mLinePaint.setStyle(Paint.Style.FILL);

mLinePaint.setTextAlign(Paint.Align.CENTER);

mLinePaint.setColor(0xff1f1f1f);

}

private void initData(){

for(int i = 0; i < 24; i++){

mDataList.add(i+"");

}

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mViewHeight = getMeasuredHeight();

mViewWidth = getMeasuredWidth();

mCenterY = mViewHeight/2;

mMaxTextSize = mViewHeight/8;

mCenterItemHeight = mViewHeight/4;

mGapRatio = 0.7f;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

if(mIsTouchEnable) {

switch (event.getActionMasked()) {

case MotionEvent.ACTION_DOWN:

onActionDown(event);

break;

case MotionEvent.ACTION_MOVE:

onActionMove(event);

break;

case MotionEvent.ACTION_UP:

onActionUp(event);

break;

}

}

return true;

}

private void onActionDown(MotionEvent event){

mLastDownY = event.getY();

//mMoveDistanceY = 0;

}

private void onActionMove(MotionEvent event){

float currentY = event.getY();

float diff = currentY - mLastDownY;

if(mIsTouchUpEnable && mIsTouchDownEnable) {

mMoveDistanceY += diff;

}else if(!mIsTouchUpEnable && mIsTouchDownEnable){ //拉到第一个 只能向下滑动

if(diff > 0){

mMoveDistanceY += diff;

mIsTouchUpEnable = true;

}

}else if(mIsTouchUpEnable && !mIsTouchDownEnable){ //拉到最后一个 只能向上滑动

if(diff < 0){

mMoveDistanceY += diff;

mIsTouchDownEnable = true;

}

}

mLastDownY = currentY;

invalidate();

}

private void onActionUp(MotionEvent event){

returnBack(mMoveDistanceY, 0);

}

private void drawText(Canvas canvas, int currentIndex, int position){

float length = mCenterY + mMoveDistanceY;

if(position == 0){ //绘制当前中间的文字

float scale = getScale((int) mMoveDistanceY);

mTextPaint.setTextSize((float) (mMaxTextSize * scale));

mTextPaint.setColor(getAlphaTextColor(scale));

Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();

int diff = (fontMetricsInt.bottom + fontMetricsInt.top)/2;

float baseY = length-diff;

canvas.drawText(mDataList.get(currentIndex), mViewWidth / 2, baseY, mTextPaint);

if(mMoveDistanceY > mCenterItemHeight/2){ //向下拉 index减

if(mCurrentDataIndex > 0) {

mCurrentDataIndex--;

}else{

mIsTouchDownEnable = false; //禁止下拉

}

mMoveDistanceY = 0;

}else if(mMoveDistanceY < -mCenterItemHeight/2){ //向上拉 index加

if(mCurrentDataIndex < mDataList.size()-1) {

mCurrentDataIndex++;

}else{

mIsTouchUpEnable = false; //禁止上拉

}

mMoveDistanceY = 0;

}

}else { //绘制上下文字

int realIndex = currentIndex + position;

if(realIndex >= 0 && realIndex < mDataList.size()){

length = length + mCenterItemHeight * mGapRatio * position;

float scale = getScale((int) length - mCenterY);

mTextPaint.setTextSize((float) (mMaxTextSize * scale));

mTextPaint.setColor(getAlphaTextColor(scale));

Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();

int diff = (fontMetricsInt.bottom + fontMetricsInt.top)/2;

canvas.drawText(mDataList.get(realIndex), mViewWidth/2 , length-diff, mTextPaint);

}

}

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

for(int i=-3; i<=3; i++){

drawText(canvas, mCurrentDataIndex, i);

}

canvas.drawLine(0, mCenterY-mCenterItemHeight/2, mViewWidth, mCenterY-mCenterItemHeight/2, mLinePaint);

canvas.drawLine(0, mCenterY + mCenterItemHeight / 2, mViewWidth, mCenterY + mCenterItemHeight / 2, mLinePaint);

}

private float getScale(int lengthToCenter){

float ret = (float) (1 - Math.pow(((float)lengthToCenter)/mCenterY, 2));

if(ret < 0){

ret = 0;

}

return ret;

}

private void returnBack(float start, float end){

mIsTouchEnable = false;

ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);

valueAnimator.setDuration(100);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator valueAnimator) {

mMoveDistanceY = (float) valueAnimator.getAnimatedValue();

if (Math.abs(mMoveDistanceY) <= 3) {

mMoveDistanceY = 0;

mIsTouchEnable = true;

}

invalidate();

}

});

valueAnimator.start();

}

/** * 根据比率设置字体颜色 *@param scale *@return */

private int getAlphaTextColor(float scale){

int data = (int) (255 * scale);

return (data << 24);

}

public String getTimeData(){

return mDataList.get(mCurrentDataIndex);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值