昨晚我写的这么详细的文章....提交成功后我就回去睡觉了.....今天一大早起来不见了,TAT 随便写点自己能看懂的当笔记吧。这个控件是我学习他人的~
1、创建新的toggle类继承自view(其中含有attributeSet attrs的构造方法是和xml有关的),然后可以通过重写setBackgroundResource()或者自己的方法去设置好控件的图样,大小,空间啥的。记得要在layout布局里面导包(记得加Id),才能使用我们自己的控件。
2、重写view中的绘制方法
view中主要是onmeasure()和ondraw()在先后起作用。而viewgroup中间还有个onlayout(),在这我们继承的是view,所以先测量,再绘画。
首先要找到控件上的图片,可以在setBackgroundResource()或者自己的方法中用bitmap=bitmapfactory.decodeResource(getResources,传下来的int R值)来找到图片,设置它。
然后再重写onMeasure()方法
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
查看view中的源码发现onmeasure是有setmeasuredemention这个方法来设置宽高的,所以就可以直接也再onmeasure下重写这个方法。然后ondraw,new个画笔,
// 1. 绘制背景 canvas.drawBitmap(图像, 0, 0, paint);
因为要通过判断初始时是否开关为开,我又设置了一个方法去判断开关,一开始我写的是:
public boolean setOnOff(boolean boo){
return boo;
}
发现这样不利于放入if语句中,于是我修改了下,变成:
public void setSwitchState(boolean mSwitchState) {
this.mSwitchState = mSwitchState;
}
然后就能在ondraw中通过if去设置位置了。
在ondraw()下重写(在里面会报错,java基础啊)
public boolean onTouchEvent (MotionEvent event){ switch (event.getAction()){ case MotionEvent.ACTION_DOWN: syso(event.getX()); break;
记得return true来消费用户的点击事件,消费了用户的点击事件才能够往下传。在这里syso还可以刚好打印出来该控件的宽高啥的。
值得注意的是,上面的if else语句中是发生在“未”点击的情况下的,我们想要通过监控去实现重绘,就要在if else外面再加一层判断是否按下。就是加入private boolean touch=false;按下的时候在监听中设置为true,不按的时候为false。
对了,记得设置限度,防止控件中的图片在不可视区“跑走”。
对了,记得设置限度,防止控件中的图片在不可视区“跑走”。
记得在Ontouch监听中使用
invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新
还有一点:因为我们是通过拉动滑块中点去移动的,可是现在系统默认我们是通过拉动左上角滑动的,所以要解决的话,不用在“触摸”的上下功夫,在滑块的显示上下功夫就行了,设置我们点击的时候,不是直接等于event.getX();而是
float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;
这是在最大那个if里面的,不是在ontouch监控里面的哦!
最重要的一点:设置监听回调:
参考以前的onclicklistener监听啥的,在外部调用是:
toggleView.setOnSwitchStateUpdateListener(new OnSwitchStateUpdateListener(){
@Override
public void onStateUpdate(boolean state) {
Toast.makeText(getApplicationContext(), "state: " + state, 0).show();
}
});
在toggle中,我们要得到这个返回值“state”,
即在toggle中:
public interface OnSwitchStateUpdateListener{
// 状态回调, 把当前状态传出去
void onStateUpdate(boolean state);
}
public void setOnSwitchStateUpdateListener(
OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
}
在上面可以设置逻辑:
if(state != mSwitchState && onSwitchStateUpdateListener != null){
// 把最新的boolean, 状态传出去了
onSwitchStateUpdateListener.onStateUpdate(state);
}
TAT........
参考valus下的源码发现 ,自定义属性格式可以这么写:(好处,不用代码写,用xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ToggleView">
<attr name="switch_res" format="reference"/>
<attr name="slide_res" format="reference"/>
<attr name="state"format="boolean"/>
</declare-styleable>
</resources>
设置完这些,可以在gen目录下的R文件生成相应的东西的。
如何用呢,就可以直接在activty_main中就像调用android:swtich_res。。。。这么用,当然,要在上面写上
xmlns:随便起名="http://schemas.android.com/apk/res/包名"然后在下面就可以
随便起名:switch_res=""这样用了。
这些东西在toggle的第二个或者第三个构造方法中可以用的
String namespace = "http://schemas.android.com/apk/res/com.itheima74.toggleview";
int switchBackgroundResource = attrs.getAttributeResourceValue(namespace , "switch_background", -1);
int slideButtonResource = attrs.getAttributeResourceValue(namespace , "slide_button", -1);
mSwitchState = attrs.getAttributeBooleanValue(namespace, "switch_state", false);
setSwitchBackgroundResource(switchBackgroundResource);
setSlideButtonResource(slideButtonResource);
这样做的好处是可以封装成一个完整的控件由别人任意使用~