自定义View——切换按钮

作者: a57ecf3aaaf2 | 来源:发表于2016-05-15 20:47 被阅读1311次

    自定义View的步骤

    今天来介绍下如何自定义类似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获取父布局分配给子布局的大小及布局模式。

    @Override
    protected 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的生效。

    @Override
    public 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

    相关文章

      网友评论

      • 放开那芒果:貌似用在API19以下的手机不行java.lang.NoSuchMethodError: com.fynn.switcher.Switch.isAttachedToWindow
        at com.fynn.switcher.Switch.setChecked(Switch.java:330)
        at com.fynn.switcher.Switch.toggle(Switch.java:393)
        at com.fynn.switcher.Switch.performClick(Switch.java:276)

        这些伟大的方法不存在
        a57ecf3aaaf2:@放开那芒果 是的,需要高版本
      • 07c46a5333ff:一个注释都没有
        a57ecf3aaaf2:@amatteroftime 之前不怎么写注释,不过不是一个好的习惯。
      • 灰色的程序员:xml资源文件在哪
        a57ecf3aaaf2:@灰色的程序员 自己新建
      • ppyy一号:刚刚进入activity setChecked貌似有问题
        a57ecf3aaaf2:@Fynn_ 已修复
        a57ecf3aaaf2:@ppyy一号 什么问题?
      • 小小Q吖:你好 ,实在iPad端做的思维导图吗 ,还是电脑端做的 什么软件噢
        小小Q吖:了解
        a57ecf3aaaf2:@就是拽嘿嘿 iOS APP Store搜索“思维导图”即可。软件名字就是“思维导图”。
      • 一墨秋风:谢谢分享!想问有颜色的思维导图是什么app?
        a57ecf3aaaf2:@一墨秋风 不客气
        一墨秋风:@Fynn_ 谢谢
        a57ecf3aaaf2:@一墨秋风 iOS端 名称是“思维导图”。

      本文标题:自定义View——切换按钮

      本文链接:https://www.haomeiwen.com/subject/awgvrttx.html