Android之---两种自定义开关(ToggleButton)的实现(代码实现和图片实现)

两种自定义开关(ToggleButton)的实现(代码实现和图片实现)

效果图

这里写图片描述

第一个button是用代码实现的,第二个不同是用图片实现的。

ToggleButton.java

package com.xiaokele.demo.stogglebutton;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * 用代码画的仿iOS开关控件
 */
public class ToggleButton extends View {

    private static final String TAG = ToggleButton.class.getSimpleName();

    //背景Paint
    private Paint mBackGroundPaint;

    //内部开关圆Paint
    private Paint mInnerCirclePaint;

    //内部开关圆环Paint
    private Paint mInnerRingPaint;

    //开关的宽度
    private int mWidth;
    //开关的高度
    private int mHeight;

    //两边半圆的半径
    private int mRadius;

    //开关的长度
    private int mToggleWidth;

    /**
     * 开关是否打开
     */
    private boolean mIsOpen = true;

    /**
     * 当前圆环与内部圆的x轴坐标
     */
    private float mCurrentXPosition = 0;

    private int mCurrentBackGroundColor;

    private int mStartBgColorR;
    private int mStartBgColorG;
    private int mStartBgColorB;

    private int mEndBgColorR;
    private int mEndBgColorG;
    private int mEndBgColorB;

    private int mBgCloseColor;
    private int mBgOpenColor;
    private int mCircleDotColor;
    private int mCircleRingWidth;
    private int mAnimationTime;


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

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

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

        initAttrs(attrs);

        initViews();
        initColors();
    }

    private void initAttrs(AttributeSet attrs) {
        TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleButton);
        mBgCloseColor = array.getColor(R.styleable.ToggleButton_close_bg_color, Color.GRAY);
        mBgOpenColor = array.getColor(R.styleable.ToggleButton_open_bg_color, Color.GREEN);
        mCircleDotColor = array.getColor(R.styleable.ToggleButton_circle_dot_color, Color.WHITE);

        mCircleRingWidth = (int) array.getDimension(R.styleable.ToggleButton_circle_ring_width, dp2px(4));
        mAnimationTime = array.getInt(R.styleable.ToggleButton_animation_time, 500);
    }

    private void initColors() {
        mStartBgColorR = Color.red(mBgCloseColor);
        mStartBgColorG = Color.green(mBgCloseColor);
        mStartBgColorB = Color.blue(mBgCloseColor);

        mEndBgColorR = Color.red(mBgOpenColor);
        mEndBgColorG = Color.green(mBgOpenColor);
        mEndBgColorB = Color.blue(mBgOpenColor);
    }

    private void initViews() {
        mBackGroundPaint = new Paint();
        mBackGroundPaint.setAntiAlias(true);
        mBackGroundPaint.setStyle(Paint.Style.FILL);

        mInnerCirclePaint = new Paint();
        mInnerCirclePaint.setStrokeWidth(mCircleRingWidth);
        mInnerCirclePaint.setAntiAlias(true);
        mInnerCirclePaint.setColor(mCircleDotColor);
        mInnerCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);

        mInnerRingPaint = new Paint();
        mInnerRingPaint.setStrokeWidth(mCircleRingWidth);
        mInnerCirclePaint.setAntiAlias(true);
        mInnerRingPaint.setStyle(Paint.Style.STROKE);

        if (mIsOpen) {
            mCurrentBackGroundColor = mBgOpenColor;
        } else {
            mCurrentBackGroundColor = mBgCloseColor;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec) ;
        int WidthMode = MeasureSpec.getMode(widthMeasureSpec) ;

        int heightSize = MeasureSpec.getSize(heightMeasureSpec) ;
        int heightMode =MeasureSpec.getMode(heightMeasureSpec) ;

        int width ;
        int height ;
        if(WidthMode == MeasureSpec.EXACTLY) {
            width = widthSize ;
        }else if(WidthMode == MeasureSpec.AT_MOST) {
            width  = Math.min(dp2px(120) , widthSize) ;
        }else {
            width = dp2px(120) ;
        }

        if(heightMode == MeasureSpec.EXACTLY) {
            height = heightSize ;
        }else if(heightMode == MeasureSpec.AT_MOST) {
            height = Math.min(dp2px(60) , heightSize) ;
        }else {
            height = dp2px(60) ;
        }

        setMeasuredDimension(width,height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mWidth = w;
        this.mHeight = h;
        this.mRadius = (mHeight - getPaddingTop() - getPaddingBottom()) / 2;
        this.mToggleWidth = (mWidth - getPaddingRight() - getPaddingLeft()) / 2;
        mCurrentXPosition = mToggleWidth / 2;
        Log.d(TAG, "mWidth:" + mWidth + ",mHeight:" + mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.translate(mWidth / 2, mHeight / 2);

        canvas.save();

        //1.画背景
        drawBackground(canvas);

        //2.画打开的状态
        drawState(canvas);
    }

    private void drawBackground(Canvas canvas) {
        mBackGroundPaint.setColor(mCurrentBackGroundColor);
        RectF recF = new RectF(mToggleWidth / 2 - mRadius, -mRadius, mToggleWidth / 2 + mRadius, mRadius);
        canvas.drawArc(recF, -90, 180, true, mBackGroundPaint);

        RectF tangle = new RectF(-mToggleWidth / 2, -mRadius, mToggleWidth / 2, mRadius);
        canvas.drawRect(tangle, mBackGroundPaint);

        RectF rectF = new RectF(-mToggleWidth / 2 - mRadius, -mRadius, -mToggleWidth / 2 + mRadius, mRadius);
        canvas.drawArc(rectF, 270, -180, true, mBackGroundPaint);

        canvas.restore();
    }

    private void drawState(Canvas canvas) {
        mInnerRingPaint.setColor(mCurrentBackGroundColor);
        canvas.drawCircle(mCurrentXPosition, 0, mRadius - mCircleRingWidth, mInnerRingPaint);
        canvas.drawCircle(mCurrentXPosition, 0, mRadius - 2 * mCircleRingWidth, mInnerCirclePaint);
    }

    public void setOpen(boolean isOpen) {
        if (mIsOpen != isOpen) {
            mIsOpen = isOpen;
            showAnimation(mIsOpen);
        }
    }

    private void showAnimation(final boolean isOpen) {
        final float start = isOpen ? -mToggleWidth / 2 : mToggleWidth / 2;
        float end = isOpen ? mToggleWidth / 2 : -mToggleWidth / 2;

        ValueAnimator animator = ValueAnimator.ofFloat(start, end);
        animator.setDuration(mAnimationTime);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mCurrentXPosition = (float) valueAnimator.getAnimatedValue();
                setCurrentColor();
                invalidate();
            }
        });
        animator.start();

    }

    private void setCurrentColor() {
        float percent = (mCurrentXPosition + mToggleWidth / 2) * 1.0f / mToggleWidth;
        int currentR = (int) ((mEndBgColorR - mStartBgColorR) * percent + mStartBgColorR);
        int currentG = (int) ((mEndBgColorG - mStartBgColorG) * percent + mStartBgColorG);
        int currentB = (int) ((mEndBgColorB - mStartBgColorB) * percent + mStartBgColorB);
        mCurrentBackGroundColor = Color.rgb(currentR, currentG, currentB);
    }

    public boolean ToggleIsOpen() {
        return mIsOpen;
    }

    private int dp2px(int dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}

