Material Design学习之 Switch(详细解释)

转载请注明出处:王亟亟的大牛之路

继续这一系列的Material Design之行,昨天讲的是Sliders链接如下:http://blog.csdn.net/ddwhan0123/article/details/50586510

今天讲的是Switch,本来有考虑把它和CheckBox一起做了,但是毕竟实现不同,还是分开做吧,废话不多,开始正题



开关
On/off 开关切换单一设置选择的状态。开关控制的选项以及它的状态,应该明确的展示出来并且与内部的标签相一致。开关应该单选按钮呈现相同的视觉特性。

开关通过动画来传达被聚焦和被按下的状态。

开关滑块上标明 “on” 和 “off” 的做法被弃用,取而代之的是下图所示的开关。

当然,也有暗主题

他的好基友的介绍可以看:http://blog.csdn.net/ddwhan0123/article/details/50578348

原文地址:http://www.google.com/design/spec/components/switches.html



我们来贴下我们代码实现的效果:

包结构:

这边就说下Switch这个类,别的在之前文章里有。

     private int backgroundColor = Color.parseColor("#4CAF50");

    private Ball ball;

    private boolean check      = false;
    private boolean eventCheck = false;
    private boolean press      = false;

    private OnCheckListener onCheckListener;
    private Bitmap bitmap;

28-37,一系列的变量声明。

   public Switch(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAttributes(attrs);
        setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                if (check)
                    setChecked(false);
                else
                    setChecked(true);
            }
        });
    }

39-52行,构造函数,设置监听事件,根据是否被按来做相应初始化操作

   protected void setAttributes(AttributeSet attrs) {

        setBackgroundResource(R.drawable.background_transparent);

        // Set size of view
        setMinimumHeight(Utils.dpToPx(48, getResources()));
        setMinimumWidth(Utils.dpToPx(80, getResources()));

        // Set background Color
        // Color by resource
        int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
                "background", -1);
        if (bacgroundColor != -1) {
            setBackgroundColor(getResources().getColor(bacgroundColor));
        } else {
            // Color by hexadecimal
            int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
            if (background != -1)
                setBackgroundColor(background);
        }

        check = attrs.getAttributeBooleanValue(MATERIALDESIGNXML, "check",
                false);
        eventCheck = check;
        ball = new Ball(getContext());
        RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
                getResources()), Utils.dpToPx(20, getResources()));
        params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
        ball.setLayoutParams(params);
        addView(ball);

    }

55-86行,具体获取xml参数的方法,在这里操作了放置了小球的位置。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isEnabled()) {
            isLastTouch = true;
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                press = true;
            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                float x = event.getX();
                x = (x < ball.xIni) ? ball.xIni : x;
                x = (x > ball.xFin) ? ball.xFin : x;
                if (x > ball.xCen) {
                    eventCheck = true;
                } else {
                    eventCheck = false;
                }
                ViewHelper.setX(ball, x);
                ball.changeBackground();
                if ((event.getX() <= getWidth() && event.getX() >= 0)) {
                    isLastTouch = false;
                    press = false;
                }
            } else if (event.getAction() == MotionEvent.ACTION_UP ||
                    event.getAction() == MotionEvent.ACTION_CANCEL) {
                press = false;
                isLastTouch = false;
                if (eventCheck != check) {
                    check = eventCheck;
                    if (onCheckListener != null)
                        onCheckListener.onCheck(Switch.this,check);
                }
                if ((event.getX() <= getWidth() && event.getX() >= 0)) {
                    ball.animateCheck();
                }
            }
        }
        return true;
    }

88-124行,具体的业务逻辑。

在控件按下去的时候勾勒出手指触控反馈,合理移动的情况下(并且手指操作距离满足条件的情况下),控件状态发生改变。如果移动不合理的情况下默认不执行操作。如果触控点为另一端点(在最左OR最右的对立点),让控件状态发生改变,未被点击时为空心圆,被选中的状态为实心圆。操作有效才执行小球挪动动画。

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!placedBall) {
            placeBall();
        }

        // Crop line to transparent effect
        if(null == bitmap) {
            bitmap = Bitmap.createBitmap(canvas.getWidth(),
                    canvas.getHeight(), Bitmap.Config.ARGB_8888);
        }
        Canvas temp = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor((eventCheck) ? backgroundColor : Color.parseColor("#B0B0B0"));
        paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
        temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
                - getHeight() / 2, getHeight() / 2, paint);
        Paint transparentPaint = new Paint();
        transparentPaint.setAntiAlias(true);
        transparentPaint.setColor(getResources().getColor(
                android.R.color.transparent));
        transparentPaint.setXfermode(new PorterDuffXfermode(
                PorterDuff.Mode.CLEAR));
        temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                ViewHelper.getY(ball) + ball.getHeight() / 2,
                ball.getWidth() / 2, transparentPaint);

        canvas.drawBitmap(bitmap, 0, 0, new Paint());

        if (press) {
            paint.setColor((check) ? makePressColor() : Color
                    .parseColor("#446D6D6D"));
            canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                    getHeight() / 2, getHeight() / 2, paint);
        }
        invalidate();

    }

