自定义控件三:自定义开关,已写成小框架

本文详细介绍了一个自定义开关控件的实现过程,包括如何创建继承View的类、重写构造方法、设置背景及滑块资源,以及如何通过触摸事件实现开关状态的动态变化,并附带监听器设置教程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   自己亲手写个自定义开关,发现能学到很多东西,事件的回调,触摸事件的作用等,之前一直在写setOnClickListener却不知道它的含义,今天总算弄明白了


首先介绍这个小框架怎么用

到网盘下载http://pan.baidu.com/s/1bTOBNo

压缩文件夹名叫switch_Demo

然后把图片复制到drawable目录下

java文件复制到你的src工程中,

报错就改改包名即可


然后写UI

<span style="font-size:18px;"><mrzhou.com.toggleview_demo.ToggleView
        android:id="@+id/toggle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/></span>


注意:
<span style="font-size:18px;">mrzhou.com.toggleview_demo.ToggleView</span>
这个文件名是到ToggleView.java文件中,光标放在类名上,右键,copyP...什么来着,把路径全名复制下来,然后粘上



再然后写主代码:

<span style="font-size:18px;">import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private ToggleView mToggleView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //找到ToggleView这个控件id
        mToggleView = (ToggleView) findViewById(R.id.toggle);

        //给ToggleView这个控件设置背景
        mToggleView.setSwitchBackgroundResource(R.drawable.switch_background);

        //给ToggleView这个控件设置滑动块
        mToggleView.setSwitchSlideMenuResource(R.drawable.slide_button);

        //给ToggleView这个控件设置开关状态,是开还是关
        mToggleView.setSwitchState(true);

        mToggleView.setOnSwitchStateUpdateListener(new ToggleView.onSwitchUpdateListener() {
            @Override
            public void onStateUpdate(boolean state) {
                if (state == true) {
                    Toast.makeText(MainActivity.this, "开关已打开...", Toast.LENGTH_SHORT).show();
                } else if (state == false) {
                    Toast.makeText(MainActivity.this, "开关关闭了呢...", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
</span>




如果想看源码的小伙伴,将会有很大收获,里面逻辑性比较强,有回调机制和onTouchEvent的部分详解

下面送上看源码的思路:



* 1. 自定义开关  
> - 1. 写个类继承View,复写三个构造方法,拷贝包名到activity_main.xml中    OK
找到控件的ID,然后设置setSwitchBackgroundResource()和setSlideButtonResource(R.drawable.),setSwitchState


另外,简单学习一下这个知识.
measure -->layout(摆放子控件,一般没什么用,摆放child) --- > draw(绘制内容,比如绘制床单的花型)
分别是OnMeasure(指定子控件自己宽高) , onLayout  , onDraw()
三个方法在onResume()之后执行


然后通过setSwitchBackgroundResource(){
switchBackgroundBitmap = BitmapFactory.decode
}把drawble目录下的控件id转化成bitmap形式




然后重写onMeasure(设置控件宽高,),onDraw()(canvas是画布,画板),(只要绘制,就显示到桌面上)方法


//绘制背景
canvas.drawBitmap(switchBackgroundBitmap, ,  , )
init() -->new Paint()


//然后绘制滑块(并默认开关状态方法设置默认为false)
if(mSwitchState){
//开关状态为开
canvas.draw


然后获取 init newLeft = ,设置滑块x方向的位置
}else{
canvas.draw
}


然后xml的centerInParent,让控件居中


到这里,静态界面已经设计好








在ToggleView()里面写
onTouchEvent(){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
 isTouchMode = true;
mCurrentX = event.getX();
break;


case MotionEvent.ACTION_MOVE:
 isTouchMode = true;
mCurrentX = event.getX();
break;


case MotionEvent.ACTION_UP:
 isTouchMode = true;
mCurrentX = event.getX();
break;


}


然后重绘界面;
incalidate();//会引发ondraw被调用
}


boolrean isTouchMode = false;
onDraw()
{
if(isTouchMode){
//动态改变
    //如果触摸,就是动态改变,根据mCurrentX位置


          //  float newLeft = mCurrentX;
            //点击控件时,发现滑块没有在点击的位置??怎么办?让滑块向左移个0.5个滑块宽度即可
            float newLeft = mCurrentX - mSwitchSlideMenu_bitmap.getWidth()/2.0f;
            canvas.drawBitmap(mSwitchSlideMenu_bitmap, newLeft, 0, mPaint);
  
}else{
//这里表示静态,没有触摸的时候,复制之前的if。。。过来即可
  //绘制滑块(注意,滑块有两种状态,开和关)
            if (mSwitch_state_isTrueOrFalse) {
                //开
                canvas.drawBitmap(mSwitchSlideMenu_bitmap, 0, 0, mPaint);
            } else {
                //关
                float newLeft = mBitmap_switchBackground.getWidth() - mSwitchSlideMenu_bitmap.getWidth();
                canvas.drawBitmap(mSwitchSlideMenu_bitmap, newLeft, 0, mPaint);
            }
}






//发现newLeft 的范围没有限制,都划跑出去了。。。
下面在 float newLeft = mCurrentX - mSwitchSlideMenu_bitmap.getWidth()/2.0f;限制一下它的范围
int maxLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();
if(newLeft < 0 ){
newLeft = 0;
}else if(newLeft > maxLeft  ){
  newLeft = maxLeft;
}


//发现一松手, isTouchMode = false; 跑到静态上去了..
在 case MotionEvent.ACTION_UP:最下面写
float center = switchBackgroupBitmap.getWidth()/2.0f;
boolean current_State = mCurrentX < center;
mSwitch_state_isTrueOrFalse = current_State;




到这里,基本动态的搞定了


下面写监听...
首先. 在ToggleView()下面写接口
public interface OnSwitchStateUpdateListener(){
//状态回调,把当前状态传出去
void onStateUpdate(boolean state);
}


然后在MainActivity.java设置开关监听
toggleView.setOnSwitchStateUpdateListener(new SwitchStateUpdateListener(){
   if (state == true) {
                    Toast.makeText(MainActivity.this, "开关已打开...", Toast.LENGTH_SHORT).show();
                } else if (state == false) {
                    Toast.makeText(MainActivity.this, "开关已关闭,hhhhh", Toast.LENGTH_SHORT).show();
                }
});


然后在ToggleView中,添加设置接口对象的方法, 外部进行调用
public void setOnSwitchStateUpdateListener(
OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;



然后在case MotionEvent.ACTION_UP:最下面写:
boolean current_State = mCurrentX < center;


if(current_State != mSwitch_state_isTrueOrFalse && onSwitchStateListener!= null)  //onSwitchStateListener!= null 一旦toggleView.setOnSwitchStateUpdateListener(new SwitchStateUpdateListener()就不为空
{
onSwitchStateUpdateListener.onStateUpdate(current_State);//不会走抽象方法,只会走子类实现的方法
}
//并记录当前状态
mSwitch_state_isTrueOrFalse = current_State;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值