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

先看下实现效果


看效果图分析

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,每天努力一点点!





  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的自定义日期选择器的示例代码: 首先,创建一个名为`DatePickerDialogFragment`的新类,继承自`DialogFragment`。这个类将用于显示日期选择器对话框。 ```java import android.app.DatePickerDialog; import android.app.Dialog; import android.os.Bundle; import android.widget.DatePicker; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import java.util.Calendar; public class DatePickerDialogFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // 获取当前日期 final Calendar calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); int day = calendar.get(Calendar.DAY_OF_MONTH); // 创建并返回一个 DatePickerDialog 实例 return new DatePickerDialog(getActivity(), this, year, month, day); } @Override public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { // 在此处处理选择的日期,你可以将其传递给其他组件或执行任何其他操作 // 例如,你可以在一个 TextView 中显示选择的日期 String selectedDate = String.format("%d-%02d-%02d", year, month + 1, dayOfMonth); // textView.setText(selectedDate); } } ``` 然后,在你的活动或片段中调用`DatePickerDialogFragment`来显示日期选择器对话框。 ```java public class MainActivity extends AppCompatActivity { // ... private void showDatePickerDialog() { DialogFragment newFragment = new DatePickerDialogFragment(); newFragment.show(getSupportFragmentManager(), "datePicker"); } // ... } ``` 当用户选择日期后,`onDateSet`方法将被调用,并传递选择的年、月和日。你可以在此方法中进行任何你想要的后续操作,例如更新文本视图中的日期。 请注意,以上代码只是一个简单的示例,你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值