126-165行,如果是第一次绘制,默认在起始位置,如果xml配置默认为选中则做被选中绘制。
先设置画布,为整个View的区域块画一条线作为ball运行的轨迹,未选中为灰色,选中为background颜色值。
再画球,默认空心球
如果手势压着我们的控件再绘制一个触控反馈“圆阴影”

  protected int makePressColor() {
        int r = (this.backgroundColor >> 16) & 0xFF;
        int g = (this.backgroundColor >> 8) & 0xFF;
        int b = (this.backgroundColor >> 0) & 0xFF;
        r = (r - 30 < 0) ? 0 : r - 30;
        g = (g - 30 < 0) ? 0 : g - 30;
        b = (b - 30 < 0) ? 0 : b - 30;
        return Color.argb(70, r, g, b);
    }

172-180行,手势阴影实现.

 boolean placedBall = false;

    private void placeBall() {
        ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
        ball.xIni = ViewHelper.getX(ball);
        ball.xFin = getWidth() - getHeight() / 2 - ball.getWidth() / 2;
        ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
        placedBall = true;
        ball.animateCheck();
    }

183-192,小球初始化坐标操作。

 @Override
    public void setBackgroundColor(int color) {
        backgroundColor = color;
        if (isEnabled())
            beforeBackground = backgroundColor;

    }

    public void setChecked(boolean check) {
        invalidate();
        this.check = check;
        this.eventCheck = check;
        ball.animateCheck();
    }

    public boolean isCheck() {
        return check;
    }

196-213一系列的设置操作。

   class Ball extends View {

        float xIni, xFin, xCen;

        public Ball(Context context) {
            super(context);
            setBackgroundResource(R.drawable.background_switch_ball_uncheck);
        }

        public void changeBackground() {
            if (eventCheck) {
                setBackgroundResource(R.drawable.background_checkbox);
                LayerDrawable layer = (LayerDrawable) getBackground();
                GradientDrawable shape = (GradientDrawable) layer
                        .findDrawableByLayerId(R.id.shape_bacground);
                shape.setColor(backgroundColor);
            } else {
                setBackgroundResource(R.drawable.background_switch_ball_uncheck);
            }
        }

        public void animateCheck() {
            changeBackground();
            ObjectAnimator objectAnimator;
            if (eventCheck) {
                objectAnimator = ObjectAnimator.ofFloat(this, "x", ball.xFin);

            } else {
                objectAnimator = ObjectAnimator.ofFloat(this, "x", ball.xIni);
            }
            objectAnimator.setDuration(300);
            objectAnimator.start();
        }

    }

215-249行,小球的实现,昨天也有出现,唯一的区别就是动画是一个从左到右或从右到左 300毫秒的变化。

实现跟之前的有些许共同点,这里总结下:

先制定一个区域,作为我们的画区,画一个底层的线,画小球,根据操作做小球的运动和UI的变化!!! 就是啦么 简单!!!

Eclipse 所需Jar包地址:https://github.com/ddwhan0123/BlogSample/tree/master/JAR

这个包的源码地址:https://github.com/ddwhan0123/BlogSample/blob/master/MaterialDesignSwitch.zip

记得点个赞哦!!

时间: 2024-08-17 19:53:29

Material Design学习之 Switch(详细解释)的相关文章

Material Design学习之 Button(详细分析,传说中的水滴动画)

转载请注明出处:王亟亟的大牛之路       上一篇大致介绍了Material Design的一些基本概念传送门:http://blog.csdn.net/ddwhan0123/article/details/50541561 这一片来具体学习下里面的内容,这篇分为两部分一部分是原理分析,一部分是代码分析. 先简要的介绍一些理论知识,顺便温顾下基础知识 按钮 按钮由文字和/或图标组成,文字及图标必须能让人轻易地和点击后展示的内容联系起来. 主要的按钮有三种: 悬浮响应按钮(Floating ac

Material Design学习之 CheckBox(详细分析,富有表现力)

