自定义开关
2018-10-02 本文已影响9人
GeekGray
自定义开关
自定义一个类继承View
/**
*
* @author: Hashub.NG
* @description:
* @update: 2018年7月26日 上午8:59:25
* 一个视图从创建到显示过程中的主要方法
* //1.构造方法实例化类
* //2.测量-measure(int,int)-->onMeasure();
* 如果当前View是一个ViewGroup,还有义务测量孩子
* 孩子有建议权
* //3.指定位置-layout()-->onLayout();
* 指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
* //4.绘制视图--draw()-->onDraw(canvas)
* 根据上面两个方法参数,进入绘制
*/
public class MyToggleButton extends View implements View.OnClickListener
{
private Bitmap backgroundBitmap;
private Bitmap slidingBitmap;
/**
* 距离左边最大距离
*/
private int slidLeftMax;
private Paint paint;
private int slideLeft;
private float startX;
private float lastX;
private boolean isOpen=false;
/**
* 如果我们在布局文件使用该类,将会用这个构造方法实例该类,如果没有就崩溃
* @param context
* @param attrs
*/
public MyToggleButton(Context context)
{
super(context);
initView();
}
.......
}
实例化控件
//创建两个Bitmap,这样才能绘制
private Bitmap backgroundBitmap;
private Bitmap slidingBitmap;
private void initView()
{
paint=new Paint();
paint.setAntiAlias(true);//设置抗锯齿,光滑
backgroundBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);//从资源文件获取
slidingBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
//背景宽度-遮盖部分的宽度
slidLeftMax=backgroundBitmap.getWidth()-slidingBitmap.getWidth();
setOnClickListener(this);//设置点击事件
}
重写onMeasure()测量方法
/**
* 视图的测量
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//保存测量结果
setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
}
绘制
/**
* 绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas)
{
//super.onDraw(canvas);
canvas.drawBitmap(backgroundBitmap, 0, 0,paint);//绘制Bitmap
canvas.drawBitmap(slidingBitmap, slideLeft,0, paint);
}
开关的点击事件
/**
* true:点击事件生效,滑动事件不生效
* false:点击事件不生效,滑动事件生效
*/
private boolean isEnableClick=true;
@Override
public void onClick(View v)
{
if(isEnableClick)
{
isOpen=!isOpen;
flushView();
}
}
private void flushView()
{
if(isOpen)
{
slideLeft=slidLeftMax;
}
else
{
slideLeft=0;
}
invalidate();//会导致onDraw()执行
}
开关的滑动事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP)
滑动在Y轴上无变化,记录X轴的坐标即可
event.getX()和event.getRawX()的区别
private float startX;//记录按下的横坐标
private float lastX;//记录原始值,该值只记录一次
@Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);//执行父类的方法
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
//1.记录按下的坐标
lastX=startX=event.getX();
isEnableClick=true;
break;
case MotionEvent.ACTION_MOVE:
//2.计算结束值
float endX=event.getX();
//3.计算偏移量
float distanceX=endX-startX;
// slideLeft = (int) (slideLeft + distanceX);//动态改变
slideLeft+=distanceX;
//4.有可能越界,屏蔽非法值
if(slideLeft<0)
{
slideLeft=0;
}
else if(slideLeft>slidLeftMax)
{
slideLeft=slidLeftMax;
}
//5.刷新
invalidate();
//6.数据还原,startX重新赋值
startX=event.getX();
if(Math.abs(endX-lastX)>5)
{
//滑动
isEnableClick=false;
}
break;
case MotionEvent.ACTION_UP://根据距离松开回弹
if(!isEnableClick)
{
if(slideLeft>slidLeftMax/2)
{
//显示按钮开
isOpen=true;
}
else
{
isOpen=false;
}
flushView();
}
break;
}
return true;//处理触摸事件
}
解决事件的冲突
/**
* true:点击事件生效,滑动事件不生效
* false:点击事件不生效,滑动事件生效
*/
private boolean isEnableClick=true;
最后的值-原始值如果大于5个px,就认为是滑动,点击事件不生效,滑动事件生效
if(Math.abs(endX-lastX)>5)
{
//滑动
isEnableClick=false;
}