请选择 进入手机版 | 继续访问电脑版

热点推荐

    查看: 71|回复: 3

    自定义收起动画的Button

    [复制链接]
  • TA的每日心情
    开心
    昨天 00:08
  • 签到天数: 362 天

    [LV.8]以坛为家I

    5万

    主题

    5万

    帖子

    16万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    160408
    发表于 2021-1-14 15:21:25 | 显示全部楼层 |阅读模式
    一个自定义收起展开动画的Button% b7 X7 f  H/ s! L* e: D& }' ?

    3 t8 k) {. y$ X3 H' Y1 K* l
    下边那个绿色的是一个可拖拽的悬浮按钮:https://www.jianshu.com/p/286acc503268
    & [! v, G4 v* Y$ L  }( Z+ x* o: ^3 r6 s9 v  [0 I/ f
    CustomAnimatorButton.java
    / K) ?$ g1 c  hpackage com.xc.myexercise.widget;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.drawable.GradientDrawable;import android.text.TextUtils;import android.util.AttributeSet;import android.view.View;import android.view.animation.AnticipateInterpolator;import androidx.annotation.Nullable;import com.xc.myexercise.R;/** * author: roc * time: 1/13/21 12:30 PM * explain:带动画的按钮 */public class CustomAnimatorButton extends View {    private Context mContext;    //view的宽度    private int width;    //view的高度    private int height;    //圆角矩形Paint    private Paint rectPaint;    private GradientDrawable mDrawable;    //矩形背景颜色    private int rectBackColor;    //矩形的渐变颜色    private int backStartColor;    private int backEndColor;    //渐变颜色方向    private int colorDirection;    //默认圆角半径    private final int DEFAULTANGLE = 100;    //矩形圆角半径    private int circleAngle;    //文字Paint    private Paint textPaint;    private int textColor;    private int btnTextSize;    private String buttonText;    //图片资源    private int imageDrable;    //图片与文字的间距    private int imagePadding;    private Bitmap imgBitmap;    private RectF rectf = new RectF();    private Rect rect2 = new Rect();    private Rect rect3 = new Rect();    private Rect textRect = new Rect();    //底部标签绘制的drawable    private GradientDrawable tagDrawable;    //底部标签的文字Paint    private Paint tagTextPaint;    //底部标签的背景颜色    private int tagBackColor;    //底部标签的文字颜色    private int tagTextColor;    //底部标签的文字大小    private int tagTextSize;    //底部标签的背景弧度    private int tagBackAngle;    //底部标签的文字    private String tagtext;    //底部标签的宽度    private int tagBackWidth;    //底部标签的高度    private int tagBackHeight;    //进入动画    private AnimatorSet entryAnimatorSet = new AnimatorSet();    //矩形到圆形形过度的动画    private ValueAnimator animatorRectToCircle;    //view右移的动画    private ObjectAnimator animatorMoveToRight;    //退出动画    private AnimatorSet exitAnimatorSet = new AnimatorSet();    //圆形过度到矩形的动画    private ValueAnimator animatorCircleToRect;    //view左移的动画    private ObjectAnimator animatorMoveToLeft;    //动画执行时间    private int animatorDuration = 200;    //移动距离    private int moveDistance = 50;    //默认两圆圆心之间的距离=需要移动的距离    private int defaultTwoCircleDistance;    //两圆圆心之间的距离    private int twoCircleDistance;    //是否显示文字    private boolean isShowText = true;    private AnimatorButtonListener animatorButtonListener;    private AnimatorButtonClickListener animatorButtonClickListener;    //动画是否正在执行中    private boolean isAnimatorExecution = false;    //是否收起状态    private boolean isCloseState = false;    public CustomAnimatorButton(Context context) {        this(context, null);    }    public CustomAnimatorButton(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomAnimatorButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        initAttrs(attrs);        initPaint();        this.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (animatorButtonClickListener != null)                    animatorButtonClickListener.onClickBtn();            }        });        entryAnimatorSet.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                isAnimatorExecution = true;                if (animatorButtonListener != null)                    animatorButtonListener.entryStart();            }            @Override            public void onAnimationEnd(Animator animation) {                invalidate();                isCloseState = true;                isAnimatorExecution = false;                if (animatorButtonListener != null)                    animatorButtonListener.entryEnd();            }            @Override            public void onAnimationCancel(Animator animation) {                isAnimatorExecution = false;            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        exitAnimatorSet.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {                isAnimatorExecution = true;                if (animatorButtonListener != null)                    animatorButtonListener.exitStart();            }            @Override            public void onAnimationEnd(Animator animation) {                isAnimatorExecution = false;                isCloseState = false;                isShowText = true;                invalidate();                if (animatorButtonListener != null)                    animatorButtonListener.exitEnd();            }            @Override            public void onAnimationCancel(Animator animation) {                isAnimatorExecution = false;            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });    }    private void initAttrs(AttributeSet attrs) {        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CustomAnimatorButton);        if (typedArray == null) {            return;        }        try {            circleAngle = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_rect_angle, DEFAULTANGLE);            rectBackColor = typedArray.getColor(R.styleable.CustomAnimatorButton_rect_back_color, Color.parseColor("#DDDDDD"));            backStartColor = typedArray.getColor(R.styleable.CustomAnimatorButton_rect_back_start_color, -1);            backEndColor = typedArray.getColor(R.styleable.CustomAnimatorButton_rect_back_end_color, -1);            colorDirection = typedArray.getInteger(R.styleable.CustomAnimatorButton_color_direction, 1);            textColor = typedArray.getColor(R.styleable.CustomAnimatorButton_text_color, Color.parseColor("#000000"));            btnTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_btn_text_size, 20);            buttonText = typedArray.getString(R.styleable.CustomAnimatorButton_btn_text);            if (TextUtils.isEmpty(buttonText))                buttonText = "我要提问";            animatorDuration = typedArray.getInteger(R.styleable.CustomAnimatorButton_animator_duration, 200);            moveDistance = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_move_distance, 100);            imageDrable = typedArray.getResourceId(R.styleable.CustomAnimatorButton_image_drawable, R.mipmap.edit_pencil_icon);            imagePadding = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_image_padding, 10);            tagBackColor = typedArray.getColor(R.styleable.CustomAnimatorButton_tag_back_color, Color.parseColor("#FFDB9B"));            tagTextColor = typedArray.getColor(R.styleable.CustomAnimatorButton_tag_text_color, Color.parseColor("#C68A36"));            tagTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_tag_text_size, -1);            tagBackAngle = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_tag_angle, DEFAULTANGLE);            tagtext = typedArray.getString(R.styleable.CustomAnimatorButton_tag_text);            tagBackWidth = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_tag_back_width, -1);            tagBackHeight = typedArray.getDimensionPixelSize(R.styleable.CustomAnimatorButton_tag_back_height, -1);        } finally {            typedArray.recycle();        }    }    /**     * 初始化化Paint     */    private void initPaint() {        if (backEndColor == -1 || backStartColor == -1) {            rectPaint = new Paint();            rectPaint.setStrokeWidth(4);            rectPaint.setStyle(Paint.Style.FILL);            rectPaint.setAntiAlias(true);            rectPaint.setColor(rectBackColor);        } else {            //初始化柱状图drawable            mDrawable = new GradientDrawable();            if (colorDirection == 1) {//设置颜色渐变方向为纵向                mDrawable.setOrientation(GradientDrawable.Orientation.TOP_BOTTOM);//设置渐变方向(从上到下)            } else {                mDrawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);//设置渐变方向(从左到右)            }            mDrawable.setShape(GradientDrawable.RECTANGLE);//设置形状为矩形            mDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);            mDrawable.setCornerRadii(new float[]{circleAngle, circleAngle, circleAngle, circleAngle, circleAngle, circleAngle, circleAngle, circleAngle});//设置圆角            mDrawable.setColors(new int[]{backStartColor, backEndColor});//设置渐变颜色        }        //初始化文字pain        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        textPaint.setTextSize(btnTextSize);        textPaint.setColor(textColor);        textPaint.setTextAlign(Paint.Align.CENTER);        textPaint.setAntiAlias(true);        //初始化图片bitMap        imgBitmap = BitmapFactory.decodeResource(this.getResources(), imageDrable);        //初始化底部标签的pain        if (!TextUtils.isEmpty(tagtext)) {            //初始化底部文字的paint            tagTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);            if (tagTextSize == -1)                tagTextSize = btnTextSize / 2;            tagTextPaint.setTextSize(tagTextSize);            tagTextPaint.setColor(tagTextColor);            tagTextPaint.setTextAlign(Paint.Align.CENTER);            tagTextPaint.setAntiAlias(true);            //初始化柱状图drawable            tagDrawable = new GradientDrawable();            tagDrawable.setShape(GradientDrawable.RECTANGLE);//设置形状为矩形            tagDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);            tagDrawable.setCornerRadii(new float[]{tagBackAngle, tagBackAngle, tagBackAngle, tagBackAngle, 0, 0, 0, 0});//设置圆角            tagDrawable.setColors(new int[]{backStartColor, backEndColor});//            tagDrawable.setColor(tagBackColor);//设置底部标签的背景颜色        }    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        width = w;        height = h;        defaultTwoCircleDistance = (w - h) / 2;        initAnimation();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        drawOvalToCircle(canvas);        if (isShowText)            drawTextAndImg(canvas);        else            drawImg(canvas);    }    /**     * 绘制长方形变成圆形     *     * @param canvas 画布     */    private void drawOvalToCircle(Canvas canvas) {        if (backStartColor == -1 || backEndColor == -1) {//如果不用颜色渐变,就绘制纯色的圆角矩形            rectf.left = twoCircleDistance;            rectf.top = 0;            rectf.right = width - twoCircleDistance;            rectf.bottom = height;            //画圆角矩形            canvas.drawRoundRect(rectf, circleAngle, circleAngle, rectPaint);        } else {            //绘制渐变颜色的圆角矩形            rect2.left = twoCircleDistance;            rect2.top = 0;            rect2.right = width - twoCircleDistance;            rect2.bottom = height;            mDrawable.setBounds(rect2);//设置位置大小            mDrawable.draw(canvas);//绘制到canvas上        }    }    /**     * 绘制图片与文字     *     * @param canvas 画布     */    private void drawTextAndImg(Canvas canvas) {        textRect.left = 0;        textRect.top = 0;        textRect.right = width;        textRect.bottom = height;        int textWidth = (int) (textPaint.getTextSize() * buttonText.length());        int imgWidth = imgBitmap.getWidth();        int imgHeight = imgBitmap.getHeight();        int imgStartX = (width - textWidth - imgWidth - imagePadding) / 2;        int imgStartY = height / 2 - imgHeight / 2;        int textStartX = imgStartX + imgWidth + textWidth / 2 + imagePadding;        //绘制文字        Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;//        canvas.drawText(buttonText, textRect.centerX(), baseline, textPaint);        canvas.drawText(buttonText, textStartX, baseline, textPaint);        //绘制图片        canvas.drawBitmap(imgBitmap, imgStartX, imgStartY, null);        drawBottomTag(canvas);    }    /**     * 绘制底部标签     */    private void drawBottomTag(Canvas canvas) {        if (TextUtils.isEmpty(tagtext))            return;        if (tagBackWidth == -1)            tagBackWidth = defaultTwoCircleDistance * 2 + 30;        if (tagBackHeight == -1)            tagBackHeight = height / 4 - 5;        //绘制底部标签的背景        rect3.left = (width - tagBackWidth) / 2;        rect3.top = height - tagBackHeight - 2;        rect3.right = rect3.left + tagBackWidth;        rect3.bottom = height - 2;        tagDrawable.setBounds(rect3);//设置位置大小        tagDrawable.draw(canvas);//绘制到canvas上        //绘制文字        Paint.FontMetricsInt fontMetrics = tagTextPaint.getFontMetricsInt();        int baseline = (rect3.bottom + rect3.top - fontMetrics.bottom - fontMetrics.top) / 2;        canvas.drawText(tagtext, rect3.centerX(), baseline, tagTextPaint);    }    /**     * 绘制图片     *     * @param canvas     */    private void drawImg(Canvas canvas) {        int imgWidth = imgBitmap.getWidth();        int imgHeight = imgBitmap.getHeight();        int imgStartX = (width - imgWidth) / 2;        int imgStartY = height / 2 - imgHeight / 2;        //绘制图片        canvas.drawBitmap(imgBitmap, imgStartX, imgStartY, null);    }    /**     * 初始化所有动画     */    private void initAnimation() {        setRectToCircleAnimation();        setMoveToRightAnimation();        entryAnimatorSet                .play(animatorMoveToRight)                .after(animatorRectToCircle);        setCircleToRectAnimation();        setMoveToLeftAnimation();        exitAnimatorSet                .play(animatorCircleToRect)                .after(animatorMoveToLeft);    }    /**     * 设置圆角矩形过度到圆的动画     */    private void setRectToCircleAnimation() {        animatorRectToCircle = ValueAnimator.ofInt(0, defaultTwoCircleDistance);        animatorRectToCircle.setDuration(animatorDuration);        animatorRectToCircle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                twoCircleDistance = (int) animation.getAnimatedValue();                int alpha = 255 - (twoCircleDistance * 255) / defaultTwoCircleDistance;                textPaint.setAlpha(alpha);                isShowText = false;                invalidate();            }        });    }    /**     * 设置圆形过渡到圆角矩形的动画     */    private void setCircleToRectAnimation() {        animatorCircleToRect = ValueAnimator.ofInt(defaultTwoCircleDistance, 0);        animatorCircleToRect.setDuration(animatorDuration);        animatorCircleToRect.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                twoCircleDistance = (int) animation.getAnimatedValue();                int alpha = 255 - (twoCircleDistance * 255) / defaultTwoCircleDistance;                textPaint.setAlpha(alpha);                invalidate();            }        });    }    /**     * 设置view右移的动画     */    private void setMoveToRightAnimation() {        final float curTranslationX = this.getTranslationX();        animatorMoveToRight = ObjectAnimator.ofFloat(this, "translationX", curTranslationX, curTranslationX + moveDistance);        animatorMoveToRight.setDuration(animatorDuration);        animatorMoveToRight.setInterpolator(new AnticipateInterpolator());    }    /**     * 设置view左移的动画     */    private void setMoveToLeftAnimation() {        final float curTranslationX = this.getTranslationX();        animatorMoveToLeft = ObjectAnimator.ofFloat(this, "translationX", curTranslationX + moveDistance, curTranslationX);        animatorMoveToLeft.setDuration(animatorDuration);        animatorMoveToLeft.setInterpolator(new AnticipateInterpolator());    }    /**     * 启动动画     */    public void closeBtn() {        entryAnimatorSet.start();    }    /**     * 退出动画     */    public void unfoldBtn() {        exitAnimatorSet.start();    }    public void setAnimatorButtonListener(AnimatorButtonListener animatorButtonListener) {        this.animatorButtonListener = animatorButtonListener;    }    public void setAnimatorButtonClickListener(AnimatorButtonClickListener animatorButtonClickListener) {        this.animatorButtonClickListener = animatorButtonClickListener;    }    /**     * 动画是否正在执行中     *     * @return     */    public boolean isAnimatorExecution() {        return isAnimatorExecution;    }    /**     * 是否收起状态     *     * @return     */    public boolean isCloseState() {        return isCloseState;    }    public interface AnimatorButtonListener {        void entryStart();        void entryEnd();        void exitStart();        void exitEnd();    }    public interface AnimatorButtonClickListener {        void onClickBtn();    }    private void clearAnimator() {        if (entryAnimatorSet != null) {            entryAnimatorSet.cancel();            entryAnimatorSet = null;        }        if (exitAnimatorSet != null) {            exitAnimatorSet.cancel();            exitAnimatorSet = null;        }        if (animatorRectToCircle != null) {            animatorRectToCircle.cancel();            animatorRectToCircle = null;        }        if (animatorMoveToRight != null) {            animatorMoveToRight.cancel();            animatorMoveToRight = null;        }        if (animatorCircleToRect != null) {            animatorCircleToRect.cancel();            animatorCircleToRect = null;        }        if (animatorMoveToLeft != null) {            animatorMoveToLeft.cancel();            animatorMoveToLeft = null;        }    }}attrs.xml
    / _3 _6 W8 S4 e! [                                                                                                                                                                                                                                                                                                                                                                                 使用方式:直接在布局文件中使用
    # |$ {% w# x2 K在代码中调用closeBtn()和unfoldBtn()来收起和展开按钮状态
    6 t* K9 D6 F5 c# v3 Z
    4 _9 A5 V! x, q6 Z* l' Cprivate boolean isCloseState = false;@Overrideprotected void initView(@Nullable Bundle savedInstanceState) {        customBtn.setAnimatorButtonClickListener(new CustomAnimatorButton.AnimatorButtonClickListener() {            @Override            public void onClickBtn() {                if (isCloseState) {                    customBtn.unfoldBtn();                } else {                    customBtn.closeBtn();                }                isCloseState = !isCloseState;            }        });}5 L% r3 _4 e+ O' P7 u# H
    Java吧 收集整理 java论坛 www.java8.com
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    120

    帖子

    240

    积分

    中级会员

    Rank: 3Rank: 3

    积分
    240
    发表于 2021-1-20 03:54:06 | 显示全部楼层
    楼主呀,,,您太有才了。。。
    回复

    使用道具 举报

    该用户从未签到

    3

    主题

    112

    帖子

    227

    积分

    中级会员

    Rank: 3Rank: 3

    积分
    227
    发表于 2021-2-20 07:23:55 | 显示全部楼层
    占坑编辑ing
    回复

    使用道具 举报

    该用户从未签到

    7

    主题

    124

    帖子

    255

    积分

    中级会员

    Rank: 3Rank: 3

    积分
    255
    发表于 2021-2-21 06:44:41 | 显示全部楼层
    不错 支持下
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表