Android自定义View年龄范围选择器

先看下实现效果

Android自定义View年龄范围选择器_第1张图片

看效果图分析

1 个是进度的背景,背景上面左右两个圆角按钮,下面是一个text显示进度用的

2 整体的高度用QQ截图简单的量下尺寸,毕竟显示到屏幕上的也都是像素,算完后,可根据2倍图,3倍图来具体的做下适配,这都是细节的处理了,测量后,从按钮的顶部到text文字的底部大概50px,按钮的高度为20px,宽度为14px,显示进度的bg是一个高度为12px的矩形区域,好了,变量基本测量完毕,下面可以写代码了

3 这里利用安卓坐标系的一个小技巧,按钮要显示在bg的中点上,如果rect区域的高度为坐标系的起始位置,则按钮头部会被隐藏掉,这也是可以理解的,所以,我门在绘制背景的时候将他的top顶点改为距离坐标系top10个像素,则按钮要以bg的垂直中点来绘制,则 bg的rectF为

 
  
bgRectF = new RectF(0, mTop, viewWidth, bgHeight + mTop);

因为bgHeight 的高度 = bottom - top 同理,左边的RectF为

RectF leftThumbF = new RectF(mLeft, mTop + bgHeight / 2 - thumbHeight / 2, thumbWidth + mLeft, mTop + bgHeight / 2 + thumbHeight / 2);

加上mTop相当于坐标系向下平移了mTop距离,因此算出左边按钮的top = mTop + bgHeight / 2 - thumbHeight / 2 ,高度不能变 则 bottom 如上所算,这样按钮就能够在bg的垂直中点上来绘制,同理,则右边按钮的rectF为

RectF rightThumbF = new RectF(thumbRightLeft, mTop + bgHeight / 2 - thumbHeight / 2, thumbWidth + thumbRightLeft, mTop + bgHeight / 2 + thumbHeight / 2);

上面的mLeft是左边按钮距离x轴的偏移量,thumbRight 为右边距离X轴的偏移量,要保证这个按钮在移动过程中的宽度不变,所以增加此变量

4.定义ThumbType 用来标示移动的是哪个按钮

private static class ThumbType {
    private static final int THUMB_LEFT = 0;
    private static final int THUMB_RIGHT = 1;
}
5.根据手指移动距离来判断用户正在移动的是哪个按钮,这个方法很重要,如果左边按钮减去当前的moveX 大于 右边按钮减去当前的moveX,说明用户的手指在右边按钮左右,则Type = Thumb.Right,反之,则是左边的按钮,ok,方法如下,咱们取绝对值

private int judgeIsLeftOrRightThumb(int x) {
    return Math.abs(mLeft - x) - Math.abs(thumbRightLeft - x) > 0 ? ThumbType.THUMB_RIGHT : ThumbType.THUMB_LEFT;
}
6 分析左右按钮的移动范围处理临界点,左右按钮互换的情况,这点处理好后,基本上可以实现这个功能了,首先,左边的按钮我现在的处理是,他右边的边界不能超越这个右边的按钮,也就是mLeft 要 小于等于 thumbRightLeft 即 mLeft <= thumbRightLeft,左边的容易理解点,当mLeft 小于等于 按钮宽度的一半时,说明已经在坐标系的最左边了,则让mLeft = 0,这样按钮就紧靠着最左边了;右边的按钮是这样的,用户拖动到与最左边的按钮重合时,还想往最左边拖动,这个时机,我用了点小技巧,此时让thumbType == ThumbType.Left,让左边的Thumb动起来,这样就不会出错了,右边按钮的右边临界点为 getWidth - thumbWidth (不让他为thumbWidth / 2 是因为rightThumbRight中的计算);两个按钮中间的进度条,我是又绘制了一层,计算也很简单 thumbRightLeft - mLeft;底部的文字居中相信大家都会算了,因为right - left都是相对距离,注意要加上mLeft才能真正居中

