自定义滑动开关就是控制右图在左图上左右滑动实现的效果
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:itheima="http://schemas.android.com/apk/res/com.itheima.togglebutton85"
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"
tools:context=".MainActivity" >
<com.itheima.togglebutton85.MyToggleButton
android:id="@+id/toggle_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
itheima:slideBackground="@drawable/slide_background2"
itheima:slideIcon="@drawable/slide_icon2"
itheima:state="false"
/>
</RelativeLayout>
public class MainActivity extends Activity {
private MyToggleButton toggleButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleButton = (MyToggleButton) findViewById(R.id.toggle_button);
toggleButton.setOnStateChangedListener(new OnStateChangedListener() {
@Override
public void onStateChanged(boolean state) {
Toast.makeText(MainActivity.this, state ? "开" : "关", Toast.LENGTH_SHORT).show();
}
});
}
}
MyToggleButton.java
public class MyToggleButton extends View {
/** 开关按钮背景图片 */
private Bitmap background;
/** 开关按钮的滑块icon */
private Bitmap slideIcon;
/** 开关按钮的状态 */
private boolean state;
/** 开关按钮状态改变的监听器 */
private OnStateChangedListener mOnStateChangedListener;
/** 滑块背景图片的宽 */
private int backgroundWidth;
/** 滑块背景图片的高 */
private int backgroundHeight;
/** 滑块icon图片的宽*/
private int slideIconWidth;
/** 滑块icon图片的高 */
private int slideIconHeight;
/** 滑块icon left坐标 */
private int slideIconLeft;
/** 滑块向右移动的时候,滑块left的最大值 */
private int maxSlideIconLeft;
public MyToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
// 自定义属性的命令空间
String namespace = "http://schemas.android.com/apk/res/com.itheima.togglebutton85";
// 读取自定义属性
// 读取滑块图片属性
int slideBackgroundResId = attrs.getAttributeResourceValue(namespace, "slideBackground", -1);
int slideIconResId = attrs.getAttributeResourceValue(namespace, "slideIcon", -1);
if (slideBackgroundResId != -1 && slideIconResId != -1) {
setSwitchImage(slideBackgroundResId, slideIconResId);
}
// 读取开关状态属性
boolean state = attrs.getAttributeBooleanValue(namespace, "state", false);
setState(state);
}
/**
* 设置开关的图片
* @param slideBackgroundResId 开关的背景图片资源id
* @param slideIconResId 开关上面的滑块icon
*/
public void setSwitchImage(int slideBackgroundResId, int slideIconResId) {
background = BitmapFactory.decodeResource(getResources(), slideBackgroundResId);
slideIcon = BitmapFactory.decodeResource(getResources(), slideIconResId);
backgroundWidth = background.getWidth();
backgroundHeight = background.getHeight();
slideIconWidth = slideIcon.getWidth();
slideIconHeight = slideIcon.getHeight();
maxSlideIconLeft = backgroundWidth - slideIconWidth;
}
/** 设置开关按钮的状态 */
public void setState(boolean state) {
checkState(state);
if (state) {
// 如果要设置成开的状态,则把滑块画图到最右边
slideIconLeft = maxSlideIconLeft;
} else {
// 如果要设置成关的状态,则把滑块画图到最左边
slideIconLeft = 0;
}
}
public void setOnStateChangedListener(OnStateChangedListener mOnStateChangedListener) {
this.mOnStateChangedListener = mOnStateChangedListener;
}
/** 开关按钮状态改变的监听器 */
public interface OnStateChangedListener {
/**
* 状态发生改变的时候
* @param state ture代表开,false代表关
*/
void onStateChanged(boolean state);
}
/**
* 对View进行测量的方法
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(backgroundWidth, backgroundHeight); // 设置View的测量的宽高
}
/** 把View画出来的方法
* @param canvas 画布
* */
@Override
protected void onDraw(Canvas canvas) {
// 画滑块的背景
int left = 0;
int top = 0;
canvas.drawBitmap(background, left, top, null);
// 画滑块icon
canvas.drawBitmap(slideIcon, slideIconLeft, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
// 滑动的时候计算滑块left = 触摸位置event.getX() – 滑块宽 / 2
slideIconLeft = (int) (event.getX() - slideIconWidth / 2);
// 预防滑动位置超出范围
if (slideIconLeft < 0) {
// 滑块往左移动时,left不能小于0
slideIconLeft = 0;
} else if (slideIconLeft > maxSlideIconLeft) {
// 滑块往右移动时,滑块left的最大值 = 背景宽 – 滑块宽
slideIconLeft = maxSlideIconLeft;
}
break;
case MotionEvent.ACTION_UP:
if (event.getX() < backgroundWidth / 2) {
// 手指松开时,计算滑块应该滑到最左边,还是滑到最右边: 如果手指抬起的位置 < 背景宽 / 2,把滑块滑到最左边
slideIconLeft = 0;
checkState(false);
} else {
// 否则滑到最右边
slideIconLeft = maxSlideIconLeft;
checkState(true);
}
break;
}
invalidate(); // 重新刷新View,内部会调用onDraw方法
return true;
}
private void checkState(boolean state) {
if (this.state != state) {
// 原来的状态和现在的状态如果不一样,则状态发生了改变
this.state = state;
// 如果状态发生改变,则通知监听器
if (mOnStateChangedListener != null) {
mOnStateChangedListener.onStateChanged(state);
}
}
}
}