转载请注明出处:王亟亟的大牛之路 这些天一直在讲Material Design控件的内容,今天继续,说说CheckBox(妈蛋,好冷),上一篇的传送门:http://blog.csdn.net/ddwhan0123/article/details/50560638 老规矩,两部分,第一部分理论知识,第二部分代码 选择控制器 选择控制器允许用户选择选项.有三种类型:复选框.单选框以及开/关切换.选择控制器使用主题同样的颜色.(待会的代码主要讲的是单选按钮) 复选框 单选按钮 切换开关 官方对呈现的

Material Design学习之 Snackbars(详细分析,Toast的加强版)

转载请注明出处:王亟亟的大牛之路 昨天把Material Design Button部分的内容分析完了,不知道大家理解了他的实现没有.如果没看的话,可以看下,传送门:http://blog.csdn.net/ddwhan0123/article/details/50555958 这几篇关于Material Design文章的代码几乎都是Git上摘录的,我做的事主要是分享给大家+解释分析. 昨天有小伙伴看完后希望我像以前一样把按钮那一部分的代码单独提取出来单独打成一个包,想单独使用或者学习而不是去

Material Design学习之 Sliders(详细分析,悬空气球显示进度值,附带Eclipse可以jar)

转载请注明出处:王亟亟的大牛之路 Material Design系列的文章这是第五篇,今天讲滑块控件(Sliders). 之前的传送门:http://blog.csdn.net/ddwhan0123/article/details/50578348(代码实现都靠画,学好View还是很重要的) 老规矩,先说下理论部分 滑块控件(Sliders,简称滑块)可以让我们通过在连续或间断的区间内滑动锚点来选择一个合适的数值.区间最小值放在左边,对应的,最大值放在右边.滑块(Sliders)可以在滑动条的左

Material Design学习之 Bottom Sheets (顺便提提CoordinatorLayout)

转载请注明出处:王亟亟的大牛之路 昨天连续上了2篇介绍第三方库的文章,正直好久没提交自己写东西了,那么就补一篇之前MD系列漏的部分 Bottom Sheets Bottom Sheets–底部动作条 底部动作条(Bottom Sheets)是一个从屏幕底部边缘向上滑出的一个面板,使用这种方式向用户呈现一组功能.底部动作条呈现了简单.清晰.无需额外解释的一组操作. 在一个标准的列表样式的底部动作条(Bottom Sheets)中,每一个操作应该有一句描述和一个左对齐的 icon.如果需要的话,也可

Material Design学习之 ProgreesBar

转载奇怪注明出处:王亟亟的大牛之路 继续我们Material Design的内容,这一篇讲的是进度条,上一篇是Switch地址如下:http://blog.csdn.net/ddwhan0123/article/details/50592579 进度和动态 在用户可以查看并与内容进行交互之前,尽可能地减少视觉上的变化,尽量使应用加载过程令人愉快.每次操作只能由一个活动指示器呈现,例如,对于刷新操作,你不能即用刷新条,又用动态圆圈来指示. 指示器类型 在操作中,对于完成部分可以确定的情况下,使用确

Material Design学习之 EditText (功能强大,优于系统自带,感谢“扔物线”)

转载请注明出处:王亟亟的大牛之路 继续之前的Material Design历程,今天是EditText,素材来源于http://www.rengwuxian.com/post/materialedittext(那么代码解释部分大家可以看原作者的文档,我在这里把理论知识灌输下就OK了,作者做的很全面,我都不知道要讲什么了 只能6666666) 大牛的这个库已经有了广泛的认知度和认可,EditText部分就拿他的作为比较推崇的演示版本. 因为大牛已经做了Jar包的支持,所以平时的拆的工作都省了,要直

Material Design学习之 Camera

转载请注明出处:王亟亟的大牛之路 年后第一篇,自从来了某司产量骤减,这里批评下自己,这一篇的素材来源于老牌Material Design控件写手afollestad的 https://github.com/afollestad/material-camera 开篇前,继续安利,你懂的:https://github.com/ddwhan0123/Useful-Open-Source-Android (最近把 6.0授权部分单独罗列出来了) 介绍代码之前先贴下效果图 如何使用 先是添加依赖让mave

Material Design学习之 Dialog(顺便把前两天AppBarLayout没讲的部分提一提)

转载请注明出处:王亟亟的大牛之路 继续之前的MD系列的内容,今天说Dialog,不知道还能翻几篇,反正这一系列都说完了话就找点别的内容整整. Dialogs (提示框)用于提示用户作一些决定,或者是完成某个任务时需要的一些其它额外的信息. Dialog可以是用一种 取消/确定 的简单应答模式,也可以是自定义布局的复杂模式,比如说一些文本设置或者是文本输入 . 官方的呈现,像这样 Dialog 包含了一个标题(可选),内容 ,事件. 标题:主要是用于简单描述下选择类型.它是可选的,要需要的时候赋值