您的位置:首页 > 移动开发 > Android开发

Android 自定义ToggleButton

2016-08-10 13:34 232 查看

Android自定义ToggleButton

1.需求

在项目需求中,可能需要自定义开关按钮,于是本人就根据网上的教程写了个符合自己需求的按钮

首先看一下要实现的效果:有4中图片的切换效果,点击切换开关状态,还要求支持滑动切换。



2.解决思路

写个MyToggleButton类,继承自View,重写onDraw,onClick,onMeasure,onTouchEvent等事件,来实现想要的效果。最后图片的添加放到xml中,这需要在attrs中添加自定义属性。

3.代码

MyToggleBtn .java

package com.sanmiao.mytest.myview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.sanmiao.mytest.R;

/**
* @作者 : 丁建强
* @创建时间:2016/8/9 0009 17:36
* @类说明 :自定义切换按钮
*/

public class MyToggleBtn extends View implements View.OnClickListener {
private Bitmap currBtnBitmap, currBackBitmap;
private Bitmap toggle_bg_on;
private Bitmap toggle_bg_off;
private Bitmap toggle_btn_on;
private Bitmap toggle_btn_off;
private Paint paint;
private float slide_left = 0;
private boolean currState = false;//当前开关状态,true 为开

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

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

public MyToggleBtn(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化自定义属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn);
currState = ta.getBoolean(R.styleable.MyToggleBtn_isChecked, false);
int backOnId = ta.getResourceId(R.styleable.MyToggleBtn_backImageOn, 0);
int backOffId = ta.getResourceId(R.styleable.MyToggleBtn_backImageOff, 0);
int slideOnId = ta.getResourceId(R.styleable.MyToggleBtn_slideImageOn, 0);
int slideOffId = ta.getResourceId(R.styleable.MyToggleBtn_slideImageOff, 0);

toggle_bg_on = BitmapFactory.decodeResource(getResources(), backOnId);
toggle_btn_on = BitmapFactory.decodeResource(getResources(), slideOnId);
if (backOffId == 0) {
toggle_bg_off = toggle_bg_on;
} else {
toggle_bg_off = BitmapFactory.decodeResource(getResources(), backOffId);
}
if (slideOffId == 0) {
toggle_btn_off = toggle_btn_on;
} else {
toggle_btn_off = BitmapFactory.decodeResource(getResources(), slideOffId);
}
ta.recycle();
initView();
}

private void initView() {
currBtnBitmap = toggle_btn_off;
currBackBitmap = toggle_btn_off;
paint = new Paint();
paint.setAntiAlias(true);//设置抗锯齿
setOnClickListener(this);
flushState();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//设置当前view 大小
setMeasuredDimension(toggle_bg_on.getWidth(), toggle_btn_on.getHeight());
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//背景图片
canvas.drawBitmap(currBackBitmap, 0, getHeight() / 2 - toggle_bg_on.getHeight() / 2, paint);
//滑动按钮图片
canvas.drawBitmap(currBtnBitmap, slide_left, 0, paint);

}

@Override
public void onClick(View v) {
currState = !currState;
if (!isDrag) {
flushState();
}

}

/**
* 刷新当前状态
*/
private void flushState() {
if (currState) {//开
slide_left = toggle_bg_on.getWidth() - toggle_btn_off.getWidth();
currBackBitmap = toggle_bg_on;
currBtnBitmap = toggle_btn_on;
} else {//关
slide_left = 0;
currBackBitmap = toggle_bg_off;
currBtnBitmap = toggle_btn_off;
}
invalidate();
}

private int firstX, lastX;
boolean isDrag = false;//是否拖动

@Override
public boolean onTouchEvent(MotionEvent event) {
int maxLeft = getWidth() - currBtnBitmap.getWidth();//左边界做大值
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
firstX = lastX = (int) event.getX();
isDrag = false;
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - firstX) > 5) {
isDrag = true;
}
//计算手指在屏幕上移动的距离
int dis = (int) (event.getX() - firstX);
//将本次的位置设置给 lastX
lastX = (int) event.getX();
//根据手指移动的距离,改变slide_left的值
slide_left = slide_left + dis;
if (slide_left > maxLeft / 2) {
currBackBitmap = toggle_bg_on;
currBtnBitmap = toggle_btn_on;
} else {
currBackBitmap = toggle_bg_off;
currBtnBitmap = toggle_btn_off;
}
break;
case MotionEvent.ACTION_UP:
if (isDrag) {
if (slide_left > maxLeft / 2) {
currState = true;
} else {
currState = false;
}
flushState();
}
break;
}
flushView();
return true;
}

/**
* 刷新视图
*/
private void flushView() {
//对slide_left进行判断 0<= slide_left <= maxLeft
int maxLeft = getWidth() - currBtnBitmap.getWidth();//左边界做大值
slide_left = slide_left > 0 ? slide_left : 0;
slide_left = slide_left < maxLeft ? slide_left : maxLeft;
invalidate();
}

/**
* 是否打开
*
* @return
*/
public boolean isChecked() {
return currState;
}
}


attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyToggleBtn">
<attr name="isChecked" format="boolean" />
<attr name="backImageOff" format="reference" />
<attr name="backImageOn" format="reference" />
<attr name="slideImageOn" format="reference" />
<attr name="slideImageOff" format="reference" />
</declare-styleable>
</resources>


activity_test.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">

<com.sanmiao.mytest.myview.MyToggleBtn
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:backImageOff="@mipmap/img_toggle_bg_off"
app:slideImageOn="@mipmap/img_toggle_btn_on"
app:slideImageOff="@mipmap/img_toggle_btn_off"
app:backImageOn="@mipmap/img_toggle_bg_on"
app:isChecked="true" />

<com.sanmiao.mytest.myview.MyToggleBtn
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:slideImageOn="@mipmap/slide_button"
app:backImageOn="@mipmap/switch_background"
app:isChecked="true" />

</LinearLayout>


4.运行效果



5.说明

若按钮只有2张图片(背景和滑动图片)只需要在xml中添加 slideImageOn 和backImageOn

这两个属性就可以了;若有4张需要添加backImageOff、slideImageOn、slideImageOff、backImageOn这4个属性
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 自定义控件