一个视图从创建到显示过程中的主要方法:
1.构造方法实例化类
public MyToggleButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
bavkgroundBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.a);
slidingBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.b);
slideLeftMax = bavkgroundBitmap.getWidth() - slidingBitmap.getWidth();
paint=new Paint();
paint.setAntiAlias(true);//设置抗锯齿
setOnClickListener(this);
}
2.测量maesure(int,int) onMeasure 如果是viewgroup ,还要测量孩子
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(bavkgroundBitmap.getWidth(),bavkgroundBitmap.getHeight());
}
3.指定位置 layout() onLayout() 指定控件的位置,一般view不用写,viewgroup的时候才需要
4.绘制视图 draw() onDraw(canvas)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bavkgroundBitmap,0,0,paint);
canvas.drawBitmap(slidingBitmap,slideLeft,0,paint);
}
onTouchEvent:
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN://手指按下
break;
case MotionEvent.ACTION_MOVE://手指滑动
break;
case MotionEvent.ACTION_UP://手指离开
break;
}
return true;
}
实现开关的点击事件,点击开关按钮的时候为打开或为关闭:
private boolean isOpen=false; //默认打开
@Override
public void onClick(View v) {
isOpen = !isOpen;
flushView();
}
private void flushView() {
if(isOpen){
slideLeft = slideLeftMax;
}else
{
slideLeft=0;
}
invalidate();//会导致onDraw()执行
}
实现滑动功能,自动回弹功能,在手指滑到接近开的位置时为关闭状态,当接近关的位置时为打开状态:
private float startX;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//1.记录按下的坐标
startX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
//2.计算结束值
float endX=event.getX();
//3.计算偏移量
float distance = endX - startX;
slideLeft = (int) (slideLeft + distance);
//4.屏蔽非法值
if(slideLeft < 0){
slideLeft = 0;
}else if(slideLeft > slideLeftMax){
slideLeft = slideLeftMax;
}
//5.刷新
invalidate();
//6.数据还原
startX = event.getX();
break;
case MotionEvent.ACTION_UP:
if(slideLeft > slideLeftMax/2){
isOpen = true;
}else {
isOpen = false;
}
flushView();
break;
}
return true;
}
解决点击事件和触摸事件的冲突:
private boolean isEnableClick = true;//点击事件生效
@Override
public void onClick(View v) {
if(isEnableClick) {
isOpen = !isOpen;
flushView();
}
}
设置只要手指滑动一点点,就认为是滑动,此时点击事件失效:
private float lastX;
lastX = startX = event.getX();
if(Math.abs(endX - lastX) > 5){
isEnableClick= false;
}
当点击事件生效的时候开关按钮不回弹,当点击事件失效的时候实现回弹。
case MotionEvent.ACTION_UP:
if(!isEnableClick){
if(slideLeft > slideLeftMax/2){
isOpen = true;
}else {
isOpen = false;
}
flushView();
}
源码:
public class MyToggleButton extends View implements View.OnClickListener{
private Bitmap bavkgroundBitmap;
private Bitmap slidingBitmap;
private int slideLeftMax;
private Paint paint;
private int slideLeft;
public MyToggleButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
bavkgroundBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.a);
slidingBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.b);
slideLeftMax = bavkgroundBitmap.getWidth() - slidingBitmap.getWidth();
paint=new Paint();
paint.setAntiAlias(true);//设置抗锯齿
setOnClickListener(this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(bavkgroundBitmap.getWidth(),bavkgroundBitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bavkgroundBitmap,0,0,paint);
canvas.drawBitmap(slidingBitmap,slideLeft,0,paint);
}
private boolean isOpen=false;
private boolean isEnableClick = true;//点击事件生效
@Override
public void onClick(View v) {
if(isEnableClick) {
isOpen = !isOpen;
flushView();
}
}
private void flushView() {
if(isOpen){
slideLeft = slideLeftMax;
}else
{
slideLeft=0;
}
invalidate();//会导致onDraw()执行
}
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();
break;
case MotionEvent.ACTION_MOVE:
//2.计算结束值
float endX=event.getX();
//3.计算偏移量
float distance = endX - startX;
slideLeft = (int) (slideLeft + distance);
//4.屏蔽非法值
if(slideLeft < 0){
slideLeft = 0;
}else if(slideLeft > slideLeftMax){
slideLeft = slideLeftMax;
}
//5.刷新
invalidate();
//6.数据还原
startX = event.getX();
if(Math.abs(endX - lastX) > 5){
isEnableClick= false;
}
break;
case MotionEvent.ACTION_UP:
if(!isEnableClick){
if(slideLeft > slideLeftMax/2){
isOpen = true;
}else {
isOpen = false;
}
flushView();
}
break;
}
return true;
}
}