最近,在項目開發中需要用到開關按鈕,因為業務需求,需要适應自己的App style,是以決定親自實操一遍,自定義一個控件。
業務需求:
1.開關點選事件
2.開關滑動事件
3.涉及了動态測量繪制文本的寬高
先上效果圖,如下:
因為比較簡單,沒有自定義屬性,注釋比較完整,是以貼上完整代碼給你們參考,有問題可以私聊。
完整代碼如下:
public class AutoButton extends View implements View.OnTouchListener{
//開關背景圖
private Bitmap bgBitmap;
//開關按鈕圖
private Bitmap btnBitmap;
private Paint paint;
//标記開關滑動的值
private int leftDis=;
//标記開關滑動的最大值
private int slidingMax;
//設定開關對應的文本
private final String text1="開";
private final String text2="關;
//标記開關狀态
private boolean mCurrent;
//标記點選事件
private boolean isClickable;
//标記滑動事件
private boolean isMove;
//開關打開的事件監聽器
private SoftFloorListener softFloorListener;
//開關關閉的事件監聽器
private HydropowerListener hydropowerListener;
//标記開關文本的寬度
float width1,width2;
//記錄文本中心點 cx1:繪制文本1的x坐标 cx2:繪制文本2的x坐标
//cy記錄繪制文本的高度
float cx1,cy,cx2;
//代碼執行個體化需要的方法
public AutoButton(Context context) {
this(context,null);
}
//在xml布局時需要用到的方法
public AutoButton(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public AutoButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
//初始化資料
private void initView() {
//加載背景圖
bgBitmap= BitmapFactory.decodeResource(getResources(), R.drawable.bg_switchbutton);
//加載開關按鈕圖 btnBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.btn_switchbutton);
paint=new Paint();
slidingMax=bgBitmap.getWidth()-btnBitmap.getWidth();
paint.setTextSize(35);
//測量繪制文本1的寬度
width1= paint.measureText(text1);
//測量文本的寬度
Paint.FontMetricsInt fontMetricsInt=paint.getFontMetricsInt();
cy=btnBitmap.getHeight()/2+(fontMetricsInt.descent-fontMetricsInt.ascent)/2;
width2= paint.measureText(text2);
cx2=(bgBitmap.getWidth()*2-btnBitmap.getWidth())/2-width2/2;
paint.setAntiAlias(true);
setOnTouchListener(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//根據加載圖檔設定控件的大小
setMeasuredDimension(bgBitmap.getWidth(),bgBitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//繪制背景圖
canvas.drawBitmap(bgBitmap,0,0,paint);
//繪制按鈕圖
canvas.drawBitmap(btnBitmap,leftDis,0,paint);
//根據不同狀态繪制不同顔色,不同位置的文本
if (mCurrent){
paint.setColor(Color.WHITE);
canvas.drawText(text2,cx2,cy,paint);
paint.setColor(Color.BLACK);
canvas.drawText(text1,cx1,cy,paint);
}else {
paint.setColor(Color.WHITE);
canvas.drawText(text1,cx1,cy,paint);
paint.setColor(Color.BLACK);
canvas.drawText(text2,cx2,cy,paint);
}
}
//根據事件重新整理視圖
private void flushView() {
mCurrent=!mCurrent;
if (mCurrent){
leftDis=slidingMax;
if (hydropowerListener!=null){
//按鈕打開監聽器
hydropowerListener.hydropower();
}
}else {
leftDis=0;
if (softFloorListener!=null){
//按鈕關閉監聽器
softFloorListener.softFloor();
}
}
invalidate();
}
//startX 标記手指按下的X坐标, lastX 标記移動後的x坐标
//disX 标記x方向移動的距離
float startX,lastX,disX;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
isClickable=true;
startX=event.getX();
isMove=false;
break;
case MotionEvent.ACTION_MOVE:
lastX=event.getX();
disX=lastX-startX;
//設定一個移動的門檻值
if (Math.abs(disX)<5) break;
isMove=true;
isClickable=false;
moveBtn();
startX=event.getX();
break;
case MotionEvent.ACTION_UP:
//點選事件
if (isClickable){
flushView();
}
//滑動事件
if (isMove){
if (leftDis>slidingMax/2){
mCurrent=false;
}else {
mCurrent=true;
}
flushView();
}
break;
}
return true;
}
//按鈕滑動時的位置控制
private void moveBtn() {
leftDis+=disX;
if (leftDis>slidingMax){
leftDis=slidingMax;
}else if (leftDis<0){
leftDis=0;
}
invalidate();
}
//設定按鈕打開監聽器
public void setSoftFloorListener(SoftFloorListener softFloorListener){
this.softFloorListener=softFloorListener;
}
//設定按鈕關閉監聽器
public void setHydropowerListener(HydropowerListener hydropowerListener){
this.hydropowerListener=hydropowerListener;
}
//設定按鈕打開監聽器接口
public interface SoftFloorListener{
void softFloor();
}
//設定按鈕打開監聽器接口
public interface HydropowerListener{
void hydropower();
}
}