android togglebutton 自定义,Android自定义ToggleButton

本文详细介绍了如何实现一个自定义的ToggleButton,包括其内部的滑动效果、绘制逻辑和触摸事件处理。代码中展示了如何通过设置测量、绘制以及触摸监听来创建一个具备左右滑动切换状态功能的按钮,同时支持动画过渡。
摘要由CSDN通过智能技术生成

效果预览

7f7616a5d295331996aea95090995d14.gif

代码实现

public class ToggleButton extends View {

private int mLineWidth = 5;

private int mTextSize = 18;

private TextPaint mTextPaint = null;

private int mTouchSlop = 0;

private boolean isTouchMove = false;

private int offsetX = 0;

private int contentWidth = 0;

private int contentHeight = 0;

private int slideBarRadius;

float startX = 0f;

float startY = 0f;

private int STATUS_LEFT = 0;

private int STATUS_RIGHT = 1;

private int mState = STATUS_LEFT;

private ValueAnimator mSlideAnimator = null;

public ToggleButton(Context context) {

this(context, null);

}

public ToggleButton(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public ToggleButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

//设置此项true,否则无法滑动

mTextPaint = initPaint();

mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() / 2;

setClickable(true);

setFocusable(true);

setFocusableInTouchMode(true);

setBackgroundColor(0xffffffff);

}

private TextPaint initPaint() {

// 实例化画笔并打开抗锯齿

TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);

paint.setAntiAlias(true);

paint.setStrokeWidth(dpTopx(mLineWidth));

paint.setTextSize(dpTopx(mTextSize));

return paint;

}

private float dpTopx(int dp) {

return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

if (heightMode == MeasureSpec.UNSPECIFIED) {

heightSize = getPaddingTop() + getPaddingBottom() + 100;

} else if (heightMode == MeasureSpec.AT_MOST) {

int disire = getPaddingTop() + getPaddingBottom() + 100;

heightSize = Math.min(disire, heightSize);

}

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

if (widthMode == MeasureSpec.UNSPECIFIED) {

widthSize = getPaddingTop() + getPaddingBottom() + 280;

} else if (widthMode == MeasureSpec.AT_MOST) {

int disire = getPaddingTop() + getPaddingBottom() + 280;

widthSize = Math.min(disire, widthSize);

}

setMeasuredDimension(widthSize, heightSize);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

int w = getWidth();

int h = getHeight();

int lineWidthPixel = (int) mTextPaint.getStrokeWidth();

contentWidth = w - 2 * lineWidthPixel;

contentHeight = h - 2 * lineWidthPixel;

int radius = Math.min(w, h) / 2 - lineWidthPixel / 2;

if (radius < 0) return;

mTextPaint.setColor(Color.DKGRAY);

mTextPaint.setStyle(Paint.Style.STROKE);

RectF outlineRectF = new RectF(

lineWidthPixel / 2,

lineWidthPixel / 2,

lineWidthPixel + contentWidth + lineWidthPixel / 2,

lineWidthPixel + contentHeight + lineWidthPixel / 2

);

canvas.drawRoundRect(outlineRectF, radius, radius, mTextPaint);

RectF innerRectF = new RectF(

lineWidthPixel,

lineWidthPixel,

lineWidthPixel + contentWidth,

lineWidthPixel + contentHeight

);

mTextPaint.setColor(0xffffffff);

mTextPaint.setStyle(Paint.Style.FILL);

canvas.drawRoundRect(innerRectF, radius, radius, mTextPaint);

mTextPaint.setColor(Color.DKGRAY);

RectF middleRect = new RectF(

w / 2 - lineWidthPixel / 2,

lineWidthPixel * 3,

w / 2 + lineWidthPixel / 2,

h - lineWidthPixel * 3

);

mTextPaint.setStyle(Paint.Style.FILL);

canvas.drawRoundRect(middleRect, radius, radius, mTextPaint);

slideBarRadius = contentHeight / 2;

RectF circleRectF = new RectF(

lineWidthPixel + lineWidthPixel + offsetX,

0,

slideBarRadius * 2 + offsetX,

h

);

mTextPaint.setColor(Color.GRAY);

canvas.drawCircle(circleRectF.centerX(), circleRectF.centerY(), slideBarRadius, mTextPaint);

if(mState==STATUS_LEFT) {

mTextPaint.setColor(Color.CYAN);

}else{

mTextPaint.setColor(Color.RED);

}

canvas.drawCircle(circleRectF.centerX(), circleRectF.centerY(), slideBarRadius / 4, mTextPaint);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

int lineWidthPixies = (int) dpTopx(mLineWidth);

switch (action) {

case MotionEvent.ACTION_DOWN:

startX = event.getX();

startY = event.getY();

getParent().requestDisallowInterceptTouchEvent(true);

break;

case MotionEvent.ACTION_MOVE:

float currentX = event.getX();

float currentY = event.getY();

float dy = Math.abs(currentY - startY);

float dx = Math.abs(currentX - startX);

if (dy <= dx && dx >= mTouchSlop) {

isTouchMove = true;

}

if (isTouchMove) {

offsetX = (int) (currentX - slideBarRadius);

startX = currentX;

startY = currentY;

if (offsetX < (lineWidthPixies)) {

offsetX = 0; //最左边

} else if (offsetX > contentWidth - slideBarRadius * 2) { //最右边

offsetX = contentWidth - slideBarRadius * 2;

}

postInvalidateOnAnimation();

}

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_OUTSIDE:

getParent().requestDisallowInterceptTouchEvent(false);

startX = event.getX();

if (startX <= getWidth() / 2) {

if(isTouchMove){

offsetX = 0;

mState = STATUS_LEFT;

}else{

startSlideBarAnimation(offsetX,0,STATUS_LEFT);

}

} else {

if(isTouchMove){

mState = STATUS_RIGHT;

offsetX = contentWidth - 2 * slideBarRadius;

}else{

startSlideBarAnimation(offsetX,contentWidth - 2 * slideBarRadius,STATUS_RIGHT);

}

}

isTouchMove = false;

postInvalidateOnAnimation();

break;

}

return super.onTouchEvent(event);

}

public void postInvalidateOnAnimation() {

if (Build.VERSION.SDK_INT >= 16) {

super.postInvalidateOnAnimation();

} else {

postInvalidate();

}

}

public void setState(int state) {

this.mState = state;

if (state == STATUS_LEFT) {

offsetX = 0;

} else {

offsetX = contentWidth - 2 * slideBarRadius;

}

postInvalidate();

}

public void startSlideBarAnimation(int from, int to, final int state) {

if (mSlideAnimator != null) {

mSlideAnimator.cancel();

}

mSlideAnimator = ValueAnimator.ofInt(from, to).setDuration(300);

mSlideAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

mSlideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

offsetX = (int) animation.getAnimatedValue();

float fraction = animation.getAnimatedFraction();

if(fraction>=0.9){

mState = state;

}

postInvalidate();

}

});

mSlideAnimator.start();

}

}

文章来源: www.oschina.net,作者:IamOkay,版权归原作者所有,如需转载,请联系作者。

原文链接:https://my.oschina.net/ososchina/blog/4395977

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值