自己亲手写个自定义开关,发现能学到很多东西,事件的回调,触摸事件的作用等,之前一直在写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;