自定义滑动开关按钮-SwitchButton-进阶

之前写过这样一个简单的控件,详情可见:
[ 自定义滑动开关按钮-SwitchButton](http://blog.csdn.net/u012424449/article/details/51678311)
发现还是有点不方便,存在一些问题:
    1.字体没有居中显示
    2.图片和字都是固定的,不灵活
于是在这基础上进行了改良,效果如下,和上次效果几乎一样。本来是有点击事件的,但是这录屏软件好像屏蔽了,录制的时候不会出现,录制完了就会出现屏蔽掉的Toast。

自定义滑动开关按钮-SwitchButton-进阶_第1张图片

1.首先在values目录里添加xml文件:attrs,自定义属性,具体如下:
attrs.xml

<resources>
    <declare-styleable name="AutoButton">
        <attr name="textOn" format="string"/>
        <attr name="textOff" format="string"/>
        <attr name="textSize_ab" format="dimension"/>
        <attr name="bg_bitmap" format="reference"/>
        <attr name="btn_bitmap" format="reference"/>
    declare-styleable>
resources>
2.新建一个类继承系统View,在创建的时候获取xml中的属性,具体代码如下:
 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoButton);
        Drawable bg_Drawable = a.getDrawable(R.styleable.AutoButton_bg_bitmap);
        Drawable btn_Drawable = a.getDrawable(R.styleable.AutoButton_btn_bitmap);
        textOn = a.getString(R.styleable.AutoButton_textOn);
        textOff = a.getString(R.styleable.AutoButton_textOff);
        textSize = a.getDimension(R.styleable.AutoButton_textSize_ab, 35);
        //注意此操作
        a.recycle();
        bgBitmap = ((BitmapDrawable) bg_Drawable).getBitmap();
        btnBitmap = ((BitmapDrawable) btn_Drawable).getBitmap();

在上面代码我标注了注意的操作,因为TypeArray是一个单例模式,这个 array 是从一个 array pool的池中获取的。具体可以参考这篇文章:http://blog.csdn.net/Monicabg/article/details/45014327

主要也就是这两个步骤,其他的我就直接上源码了:

AuttoButton.java

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;


/**
 * Created by admin on 2016/6/13.
 * author: myc
 * CopyRight:
 * email:[email protected]
 * description:
 */
public class AutoButton extends View implements View.OnTouchListener {
    //背景图片
    private Bitmap bgBitmap;
    //按钮图片
    private Bitmap btnBitmap;
    private Paint paint;
    private int leftDis = 0;
    //标记最大滑动
    private int slidingMax;
    //标记按钮开关状态
    private boolean mCurrent;
    //标记是否点击事件
    private boolean isClickable;
    //标记是否移动
    private boolean isMove;
    //"开"事件监听器
    private SoftFloorListener softFloorListener;
    //"关"事件监听器
    private HydropowerListener hydropowerListener;
    //标记开关文本的宽度
    float width1, width2;
    //记录文本中心点 cx1:绘制文本1的x坐标  cx2:绘制文本2的x坐标
    //cy记录绘制文本的高度
    float cx1, cy, cx2;
    //定义"开"文本
    String textOn;
    //定义"关"文本
    String textOff;
    //定义文本大小
    float textSize;

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

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

