您的位置:首页 > 其它

自定义开关控件(ToggleView)继承View实现

2016-11-27 12:36 375 查看
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