textLeft = ((thumbRightLeft - mLeft) - textLength) / 2 + mLeft;
7上面基本分析完毕,要得到最后的mLeft,right的值,这个年龄我们平分100份来算,则每个刻度
mGraduation = viewWidth / range;
使用一个方法算出这个mLeft,Right对应的值,方法如下
private int[] getmGraduation() {
    int[] graduations = new int[2];
    int leftRange = mLeft / mGraduation;
    int rightRange = thumbRightLeft / mGraduation;
    if (leftRange <= 0) {
        leftRange = 0;
    }
    if (rightRange >= 100) {
        rightRange = 100;
    }
    graduations[0] = leftRange;
    graduations[1] = rightRange;
    Log.e(getClass().getSimpleName(), graduations[0] + "----" + graduations[1]);
    return
看下输出的log如下


该自定义View基本就是这样了,大家最好练起来,主类就一个,其实不想分享代码,大家自己写最好!

主类代码如下

package com.example.mrboudar.playboy.widgets;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * Created by MrBoudar on 16/9/18.
 */
public class SingleSeekBar extends View {

    private int viewWidth;
    private int viewHeight = 50;
    private int bgHeight = 12;
    private int thumbHeight = 20;
    private int thumbWidth = 14;
    private static final int mTop = 10;
    private RectF bgRectF;
    private int mLeft;
    private int thumbRightLeft;
    private int textLeft;
    private int downX;
    private int mType = ThumbType.THUMB_LEFT;
    private int range = 100;
    //刻度
    private int mGraduation;


    public SingleSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SingleSeekBar(Context context) {
        this(context, null);
    }

    public SingleSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int measureHeight;
        if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
            measureHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, viewHeight, getContext().getResources().getDisplayMetrics());
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(measureHeight, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.viewWidth = w;
        this.viewHeight = h;
        mLeft = mTop;
        thumbRightLeft = 4 * mLeft;
        mGraduation = viewWidth / range;
        bgRectF = new RectF(0, mTop, viewWidth, bgHeight + mTop);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawRoundBg(canvas);
        drawLeftThumb(canvas);
        drawRightThumb(canvas);
        drawProgressBg(canvas);
        drawText(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        //最好判定下版本,低版本无此API
        int masked = event.getActionMasked();
        switch (action & masked) {
            case MotionEvent.ACTION_DOWN:
                downX = (int) event.getRawX();
                mType = judgeIsLeftOrRightThumb(downX);
                break;
            case MotionEvent.ACTION_MOVE:
                actionOperations((int) event.getRawX());
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                actionOperations((int) event.getRawX());
                break;
        }
        return true;
    }

    private void drawRoundBg(Canvas canvas) {
        Paint paint = initPaint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.LTGRAY);
        canvas.drawRect(bgRectF, paint);
    }

    private void drawLeftThumb(Canvas canvas) {
        Paint paint = initPaint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        RectF leftThumbF = new RectF(mLeft, mTop + bgHeight / 2 - thumbHeight / 2, thumbWidth + mLeft, mTop + bgHeight / 2 + thumbHeight / 2);
        canvas.drawRoundRect(leftThumbF, 5, 5, paint);
    }

    private void drawRightThumb(Canvas canvas) {
        Paint paint = initPaint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        RectF rightThumbF = new RectF(thumbRightLeft, mTop + bgHeight / 2 - thumbHeight / 2, thumbWidth + thumbRightLeft, mTop + bgHeight / 2 + thumbHeight / 2);
        canvas.drawRoundRect(rightThumbF, 5, 5, paint);
    }

    private void drawProgressBg(Canvas canvas) {
        Paint paint = initPaint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLUE);
        RectF progressF = new RectF(mLeft + thumbWidth, mTop, thumbRightLeft, bgHeight + mTop);
        canvas.drawRect(progressF, paint);
    }

    private void drawText(Canvas canvas) {
        String text = getmGraduation()[0] + "--" + getmGraduation()[1];
        Paint paint = initPaint();
        paint.setColor(Color.WHITE);
        paint.setTextSize(20.F);
        int textLength = (int) paint.measureText(text);
        textLeft = ((thumbRightLeft - mLeft) - textLength) / 2 + mLeft;
        if (textLeft >= getWidth() - textLength) {
            textLeft = getWidth() - textLength;
        } else if (textLeft <= 0) {
            textLeft = 0;
        }
        canvas.drawText(text, textLeft, 5 * mTop, paint);
    }

    private Paint initPaint() {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(1.F);
        paint.setShader(null);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        return paint;
    }

    private int judgeIsLeftOrRightThumb(int x) {
        return Math.abs(mLeft - x) - Math.abs(thumbRightLeft - x) > 0 ? ThumbType.THUMB_RIGHT : ThumbType.THUMB_LEFT;
    }

    private void actionOperations(int acionX) {
        if (mType == ThumbType.THUMB_LEFT) {
            if (acionX <= thumbWidth / 2) {
                mLeft = 0;
            } else if (acionX >= thumbRightLeft - thumbWidth / 2) {
                mLeft = thumbRightLeft - thumbWidth / 2;
            } else {
                mLeft = acionX;
            }
        } else if (mType == ThumbType.THUMB_RIGHT) {
            if (acionX <= thumbWidth / 2 + thumbWidth) {
                thumbRightLeft = 0;
            } else if (acionX >= getWidth() - thumbWidth) {
                thumbRightLeft = getWidth() - thumbWidth;
            } else {
                if(thumbRightLeft <= mLeft){
                    mType = ThumbType.THUMB_LEFT;
                    return;
                }
                thumbRightLeft = acionX;
            }
        }
        invalidateView();
    }

    private void invalidateView() {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }

    private void startAnimation(final int x1, final int x2) {
        //android 3.0后才有属性动画ObjectAnimation,3.0以下版本使用Nineoldandroid.jar使用属性动画
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(x1, x2);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration(200);
        valueAnimator.setRepeatCount(0);
        valueAnimator.setStartDelay(200);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Float atFloat = (Float) valueAnimator.getAnimatedValue();
                if (x2 >= x1) {
                    if (mType == ThumbType.THUMB_LEFT) {
                        mLeft = (int) (mLeft * atFloat);
                    } else if (mType == ThumbType.THUMB_RIGHT) {
                        thumbRightLeft = (int) (thumbRightLeft * atFloat);
                    }
                } else {
                    if (mType == ThumbType.THUMB_LEFT) {
                        mLeft = (int) (mLeft * (1 - atFloat));
                    } else if (mType == ThumbType.THUMB_RIGHT) {
                        thumbRightLeft = (int) (thumbRightLeft * (1 - atFloat));
                    }
                }
                invalidateView();
            }
        });
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        valueAnimator.start();
    }

    private int[] getmGraduation() {
        int[] graduations = new int[2];
        int leftRange = mLeft / mGraduation;
        int rightRange = thumbRightLeft / mGraduation;
        if (leftRange <= 0) {
            leftRange = 0;
        }
        if (rightRange >= 100) {
            rightRange = 100;
        }
        graduations[0] = leftRange;
        graduations[1] = rightRange;
        Log.e(getClass().getSimpleName(), graduations[0] + "----" + graduations[1]);
        return graduations;
    }

    private static class ThumbType {
        private static final int THUMB_LEFT = 0;
        private static final int THUMB_RIGHT = 1;
    }
}

ok,每天努力一点点!





你可能感兴趣的:(自定义View,AndroidStudio)