自定义View开关按钮

来源:互联网 发布:linux分析日志 编辑:程序博客网 时间:2024/05/21 14:44

今天来介绍下如何自定义类似iOS的按钮。


switch.gif

要想自定义View,需要了解自定义View的相关步骤,一般来说自定义View需要实现以下操作:


自定义view步骤

自定义切换按钮

1.自定义属性

根据自定义View中需要用户设置的属性,来构造自定义属性,直接在xml资源文件中的resources标签下声明:

<declare-styleable name="Switch">    <attr name="checked" format="reference|boolean"/>    <attr name="switchOnColor" format="reference|color"/>    <attr name="switchOffColor" format="reference|color"/>    <attr name="spotOnColor" format="reference|color"/>    <attr name="spotOffColor" format="reference|color"/>    <attr name="spotPadding" format="reference|dimension"/>    <attr name="duration" format="reference|integer" /></declare-styleable>

并在继承View类的Switch类中声明全局变量:

private int switchOnColor;private int switchOffColor;private int spotOnColor;private int spotOffColor;private int spotPadding;private boolean mChecked;private int duration;
2.初始化构造函数

一般来说,如果自定义View用于在布局文件声明,则必须初始化覆盖基类的两个参数的构造函数;其他带参构造函数,根据需求进行初始化。

在构造函数中通过obtainStyledAttributes()方法获取用户设置的属性值:

public Switch(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Switch);        switchOnColor = a.getColor(R.styleable.Switch_switchOnColor, DEFAULT_SWITCH_ON_COLOR);        switchOffColor = a.getColor(R.styleable.Switch_switchOffColor, DEFAULT_SWITCH_OFF_COLOR);        spotOnColor = a.getColor(R.styleable.Switch_spotOnColor, DEFAULT_SPOT_ON_COLOR);        spotOffColor = a.getColor(R.styleable.Switch_spotOffColor, DEFAULT_SPOT_OFF_COLOR);        spotPadding = a.getDimensionPixelSize(R.styleable.Switch_spotPadding, dp2px(DEFAULT_SPOT_PADDING));        duration = a.getInteger(R.styleable.Switch_duration, ANIMATION_DURATION);        mChecked = a.getBoolean(R.styleable.Switch_checked, false);        a.recycle();        state = mChecked ? State.SWITCH_ON : State.SWITCH_OFF;        setClickable(true);}
3.测量View——onMeasure

onMeasure方法是决定自定义View布局大小的关键,可通过MeasureSpec获取父布局分配给子布局的大小及布局模式。

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);    int width = dp2px(DEFAULT_WIDTH) + getPaddingLeft() + getPaddingRight();    int height = dp2px(DEFAULT_HEIGHT) + getPaddingTop() + getPaddingBottom();    if (widthSpecMode != MeasureSpec.AT_MOST) {        width = Math.max(width, widthSpecSize);    }    if (heightSpecMode != MeasureSpec.AT_MOST) {        height = Math.max(height, heightSpecSize);    }    setMeasuredDimension(width, height);}
4.给定View高宽——setMeasuredDimension

通过setMeasuredDimension方法设置自定义布局想要的View大小。代码如上所示。

5.绘制View——onDraw

最核心的方法莫过于onDraw了,onDraw是绘制View的关键,结合ValueAnimatorObjectAnimator等可实现View的动画效果。

private void animateToCheckedState() {    valueAnimator = ValueAnimator.ofFloat(0, 1);    valueAnimator.setDuration(duration);    valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator animation) {            currentPos = (float) animation.getAnimatedValue();            invalidate();        }    });    valueAnimator.addListener(new AnimatorListenerAdapter() {        @Override        public void onAnimationStart(Animator animation) {            super.onAnimationStart(animation);            isMoving = true;        }        @Override        public void onAnimationEnd(Animator animation) {            super.onAnimationEnd(animation);            isMoving = false;        }    });    if (!valueAnimator.isRunning()) {        valueAnimator.start();        currentPos = 0;    }}
6.回调监听

切换按钮的回调,主要体现在开关状态的变化:

public interface OnCheckedChangeListener {    /**     * Called when the checked state of a switch has changed.     *     * @param s The switch whose state has changed.     * @param isChecked The new checked state of switch.     */    void onCheckedChanged(Switch s, boolean isChecked);}
7.手势处理

本项目中并未使用onTouchEvent方法处理手势监听,而是覆盖了父类的performClick方法,同时保证了OnClickListener的生效。

@Overridepublic boolean performClick() {    toggle();    final boolean handled = super.performClick();    if (!handled) {        // View only makes a sound effect if the onClickListener was        // called, so we'll need to make one here instead.        playSoundEffect(SoundEffectConstants.CLICK);    }    return handled;}
作者 @fynn
项目地址 github
0 0
原创粉丝点击