Android自定义View-SwitchView(自定义开关)

Android自定义View-SwitchView(自定义开关)

Android自定义开关,效果图如图:

  

一个是关的状态,一个是开的状态,通过监听回调将滑块滑动状态返回到调用界面。

实质上底层是一个背景,然后在这个背景之上增加了一个可移动滑块,通过判断滑块滑动之后的位置,在背景图中心点左边表示开关是开,在右边表示是关。

      

1.自定义view类

SwitchView:主要是用来绘制开关背景及滑块,并通过滑块移动位置来判断状态。

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.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author M.xang
 * @时间 2019年4月22日
 * @描述 自定义开关控件
 */
public class SwitchView extends View {

	private Bitmap switchBackgroupBitmap = null; // 背景图片
	private Bitmap slideButtonBitmap = null; // 滑块图片
	private Paint paint = null; // 画笔
	private boolean mSwitchState = false; // 开关状态, 默认false
	private float currentX;
	private int width_bg = 0, height_bg = 0;
	@SuppressWarnings("unused")
	private int width_slide = 0, height_slide = 0;

	/**
	 * 用于代码创建控件
	 * 
	 * @param context
	 */
	public SwitchView(Context context) {
		super(context);
		init();
	}

	/**
	 * 用于在xml里使用, 可指定自定义属性
	 *
	 * @param context
	 * @param attrs
	 */
	public SwitchView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
		// 获取配置的自定义属性
		setSwitchBackgroundResource(R.drawable.switch_bg);// 开关背景
		setSlideButtonResource(R.drawable.switch_control);// 滑块背景
	}

	private void init() {
		paint = new Paint();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 依据背景图片来确定控件大小
		width_bg = switchBackgroupBitmap.getWidth();
		height_bg = switchBackgroupBitmap.getHeight();
		if (slideButtonBitmap != null) {
			width_slide = slideButtonBitmap.getWidth();
			height_slide = slideButtonBitmap.getHeight();
		}
		setMeasuredDimension(width_bg, height_bg);
	}

	// Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.
	@Override
	protected void onDraw(Canvas canvas) {
		// 1. 绘制背景
		canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);
		// 2. 绘制滑块
		if (isTouchMode) {
			// 根据当前用户触摸到的位置画滑块
			// 让滑块向左移动自身一半大小的位置
			float newLeft = currentX - width_slide / 2.0f;
			int maxLeft = width_bg - width_slide;
			// 限定滑块范围
			if (newLeft < 0) {
				newLeft = 0; // 左边范围
			} else if (newLeft > maxLeft) {
				newLeft = maxLeft; // 右边范围
			}
			canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
		} else {
			// 根据开关状态boolean, 直接设置图片位置
			if (mSwitchState) {// 开,开关滑块置于最右边,显示ON
				canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);
			} else {// 关,开关滑块置于最左边,显示OFF
				int newLeft = width_bg - width_slide;
				if (slideButtonBitmap != null) {
					canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
				}
			}
		}
	}

	boolean isTouchMode = false;
	private OnSwitchStateUpdateListener onSwitchStateUpdateListener;

	// 重写触摸事件, 响应用户的触摸.
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			isTouchMode = true;
			currentX = event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			currentX = event.getX();
			break;
		case MotionEvent.ACTION_UP:
			isTouchMode = false;
			currentX = event.getX();
			float center = width_bg / 2.0f;
			// 根据当前按下的位置, 和控件中心的位置进行比较.
			boolean state = currentX < center;// 离开位置小于中心位置,点击了关,true
			// 如果开关状态变化了, 通知界面. 里边开关状态更新了.
			if (state != mSwitchState && onSwitchStateUpdateListener != null) {
				// 把最新的boolean, 状态传出去了
				onSwitchStateUpdateListener.onStateUpdate(state);
			}
			mSwitchState = state;
			break;
		}
		// 重绘界面
		invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新
		return true; // 消费了用户的触摸事件, 才可以收到其他的事件.
	}

	/**
	 * 设置背景图
	 *
	 * @param switchBackground
	 */
	public void setSwitchBackgroundResource(int switchBackground) {
		if (switchBackground > 0) {
			switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);
		} else {
			Log.e("---SlideSwitchView--->", "没有设置开关背景图,应设置app:switch_background=\"@drawable/xxx\"");
		}
	}

	/**
	 * 设置滑块图片资源
	 *
	 * @param slideButton
	 */
	public void setSlideButtonResource(int slideButton) {
		if (slideButton > 0) {
			slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
		} else {
			Log.e("---SlideSwitchView--->", "没有设置滑动按钮图,应设置app:slide_button=\"@drawable/xxx\"");
		}
	}

	/**
	 * 设置开关初始状态
	 * 
	 * @param mSwitchState true:默认开,false:默认关
	 */
	public void setSwitchState(boolean mSwitchState) {
		this.mSwitchState = mSwitchState;
	}

	/**
	 * 设置开关初始状态
	 * 
	 * @param state true:开,false:关
	 */
	public void setSwitchOpen(boolean state) {
		mSwitchState = state;
		invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新
	}

	/**
	 * @author M.xang
	 * @时间 2019年4月22日
	 * @描述 开关状态回调
	 */
	public interface OnSwitchStateUpdateListener {
		/**
		 * 状态回调, 开关当前状态
		 * 
		 * @param state
		 */
		void onStateUpdate(boolean state);
	}

	/**
	 ** 将回调对象传到控件
	 * 
	 * @param onSwitchStateUpdateListener
	 */
	public void setOnSwitchStateUpdateListener(OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
		this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
	}

}

2.使用

再布局中的使用:

<com.view.SwitchView
            android:id="@+id/sw_computer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

在Activity中调用:

// 进行实例化
SwitchView sw_computer = sw_computer = UIUtil.findView(this, R.id.sw_computer);
// 设置开关的初始状态,默认是关闭的
sw_computer.setSwitchState(false);

// 开关点击事件
sw_computer.setOnSwitchStateUpdateListener(new OnSwitchStateUpdateListener() {
    @Override
    public void onStateUpdate(boolean state) {
	
        // state 为 true是开,false是关

    }
});

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值