效果图:
simpleButton类代码:
- package com.oneway.demo.navcontroller.view;
-
- import android.animation.ObjectAnimator;
- import android.animation.ValueAnimator;
- import android.annotation.SuppressLint;
- 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.Matrix;
- import android.graphics.Paint;
- import android.graphics.RectF;
- import android.util.AttributeSet;
- import android.util.TypedValue;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.animation.LinearInterpolator;
-
- import com.oneway.demo.navcontroller.R;
-
-
- public class SimpleLoadingButton extends View {
-
- private int textColor;
- private int backgroundNormal;
- private float textSize;
- private String content;
- private Bitmap bitmap;
- private int default_padding;
- private int paddingBottom;
- private int paddingLeft;
- private int paddingTop;
- private int paddingRight;
- private Paint paintRect;
- private Paint paintTxt;
- private RectF rect;
- private float txtHeight;
- private Matrix matrix;
- private ObjectAnimator animator;
- private int mViewWidth;
- private int mViewHeight;
- private int STATE_NORMAL = 0;
- private int STATE_LOADING = 1;
- private int STATE_COMPLETED = 2;
- private int state = STATE_NORMAL;
- private String loadingTxt;
- private String contentNormal;
- private float corners;
- private int backgroundPressed;
-
- public SimpleLoadingButton(Context context) {
- this(context, null, 0);
- }
-
- public SimpleLoadingButton(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SimpleLoadingButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initAttrs(context, attrs);
- initData(context);
- }
-
- /**
- * 方法描述:初始化属性值
- *
- * @param context 上下文
- * @param attrs 属性集合
- */
- private void initAttrs(Context context, AttributeSet attrs) {
- TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleLoadingButton);
- backgroundNormal = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_normal,
- Color.parseColor("#3A96FF"));
- backgroundPressed = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_pressed,
- Color.parseColor("#1E90FF"));
- // Log.e("Custom", "background===" + background);
- // if (background >= TypedValue.TYPE_FIRST_COLOR_INT &&
- // background <= TypedValue.TYPE_LAST_COLOR_INT){
-
-
- textColor = typeArray.getColor(R.styleable.SimpleLoadingButton_button_text_color, Color.WHITE);
- textSize = typeArray.getDimension(R.styleable.SimpleLoadingButton_button_text_size, (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
- contentNormal = typeArray.getString(R.styleable.SimpleLoadingButton_button_text);
- loadingTxt = typeArray.getString(R.styleable.SimpleLoadingButton_button_loading_text);
- corners = typeArray.getDimension(R.styleable.SimpleLoadingButton_corners, (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics()));
- typeArray.recycle();
- }
-
- private void initData(Context context) {
- if (contentNormal != null) {
- content = contentNormal;
- } else {
- content = "";
- }
-
- bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.loading);
-
- default_padding = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 22, getResources().getDisplayMetrics());
-
- paddingBottom = getPaddingBottom();
- paddingLeft = getPaddingLeft();
- paddingTop = getPaddingTop();
- paddingRight = getPaddingRight();
-
- //矩形画笔
- paintRect = new Paint();
- paintRect.setColor(backgroundNormal);
- paintRect.setAntiAlias(true);
- paintRect.setStyle(Paint.Style.FILL);
-
- //矩形对象
- rect = new RectF();
-
- //文字画笔
- paintTxt = new Paint();
- paintTxt.setColor(textColor);
- paintRect.setAntiAlias(true);
- paintTxt.setTextAlign(Paint.Align.CENTER);
- paintTxt.setTextSize(textSize);
- txtHeight = (float) getTxtHeight(paintTxt);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mViewWidth = w;
- mViewHeight = h;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int measureWidth = measureWidth(widthMeasureSpec);
- int measureHeight = measureHeight(heightMeasureSpec);
- initRect(measureWidth, measureHeight);
- setMeasuredDimension(measureWidth, measureHeight);
- }
-
- /**
- * 方法描述:矩形对象初始化
- */
- private void initRect(int measureWidth, int measureHeight) {
- rect.left = 0;
- rect.top = 0;
- rect.right = measureWidth;
- rect.bottom = measureHeight;
- }
-
- private int measureWidth(int measureSpec) {
- int width;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- if (specMode == MeasureSpec.EXACTLY) {
- width = specSize;
- } else {
- width = (int) paintTxt.measureText(content) + paddingLeft + paddingRight;
- if (specMode == MeasureSpec.AT_MOST) {
- width = Math.min(width, specSize);
- }
- }
- return width;
- }
-
- private int measureHeight(int measureSpec) {
- int height = 0;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
-
- if (specMode == MeasureSpec.EXACTLY) {
- height = specSize;
- } else if (specMode == MeasureSpec.AT_MOST) {
- height = (int) txtHeight + paddingTop + paddingBottom + default_padding;
- }
- return height;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawRoundRect(rect, corners, corners, paintRect);
- if (state == STATE_NORMAL) {
- canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
- rect.height() / 2 + txtHeight / 3, paintTxt);
- }
- if (state == STATE_LOADING) {
- canvas.translate(mViewWidth / 2, mViewHeight / 2);// 旋转的位置
- matrix.preTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2);//旋转中心点
- canvas.drawBitmap(bitmap, matrix, null);
- }
- if (state == STATE_COMPLETED) {
- canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
- rect.height() / 2 + txtHeight / 3, paintTxt);
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (listener == null) {
- return true;
- }
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (loadingTxt == null) {
- content = "";
- } else {
- content = loadingTxt;
- }
- paintRect.setColor(backgroundPressed);
- state = STATE_NORMAL;
- postInvalidate();
- break;
- case MotionEvent.ACTION_UP:
- paintRect.setColor(backgroundNormal);
- startAnim();
- state = STATE_LOADING;
- postInvalidate();
- listener.onLoadingClick(this);
- break;
- }
- return true;
- }
-
- /**
- * 方法描述:加载完成以后让SimpleLoadingButton复位
- */
- public void setCompleted() {
- content = contentNormal;
- state = STATE_COMPLETED;
- cancelAnim();
- postInvalidate();
- }
-
-
- /**
- * 方法描述:获取文本字符的高度
- *
- * @param mPaint 画文本字符的画笔
- * @return 文本字符的高度
- */
- public double getTxtHeight(Paint mPaint) {
- Paint.FontMetrics fm = mPaint.getFontMetrics();
- return Math.ceil(fm.descent - fm.ascent);
- }
-
- /**
- * 方法描述:开启动画
- */
- private void startAnim() {
- if (animator == null) {
- initAnimator();
- animator.start();
- return;
- }
- if (!animator.isRunning()) {
- animator.start();
- }
- }
-
- /**
- * 方法描述:取消动画
- */
- private void cancelAnim() {
- if (animator != null && animator.isRunning()) {
- animator.cancel();
- }
- }
-
- @SuppressLint("ObjectAnimatorBinding")
- private void initAnimator() {
- matrix = new Matrix();
- animator = ObjectAnimator.ofFloat(matrix, "rotation", 0, 360);
- animator.setDuration(1000);
- animator.setInterpolator(new LinearInterpolator());
- animator.setRepeatCount(ValueAnimator.INFINITE);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- matrix.setRotate((float) animation.getAnimatedValue());
- invalidate();
- }
- });
- }
-
- private LoadingListener listener;
-
- public void setLoadingListener(LoadingListener loginClickListener) {
- this.listener = loginClickListener;
- }
-
- public interface LoadingListener {
- void onLoadingClick(SimpleLoadingButton view);
- }
- }
value文件夹里面的attrs.xml代码为:
- "1.0" encoding="utf-8"?>
-
"SimpleLoadingButton"> -
"button_background_color_normal" format="color" /> -
"button_background_color_pressed" format="color" /> -
"button_text" format="string" /> -
"button_text_color" format="color" /> -
"button_text_size" format="dimension" /> -
"button_loading_text" format="string" /> -
"corners" format="dimension" /> -
loading.png图标为:
在activity的xml里面添加代码:
- android:id="@+id/simple_loading_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- app:button_background_color_normal="#3A96FF"
- app:button_background_color_pressed="#1E90FF"
- app:button_loading_text="登录中..."
- app:button_text="登录"
- app:button_text_color="#ffffff"
- app:button_text_size="18sp"
- app:corners="8dp"
- tools:ignore="MissingConstraints" />
最后,开始调用findviewbyid拿到SimpleLoadingButton控件,调用setLoadingListener方法
加载结束调用setCompleted方法复位
方式二
点击前效果:
点击后效果:
LoadingButton代码:
- import android.animation.Animator;
- import android.animation.AnimatorListenerAdapter;
- import android.animation.ValueAnimator;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.Gravity;
- import android.view.animation.Animation;
- import android.view.animation.Interpolator;
- import android.view.animation.LinearInterpolator;
- import android.view.animation.RotateAnimation;
-
- /**
- *
- */
- public class LoadingButton extends androidx.appcompat.widget.AppCompatButton {
- private Context context;
-
- // 开始Loading时的回调
- private OnStartListener startListener;
-
- // 结束Loading时的回调
- private OnFinishListener finishListener;
-
- // 开始和结束Loading时的回调
- private OnLoadingListener listener;
-
- // Loading动画旋转周期
- private int rotateDuration = 1000;
-
- // 按钮缩成Loading动画的时间
- private int reduceDuration = 350;
-
- // Loading旋转动画控制器
- private Interpolator rotateInterpolator;
-
- // 按钮缩成Loading动画的控制器
- private Interpolator reduceInterpolator;
-
- private int width;
- private int height;
-
- private String text;
-
- // 是否在Loading中
- private boolean isLoading = false;
-
- public LoadingButton(Context context) {
- this(context, null);
- }
-
- public LoadingButton(Context context, AttributeSet attrs) {
- this(context, attrs, -1);
- }
-
- public LoadingButton(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context);
- }
-
- private void init(Context context) {
- this.context = context;
-
- setGravity(Gravity.CENTER);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (width == 0) width = getMeasuredWidth();
- if (height == 0) height = getMeasuredHeight();
- }
-
- /**
- * 播放按钮缩成Loading的动画
- */
- private void showStartLoadAnimation() {
- ValueAnimator animator = new ValueAnimator().ofInt(width, height);
- animator.setDuration(reduceDuration);
- if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- getLayoutParams().width = (int) animation.getAnimatedValue();
- requestLayout();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
- setEnabled(false);
- text = getText().toString();
- setText("");
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- showLoadingAnimation();
- }
- });
- animator.start();
- }
-
- /**
- * 播放Loading动画
- */
- private void showLoadingAnimation() {
- RotateAnimation animation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
- animation.setDuration(rotateDuration);
- animation.setInterpolator(rotateInterpolator != null ? rotateInterpolator : new LinearInterpolator());
- animation.setRepeatCount(-1);
- setBackgroundDrawable(context.getResources().getDrawable(R.drawable.circle_loading));
- if (startListener != null) {
- startListener.onStart();
- } else if (listener != null) {
- listener.onStart();
- }
- startAnimation(animation);
- isLoading = true;
- }
-
- /**
- * 播放Loading拉伸成按钮的动画
- */
- private void showFinishLoadAnimation() {
- ValueAnimator animator = new ValueAnimator().ofInt(height, width);
- animator.setDuration(reduceDuration);
- if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- getLayoutParams().width = (int) animation.getAnimatedValue();
- requestLayout();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
- setEnabled(false);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- setText(text);
- setEnabled(true);
- if (finishListener != null) {
- finishListener.onFinish();
- } else if (listener != null) {
- listener.onFinish();
- }
- }
- });
- animator.start();
- isLoading = false;
- }
-
- /**
- * 开始Loading
- */
- public void startLoading() {
- if (!isLoading) {
- clearAnimation();
- showStartLoadAnimation();
- }
- }
-
- /**
- * 开始Loading
- *
- * @param listener Loading开始时的回调
- */
- public void startLoading(OnStartListener listener) {
- if (!isLoading) {
- this.startListener = listener;
- clearAnimation();
- showStartLoadAnimation();
- }
- }
-
- /**
- * 结束Loading
- */
- public void finishLoading() {
- if (isLoading) {
- clearAnimation();
- showFinishLoadAnimation();
- }
- }
-
- /**
- * 结束Loading
- *
- * @param listener Loading结束时的回调
- */
- public void finishLoading(OnFinishListener listener) {
- if (isLoading) {
- this.finishListener = listener;
- clearAnimation();
- showFinishLoadAnimation();
- }
- }
-
- /**
- * 设置Loading开始和结束时的回调接口
- *
- * @param listener
- */
- public void setOnLoadingListener(OnLoadingListener listener) {
- this.listener = listener;
- }
-
- /**
- * 设置按钮缩成Loading动画的时间
- *
- * @param reduceDuration 时间,单位毫秒
- */
- public void setReduceDuration(int reduceDuration) {
- this.reduceDuration = reduceDuration;
- }
-
- /**
- * 设置Loading动画旋转周期
- *
- * @param rotateDuration 旋转周期,单位毫秒
- */
- public void setRotateDuration(int rotateDuration) {
- this.rotateDuration = rotateDuration;
- }
-
- /**
- * 获取是否正在Loading
- *
- * @return
- */
- public boolean isLoading() {
- return isLoading;
- }
-
- /**
- * 设置Loading旋转动画控制器
- *
- * @param rotateInterpolator
- */
- public void setRotateInterpolator(Interpolator rotateInterpolator) {
- this.rotateInterpolator = rotateInterpolator;
- }
-
- /**
- * 按钮缩成Loading动画的控制器
- *
- * @param reduceInterpolator
- */
- public void setReduceInterpolator(Interpolator reduceInterpolator) {
- this.reduceInterpolator = reduceInterpolator;
- }
-
- /**
- * Loading开始时的回调接口
- */
- public interface OnStartListener {
- void onStart();
- }
-
- /**
- * Loading结束时的回调接口
- */
- public interface OnFinishListener {
- void onFinish();
- }
-
- /**
- * Loading开始和结束时的回调接口
- */
- public interface OnLoadingListener {
- void onStart();
-
- void onFinish();
- }
- }
button_main_color_up.xml:
- "1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"> -
-
"20dp" /> -
-
"#45a8ca" /> -
-
- android:endColor="#45a8ca"
- android:startColor="#6fd1e7" />
-
button_main_color_down.xml:
- "1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"> -
-
"20dp" /> -
-
"#45a8aa" /> -
-
- android:endColor="#45a8aa"
- android:startColor="#6fd1c7" />
-
button_main_color_selector.xml:
- "1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"> -
-
- "@drawable/button_main_color_up" android:state_pressed="false">
-
- "@drawable/button_main_color_down" android:state_pressed="true">
-
circle_loading.xml代码
- "1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android" - android:innerRadius="18dp"
- android:shape="ring"
- android:thickness="2dp"
- android:useLevel="false">
-
-
"#45a8ca" /> -
-
- android:endColor="#45a8ca"
- android:startColor="#0000"
- android:type="sweep" />
-
在activity.xml里面的代码为:
- android:id="@+id/load_btn"
- android:layout_width="match_parent"
- android:layout_height="40dp"
- android:layout_margin="10dp"
- android:background="@drawable/button_main_color_selector"
- android:text="CLICK"
- android:textColor="#ffffff"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
在activity里的代码为(开始加载):
- findViewById
(R.id.load_btn).setOnClickListener { - (it as LoadingButton).startLoading()
- }
结束加载:finishLoading
方式三
LoadingButton的代码
- package com.oneway.demo.loadingbutton_master
-
- import android.content.Context
- import android.util.AttributeSet
- import android.util.Log
- import android.view.LayoutInflater
- import android.view.View
- import android.widget.ProgressBar
- import androidx.constraintlayout.widget.ConstraintLayout
-
- /**
- * 封装的LoadingButton按钮
- *
- * @author WY+ 22/9/19.
- */
- class LoadingButton(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
- // 是否在Loading中
- private var isLoading = false
- private var view: View? = null
- private var progressBar: ProgressBar? = null
-
- init {
- // 自定义TitleLayout的相关属性
- view = LayoutInflater.from(context).inflate(R.layout.layout_loading_button, this, true)
- progressBar = view?.findViewById
(R.id.pb_loading) - }
-
- /**
- * 重写点击事件
- */
- override fun setOnClickListener(l: OnClickListener?) {
- super.setOnClickListener {
- // Log.e("wang", "点击事件==点击的时候会进入这里")
- progressBar?.visibility = View.VISIBLE // 显示loading
- l?.onClick(view) // 回调给调用方
- }
- }
-
- fun complete() {
- progressBar?.visibility = View.GONE
- }
-
-
- }
layout_loading_button.xml代码
- "1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/cl_loading"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="8dp">
-
-
- android:id="@+id/pb_loading"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginRight="8dp"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/tv_loading"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
-
-
- android:id="@+id/tv_loading"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="login"
- android:textColor="@color/white"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/pb_loading"
- app:layout_constraintTop_toTopOf="parent" />
-
-
使用:第一步在xml里面添加(跟普通的控件使用方式一样)
- android:id="@+id/lb_login"
- android:layout_width="90dp"
- android:layout_height="wrap_content"
- android:background="@color/purple_200"
- android:text="Hello World!"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
activity里面调用点击事件:
- val mLoadingButton = findViewById
(R.id.lb_login) - mLoadingButton.setOnClickListener {
- Log.e("wang", "点击==开始异步网络请求")
- Handler(Looper.myLooper()!!).postDelayed({
- Log.e("wang", "拿到请求结果")
- mLoadingButton.complete()
- }, 3000)
- }
-
相关阅读:
【VMware ESXi】HP Z4G4 Workstation安装ESXi停留在Shutting down firmware services...的解决办法。
gs_moment
React和vue等前端html页面引入自定义字体文件,更改页面字体样式
贪心法求解问题
FFmpeg 基础模块:容器相关的 API 操作
TypeScript 最细项目实践:四步走高效改造现有的 JavaScript 项目
GEO的表达矩阵的探针ID转换成基因名称教程
【C#】【SAP2000】读取SAP2000中所有Frame对象的应力比到Grasshopper中
linux交叉编译
关于[git reset]
-
原文地址:https://blog.csdn.net/wy313622821/article/details/128002463