滑动开关:
测量:设置自己显示在屏幕上的宽高 onMeasure
布局:设置自己显示在屏幕上的位置(只有在自定义的viewGroup中才用到) onLayout
绘制:控制显示在屏幕上的样子(自定义viewGroup时不需要这个) onDraw
view和viewGroup的区别
相同点:都需要进行测量
不同点:viewGroup主要控制子view如何摆放,所以必须实现onLayout
view没有子view,所以不需要onLayout方法,但是必须实现onDraw
第一:xml文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<heimatogglebutton.ncs.yeyy.togglebutton.view.ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toggleButton"
android:layout_centerInParent="true"/>
</RelativeLayout>
第二:自定义Button
package heimatogglebutton.ncs.yeyy.togglebutton.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by yeyy on 2016/4/12.
*/
public class ToggleButton extends View {
private ToggleState toggleState = ToggleState.Open; //开关的状态
private Bitmap slideBg;//滑动块图片
private Bitmap switchBg;//背景图片
private int currentX;//当前触摸点X坐标
private boolean isSliding = false;//正在滑动的状态
/**
* 如果你的view需要在java代码中动态new出来,走的是这个构造方法
*
* @param context
*/
public ToggleButton(Context context) {
super(context);
}
/**
* 如果你的view只是在布局文件中使用,只需要重写这个方法
*
* @param context
* @param attrs
*/
public ToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 枚举
public enum ToggleState {
Open, Close;
}
/**
* 设置滑动块的背景图片
*
* @param slideBackgroundResource
*/
public void setSlideBackgroundResource(int slideBackgroundResource) {
slideBg = BitmapFactory.decodeResource(getResources(), slideBackgroundResource);
}
/**
* 设置滑动开关的背景图片
*
* @param switchBackgroundResource
*/
public void setSwitchBackgroundResource(int switchBackgroundResource) {
switchBg = BitmapFactory.decodeResource(getResources(), switchBackgroundResource);
}
/**
* 设置开关的状态
*
* @param state
*/
public void setToggleState(ToggleState state) {
toggleState = state;
}
/**
* 设置当前控件在屏幕上显示的宽高
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(switchBg.getWidth(), switchBg.getHeight());
}
/**
* 绘制自己显示在屏幕是的样子
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制背景图片
// left 第二个参数 图片的左边的x坐标
// top 第三个参数 图片顶部的y坐标
canvas.drawBitmap(switchBg, 0, 0, null);
// 绘制滑动块的图片
// 滑动中的逻辑
if (isSliding) {//如果正在滑动
// 限制滑动块左右滑动的边界
int left = currentX - slideBg.getWidth() / 2;
if (left < 0) left = 0;
if (left > (switchBg.getWidth() - slideBg.getWidth())) {
// 设置右边的滑动界限
left = switchBg.getWidth() - slideBg.getWidth();
}
canvas.drawBitmap(slideBg, left, 0, null);
} else {//没有滑动的时候
// 此时抬起,根据state去绘制滑动块的位置
if (toggleState == ToggleState.Open) {
canvas.drawBitmap(slideBg, switchBg.getWidth() - slideBg.getWidth(), 0, null);
} else {
canvas.drawBitmap(slideBg, 0, 0, null);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
currentX = (int) event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isSliding = true;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
isSliding = false;
// 背景图片宽的一半
int centerX = switchBg.getWidth() / 2;
// 判断当滑动块滑动的时候在左边右边滑动的位置来判断显示当前是开还是关
if (currentX > centerX) {
// open 当点击一下但是没有滑动,比如已经滑动到开启,然后又原地点击了滑动块一次显示关闭了,需要判断
if (toggleState!=ToggleState.Open){//当原地点击了但是状态没有改变,不是open时
toggleState = ToggleState.Open;//仍然设置为open
if (listener!=null){
// 调用接口
listener.onToggleStateChange(toggleState);
}
}
} else {
// close
if (toggleState!=ToggleState.Close){//当原地点击了但是状态没有改变,不是close时
toggleState = ToggleState.Close;
if (listener!=null){
listener.onToggleStateChange(toggleState);
}
}
}
break;
}
invalidate();//当你需要调用onDraw方法的时候,就需要invalidate(),来进行重绘,不要直接调用onDraw方法
return true;
}
private OnToggleStateChangeListener listener;
public void setOnToggleStateChangeListener(OnToggleStateChangeListener listener){
this.listener=listener;
}
public interface OnToggleStateChangeListener{
void onToggleStateChange(ToggleState state);
}
}
第三:mainActivity
package heimatogglebutton.ncs.yeyy.togglebutton;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import heimatogglebutton.ncs.yeyy.togglebutton.view.ToggleButton;
public class MainActivity extends Activity {
private ToggleButton toggleBut;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleBut = (ToggleButton) findViewById(R.id.toggleButton);
// 滑动块的背景图片
toggleBut.setSlideBackgroundResource(R.drawable.switch_background);
// 设置滑动开关的背景图片
toggleBut.setSwitchBackgroundResource(R.drawable.slide_button_background);
// 设置开关的状态
toggleBut.setToggleState(ToggleButton.ToggleState.Open);
toggleBut.setOnToggleStateChangeListener(new ToggleButton.OnToggleStateChangeListener() {
@Override
public void onToggleStateChange(ToggleButton.ToggleState state) {
Toast.makeText(MainActivity.this,
state== ToggleButton.ToggleState.Close.Open?"开启":"关闭",
Toast.LENGTH_LONG).show();
}
});
}
}
注意:
滑动块的滑动位置如何取坐标
源码地址:http://download.csdn.net/detail/csdnyuandaimaxuexi/9489948