    public AutoButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData(context, attrs);
        initView();
    }
    private void initData(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoButton);
        Drawable bg_Drawable = a.getDrawable(R.styleable.AutoButton_bg_bitmap);
        Drawable btn_Drawable = a.getDrawable(R.styleable.AutoButton_btn_bitmap);
        textOn = a.getString(R.styleable.AutoButton_textOn);
        textOff = a.getString(R.styleable.AutoButton_textOff);
        textSize = a.getDimension(R.styleable.AutoButton_textSize_ab, 35);
        a.recycle();
        bgBitmap = ((BitmapDrawable) bg_Drawable).getBitmap();
        btnBitmap = ((BitmapDrawable) btn_Drawable).getBitmap();
    }

    private void initView() {
        paint = new Paint();
        slidingMax = bgBitmap.getWidth() - btnBitmap.getWidth();
        paint.setTextSize(textSize);
        width1 = paint.measureText(textOn);
        cx1 = btnBitmap.getWidth() / 2 - width1 / 2;

        //测量绘制文本高度
        Paint.FontMetrics fontMetrics=paint.getFontMetrics();
        float fontHeight=fontMetrics.bottom-fontMetrics.top;
        cy = btnBitmap.getHeight() -(btnBitmap.getHeight()-fontHeight)/2-fontMetrics.bottom;
        width2 = paint.measureText(textOff);
        cx2 = (bgBitmap.getWidth() * 2 - btnBitmap.getWidth()) / 2 - width2 / 2;
        paint.setAntiAlias(true);
        setOnTouchListener(this);
    }



    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(bgBitmap.getWidth(), bgBitmap.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bgBitmap, 0, 0, paint);
        canvas.drawBitmap(btnBitmap, leftDis, 0, paint);
        if (mCurrent) {
            paint.setColor(Color.WHITE);
            canvas.drawText(textOff, cx2, cy, paint);
            paint.setColor(Color.BLACK);
            canvas.drawText(textOn, cx1, cy, paint);
        } else {
            paint.setColor(Color.WHITE);
            canvas.drawText(textOn, cx1, cy, paint);
            paint.setColor(Color.BLACK);
            canvas.drawText(textOff, cx2, cy, paint);
        }


    }


    //刷新视图
    private void flushView() {
        mCurrent = !mCurrent;
        if (mCurrent) {
            leftDis = slidingMax;
            if (hydropowerListener != null) {
                hydropowerListener.hydropower();
            }
        } else {
            leftDis = 0;
            if (softFloorListener != null) {
                softFloorListener.softFloor();
            }
        }
//        System.out.println("mCurrent:="+mCurrent);
        invalidate();
    }

    //startX 标记按下的X坐标,  lastX标记移动后的X坐标 ,disX移动的距离
    float startX, lastX, disX;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isClickable = true;
                startX = event.getX();
                isMove = false;
                break;
            case MotionEvent.ACTION_MOVE:
                lastX = event.getX();
                disX = lastX - startX;
                if (Math.abs(disX) < 5) break;
                isMove = true;
                isClickable = false;
                moveBtn();
                startX = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                if (isClickable) {
                    flushView();
                }
                if (isMove) {
                    if (leftDis > slidingMax / 2) {
                        mCurrent = false;
                    } else {
                        mCurrent = true;
                    }
                    flushView();
                }
                break;
        }

        return true;
    }


    //移动后判断位置
    private void moveBtn() {
        leftDis += disX;
        if (leftDis > slidingMax) {
            leftDis = slidingMax;
        } else if (leftDis < 0) {
            leftDis = 0;
        }
        invalidate();
    }


    //设置左边按钮点击事件监听器
    public void setSoftFloorListener(SoftFloorListener softFloorListener) {
        this.softFloorListener = softFloorListener;
    }

    //设置右边按钮点击事件监听器
    public void setHydropowerListener(HydropowerListener hydropowerListener) {
        this.hydropowerListener = hydropowerListener;
    }

    //开点击事件
    public interface SoftFloorListener {
        void softFloor();
    }

    //关点击事件
    public interface HydropowerListener {
        void hydropower();
    }
}

然后就是在xml布局里调用,具体如下:

activity_main.xml

"http://schemas.android.com/apk/res/android"
    
    xmlns:myc="http://schemas.android.com/apk/res-auto"
    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">

  "@+id/btn_switchbutton"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      myc:bg_bitmap="@drawable/bg"
      myc:btn_bitmap="@drawable/btn"
      myc:textSize_ab="15sp"
      myc:textOn="开"
      myc:textOff="关"
      android:padding="10dp"
      android:layout_centerHorizontal="true"/>
</RelativeLayout>

在上面我标注了注意步骤,因为需要使用自定义的控件属性,所以需要设置xml命名空间
xmlns:myc=”http://schemas.android.com/apk/res-auto”,简单点可以这么设置,规范是
xmlns:myc=”http://schemas.android.com/apk/<这里是包名>”

MainActivity.java

public class MainActivity extends Activity {
    private AutoButton btn_switchbutton;


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

    private void initView() {
        btn_switchbutton= (AutoButton) findViewById(R.id.btn_switchbutton);
        btn_switchbutton.setHydropowerListener(hydropowerListener);
        btn_switchbutton.setSoftFloorListener(softFloorListener);
    }
    AutoButton.HydropowerListener hydropowerListener=new AutoButton.HydropowerListener() {
        @Override
        public void hydropower() {
            Toast.makeText(MainActivity.this,"关",Toast.LENGTH_SHORT).show();
        }
    };
    AutoButton.SoftFloorListener softFloorListener=new AutoButton.SoftFloorListener() {
        @Override
        public void softFloor() {
      Toast.makeText(MainActivity.this,"开",Toast.LENGTH_SHORT).show();
        }
    };
}

完整代码可前往GitHub:https://github.com/yangmyc/SwitchButton
我这里设置了点击事件,因为录屏软件问题,所以没有显示,关了录屏软件后,之前的Toast就全出来了。有问题可以私聊,或者你有更好的方法,请多多指教。

你可能感兴趣的:(自定义,开关)