package yuan.jxau.cn.toggleview.view;
import android.content.Context;
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 yuan.jxau.cn.toggleview.R;
/**
* Created by 编程只服JAVA on 2016.11.26.
*/
/**
* 自定义开关
*
* Android界面绘制流程
* 测量 摆放 绘制
* measure->layout->draw
* | | |
* onMeasure->onLayout->onDraw 重写这些方法,实现自定义控件
*
* onResume()方法之后执行
*
* View
* onMeasure()(在这个方法里面指定自己的宽高)->onDraw()(绘制自己的内容)
*
* ViewGroup
* onMeasure(指定自己的宽高,所有子view的宽高)()->onLayout()(摆放所有子view)->onDraw()(绘制内容)
*/
public class ToggleView extends View {
private Bitmap switchBackgroud;
private Bitmap slideBackground;
private Boolean switchState;
private Paint paint;
private float currentX;
private Boolean isTouchMode = false;
private OnSwitchStateUpdateListener onSwitchStateUpdateListener;
/**
* 用于代码创建控件
* @param context
*/
public ToggleView(Context context) {
super(context);
init();
}
private void init() {
paint = new Paint();
}
/**
* 用于在xml里使用,可指定自定义属性
* @param context
* @param attrs
*/
public ToggleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
String namespace = "http://schemas.android.com/apk/res-auto";
int switchResouceBackground = attrs.getAttributeResourceValue(namespace ,"switch_background", R.drawable.switch_background);
int slideResouceBackGround = attrs.getAttributeResourceValue(namespace , "slide_button" , R.drawable.slide_button);
Boolean isOpen = attrs.getAttributeBooleanValue(namespace,"switch_state",false);
setSlideBackgroundResource(slideResouceBackGround);
setSwitchBackgroundResource(switchResouceBackground);
setState(isOpen);
}
/**
* 用于在xml里使用,可指定自定义属性,如果指定了样式,则走此构造函数
* @param context
* @param attrs
* @param defStyleAttr
*/
public ToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//重写测量方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(switchBackgroud.getWidth(),switchBackgroud.getHeight());
}
//重写绘制方法
@Override
protected void onDraw(Canvas canvas) {
//1.绘制背景
canvas.drawBitmap(switchBackgroud,0,0,paint);
//2.绘制滑块
if (isTouchMode){
//用户触摸状态
float newLeft = currentX - slideBackground.getWidth()/2.0f;
/**
* 限定滑块滑动范围
*/
int maxLeft = switchBackgroud.getWidth() - slideBackground.getWidth();
if(newLeft < 0){
newLeft = 0;
}else if (newLeft > maxLeft){
newLeft = maxLeft;
}
//根据当前用户触摸到的位置绘制滑块
canvas.drawBitmap(slideBackground, newLeft , 0,paint);
}else{
if (switchState){
//打开状态
int newLeft = switchBackgroud.getWidth() - slideBackground.getWidth();
canvas.drawBitmap(slideBackground,newLeft,0,paint);
}else {
//关闭状态
canvas.drawBitmap(slideBackground,0,0,paint);
}
}
}
//重写触摸事件,响应用户的触摸
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN :
currentX = event.getX();
isTouchMode = true;
break;
case MotionEvent.ACTION_MOVE :
currentX = event.getX();
break;
case MotionEvent.ACTION_UP:
isTouchMode = false;
currentX = event.getX();
float center = switchBackgroud.getWidth()/2.0f;
Boolean state = currentX >center;
/**
* 如果ToggleView的状态发生改变,通知外面ToggleView的状态已经发生了变化
*/
if (state != switchState && onSwitchStateUpdateListener != null){
onSwitchStateUpdateListener.onStateUpdate(state);
}
switchState = state;
break;
}
//#######重绘界面,onDraw()被调用,里面的变量会重新生效,界面会更新########
invalidate();
return true;//返回true:消费了用户的触摸事件
}
/**
* 设置背景图片
* @param switch_background
*/
public void setSwitchBackgroundResource(int switch_background) {
switchBackgroud = BitmapFactory.decodeResource(getResources(), switch_background);
}
/**
* 设置滑块的背景图片
* @param slide_button
*/
public void setSlideBackgroundResource(int slide_button) {
slideBackground = BitmapFactory.decodeResource(getResources(), slide_button);
}
public void setState(boolean switchState) {
//状态回调,将当前状态传出去
this.switchState = switchState;
}
//状态变化的监听方法,当ToggleView的状态发生改变的时候,会通知外面。
public void setOnSwitchStateUpdateListener(OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
}
public interface OnSwitchStateUpdateListener{
void onStateUpdate(Boolean state);
}
}
自定义属性attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ToggleView">
<attr name="switch_background" format="reference"/>
<attr name="slide_button" format="reference"/>
<attr name="switch_state" format="boolean"/>
</declare-styleable>
</resources>
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="yuan.jxau.cn.toggleview.MainActivity">
<yuan.jxau.cn.toggleview.view.ToggleView
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/taggleview"
android:background="@android:color/transparent"/>
</RelativeLayout>