上面ToggleButton.java中用到的attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>


    <declare-styleable name="ToggleButton" >
        <!--关闭时背景颜色-->
        <attr name="close_bg_color" format="dimension|color"/>
        <!--打开时背景颜色-->
        <attr name="open_bg_color" format="dimension|color" />
        <!--实心圆的颜色-->
        <attr name="circle_dot_color" format="dimension|color" />
        <!--圆环的宽度-->
        <attr name="circle_ring_width" format="dimension" />
        <!--动画执行的时间-->
        <attr name="animation_time" format="integer" />
    </declare-styleable>

</resources>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.xiaokele.demo.stogglebutton.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用代码画的开关"/>

    <com.xiaokele.demo.stogglebutton.ToggleButton
        android:id="@+id/btn"
        android:onClick="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="仿iOS7"/>

    <ToggleButton
        android:id="@+id/ios7Btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
       android:button="@drawable/ios7_btn"
        android:checked="false"
        android:layout_gravity="center_vertical"
        android:textOn=""
        android:textOff=""
        android:text=""/>
</LinearLayout>

MainActivity.java

package com.xiaokele.demo.stogglebutton;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ToggleButton toggleBtn = (ToggleButton) findViewById(R.id.btn);
        toggleBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                boolean isOpen = toggleBtn.ToggleIsOpen();
                toggleBtn.setOpen(!isOpen);
                Toast.makeText(MainActivity.this,"开关---"+!isOpen,Toast.LENGTH_SHORT).show();
            }
        });

        final android.widget.ToggleButton ios7Btn = (android.widget.ToggleButton) findViewById(R.id.ios7Btn);
        ios7Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                boolean isChecked = ios7Btn.isChecked();
                Toast.makeText(MainActivity.this,"开关---"+isChecked,Toast.LENGTH_SHORT).show();
            }
        });
    }
}

代码就不上传github了,上面的是全部的内容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值