• android——自定义加载按钮LoadingButton


    方式一

    效果图:

    simpleButton类代码:

    1. package com.oneway.demo.navcontroller.view;
    2. import android.animation.ObjectAnimator;
    3. import android.animation.ValueAnimator;
    4. import android.annotation.SuppressLint;
    5. import android.content.Context;
    6. import android.content.res.TypedArray;
    7. import android.graphics.Bitmap;
    8. import android.graphics.BitmapFactory;
    9. import android.graphics.Canvas;
    10. import android.graphics.Color;
    11. import android.graphics.Matrix;
    12. import android.graphics.Paint;
    13. import android.graphics.RectF;
    14. import android.util.AttributeSet;
    15. import android.util.TypedValue;
    16. import android.view.MotionEvent;
    17. import android.view.View;
    18. import android.view.animation.LinearInterpolator;
    19. import com.oneway.demo.navcontroller.R;
    20. public class SimpleLoadingButton extends View {
    21. private int textColor;
    22. private int backgroundNormal;
    23. private float textSize;
    24. private String content;
    25. private Bitmap bitmap;
    26. private int default_padding;
    27. private int paddingBottom;
    28. private int paddingLeft;
    29. private int paddingTop;
    30. private int paddingRight;
    31. private Paint paintRect;
    32. private Paint paintTxt;
    33. private RectF rect;
    34. private float txtHeight;
    35. private Matrix matrix;
    36. private ObjectAnimator animator;
    37. private int mViewWidth;
    38. private int mViewHeight;
    39. private int STATE_NORMAL = 0;
    40. private int STATE_LOADING = 1;
    41. private int STATE_COMPLETED = 2;
    42. private int state = STATE_NORMAL;
    43. private String loadingTxt;
    44. private String contentNormal;
    45. private float corners;
    46. private int backgroundPressed;
    47. public SimpleLoadingButton(Context context) {
    48. this(context, null, 0);
    49. }
    50. public SimpleLoadingButton(Context context, AttributeSet attrs) {
    51. this(context, attrs, 0);
    52. }
    53. public SimpleLoadingButton(Context context, AttributeSet attrs, int defStyleAttr) {
    54. super(context, attrs, defStyleAttr);
    55. initAttrs(context, attrs);
    56. initData(context);
    57. }
    58. /**
    59. * 方法描述:初始化属性值
    60. *
    61. * @param context 上下文
    62. * @param attrs 属性集合
    63. */
    64. private void initAttrs(Context context, AttributeSet attrs) {
    65. TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleLoadingButton);
    66. backgroundNormal = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_normal,
    67. Color.parseColor("#3A96FF"));
    68. backgroundPressed = typeArray.getColor(R.styleable.SimpleLoadingButton_button_background_color_pressed,
    69. Color.parseColor("#1E90FF"));
    70. // Log.e("Custom", "background===" + background);
    71. // if (background >= TypedValue.TYPE_FIRST_COLOR_INT &&
    72. // background <= TypedValue.TYPE_LAST_COLOR_INT){
    73. textColor = typeArray.getColor(R.styleable.SimpleLoadingButton_button_text_color, Color.WHITE);
    74. textSize = typeArray.getDimension(R.styleable.SimpleLoadingButton_button_text_size, (int) TypedValue.applyDimension(
    75. TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
    76. contentNormal = typeArray.getString(R.styleable.SimpleLoadingButton_button_text);
    77. loadingTxt = typeArray.getString(R.styleable.SimpleLoadingButton_button_loading_text);
    78. corners = typeArray.getDimension(R.styleable.SimpleLoadingButton_corners, (int) TypedValue.applyDimension(
    79. TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics()));
    80. typeArray.recycle();
    81. }
    82. private void initData(Context context) {
    83. if (contentNormal != null) {
    84. content = contentNormal;
    85. } else {
    86. content = "";
    87. }
    88. bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.loading);
    89. default_padding = (int) TypedValue.applyDimension(
    90. TypedValue.COMPLEX_UNIT_DIP, 22, getResources().getDisplayMetrics());
    91. paddingBottom = getPaddingBottom();
    92. paddingLeft = getPaddingLeft();
    93. paddingTop = getPaddingTop();
    94. paddingRight = getPaddingRight();
    95. //矩形画笔
    96. paintRect = new Paint();
    97. paintRect.setColor(backgroundNormal);
    98. paintRect.setAntiAlias(true);
    99. paintRect.setStyle(Paint.Style.FILL);
    100. //矩形对象
    101. rect = new RectF();
    102. //文字画笔
    103. paintTxt = new Paint();
    104. paintTxt.setColor(textColor);
    105. paintRect.setAntiAlias(true);
    106. paintTxt.setTextAlign(Paint.Align.CENTER);
    107. paintTxt.setTextSize(textSize);
    108. txtHeight = (float) getTxtHeight(paintTxt);
    109. }
    110. @Override
    111. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    112. super.onSizeChanged(w, h, oldw, oldh);
    113. mViewWidth = w;
    114. mViewHeight = h;
    115. }
    116. @Override
    117. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    118. int measureWidth = measureWidth(widthMeasureSpec);
    119. int measureHeight = measureHeight(heightMeasureSpec);
    120. initRect(measureWidth, measureHeight);
    121. setMeasuredDimension(measureWidth, measureHeight);
    122. }
    123. /**
    124. * 方法描述:矩形对象初始化
    125. */
    126. private void initRect(int measureWidth, int measureHeight) {
    127. rect.left = 0;
    128. rect.top = 0;
    129. rect.right = measureWidth;
    130. rect.bottom = measureHeight;
    131. }
    132. private int measureWidth(int measureSpec) {
    133. int width;
    134. int specMode = MeasureSpec.getMode(measureSpec);
    135. int specSize = MeasureSpec.getSize(measureSpec);
    136. if (specMode == MeasureSpec.EXACTLY) {
    137. width = specSize;
    138. } else {
    139. width = (int) paintTxt.measureText(content) + paddingLeft + paddingRight;
    140. if (specMode == MeasureSpec.AT_MOST) {
    141. width = Math.min(width, specSize);
    142. }
    143. }
    144. return width;
    145. }
    146. private int measureHeight(int measureSpec) {
    147. int height = 0;
    148. int specMode = MeasureSpec.getMode(measureSpec);
    149. int specSize = MeasureSpec.getSize(measureSpec);
    150. if (specMode == MeasureSpec.EXACTLY) {
    151. height = specSize;
    152. } else if (specMode == MeasureSpec.AT_MOST) {
    153. height = (int) txtHeight + paddingTop + paddingBottom + default_padding;
    154. }
    155. return height;
    156. }
    157. @Override
    158. protected void onDraw(Canvas canvas) {
    159. super.onDraw(canvas);
    160. canvas.drawRoundRect(rect, corners, corners, paintRect);
    161. if (state == STATE_NORMAL) {
    162. canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
    163. rect.height() / 2 + txtHeight / 3, paintTxt);
    164. }
    165. if (state == STATE_LOADING) {
    166. canvas.translate(mViewWidth / 2, mViewHeight / 2);// 旋转的位置
    167. matrix.preTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2);//旋转中心点
    168. canvas.drawBitmap(bitmap, matrix, null);
    169. }
    170. if (state == STATE_COMPLETED) {
    171. canvas.drawText(content, paddingLeft + rect.width() / 2 - paddingRight,
    172. rect.height() / 2 + txtHeight / 3, paintTxt);
    173. }
    174. }
    175. @Override
    176. public boolean onTouchEvent(MotionEvent event) {
    177. if (listener == null) {
    178. return true;
    179. }
    180. switch (event.getAction()) {
    181. case MotionEvent.ACTION_DOWN:
    182. if (loadingTxt == null) {
    183. content = "";
    184. } else {
    185. content = loadingTxt;
    186. }
    187. paintRect.setColor(backgroundPressed);
    188. state = STATE_NORMAL;
    189. postInvalidate();
    190. break;
    191. case MotionEvent.ACTION_UP:
    192. paintRect.setColor(backgroundNormal);
    193. startAnim();
    194. state = STATE_LOADING;
    195. postInvalidate();
    196. listener.onLoadingClick(this);
    197. break;
    198. }
    199. return true;
    200. }
    201. /**
    202. * 方法描述:加载完成以后让SimpleLoadingButton复位
    203. */
    204. public void setCompleted() {
    205. content = contentNormal;
    206. state = STATE_COMPLETED;
    207. cancelAnim();
    208. postInvalidate();
    209. }
    210. /**
    211. * 方法描述:获取文本字符的高度
    212. *
    213. * @param mPaint 画文本字符的画笔
    214. * @return 文本字符的高度
    215. */
    216. public double getTxtHeight(Paint mPaint) {
    217. Paint.FontMetrics fm = mPaint.getFontMetrics();
    218. return Math.ceil(fm.descent - fm.ascent);
    219. }
    220. /**
    221. * 方法描述:开启动画
    222. */
    223. private void startAnim() {
    224. if (animator == null) {
    225. initAnimator();
    226. animator.start();
    227. return;
    228. }
    229. if (!animator.isRunning()) {
    230. animator.start();
    231. }
    232. }
    233. /**
    234. * 方法描述:取消动画
    235. */
    236. private void cancelAnim() {
    237. if (animator != null && animator.isRunning()) {
    238. animator.cancel();
    239. }
    240. }
    241. @SuppressLint("ObjectAnimatorBinding")
    242. private void initAnimator() {
    243. matrix = new Matrix();
    244. animator = ObjectAnimator.ofFloat(matrix, "rotation", 0, 360);
    245. animator.setDuration(1000);
    246. animator.setInterpolator(new LinearInterpolator());
    247. animator.setRepeatCount(ValueAnimator.INFINITE);
    248. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    249. @Override
    250. public void onAnimationUpdate(ValueAnimator animation) {
    251. matrix.setRotate((float) animation.getAnimatedValue());
    252. invalidate();
    253. }
    254. });
    255. }
    256. private LoadingListener listener;
    257. public void setLoadingListener(LoadingListener loginClickListener) {
    258. this.listener = loginClickListener;
    259. }
    260. public interface LoadingListener {
    261. void onLoadingClick(SimpleLoadingButton view);
    262. }
    263. }

    value文件夹里面的attrs.xml代码为:

    1. "1.0" encoding="utf-8"?>
    2. "SimpleLoadingButton">
    3. "button_background_color_normal" format="color" />
    4. "button_background_color_pressed" format="color" />
    5. "button_text" format="string" />
    6. "button_text_color" format="color" />
    7. "button_text_size" format="dimension" />
    8. "button_loading_text" format="string" />
    9. "corners" format="dimension" />

    loading.png图标为:

    在activity的xml里面添加代码:

    1. android:id="@+id/simple_loading_button"
    2. android:layout_width="match_parent"
    3. android:layout_height="wrap_content"
    4. android:layout_marginLeft="16dp"
    5. android:layout_marginRight="16dp"
    6. app:button_background_color_normal="#3A96FF"
    7. app:button_background_color_pressed="#1E90FF"
    8. app:button_loading_text="登录中..."
    9. app:button_text="登录"
    10. app:button_text_color="#ffffff"
    11. app:button_text_size="18sp"
    12. app:corners="8dp"
    13. tools:ignore="MissingConstraints" />

     最后,开始调用findviewbyid拿到SimpleLoadingButton控件,调用setLoadingListener方法

     加载结束调用setCompleted方法复位

    方式二

    点击前效果:

     点击后效果:

    LoadingButton代码:

    1. import android.animation.Animator;
    2. import android.animation.AnimatorListenerAdapter;
    3. import android.animation.ValueAnimator;
    4. import android.content.Context;
    5. import android.util.AttributeSet;
    6. import android.view.Gravity;
    7. import android.view.animation.Animation;
    8. import android.view.animation.Interpolator;
    9. import android.view.animation.LinearInterpolator;
    10. import android.view.animation.RotateAnimation;
    11. /**
    12. *
    13. */
    14. public class LoadingButton extends androidx.appcompat.widget.AppCompatButton {
    15. private Context context;
    16. // 开始Loading时的回调
    17. private OnStartListener startListener;
    18. // 结束Loading时的回调
    19. private OnFinishListener finishListener;
    20. // 开始和结束Loading时的回调
    21. private OnLoadingListener listener;
    22. // Loading动画旋转周期
    23. private int rotateDuration = 1000;
    24. // 按钮缩成Loading动画的时间
    25. private int reduceDuration = 350;
    26. // Loading旋转动画控制器
    27. private Interpolator rotateInterpolator;
    28. // 按钮缩成Loading动画的控制器
    29. private Interpolator reduceInterpolator;
    30. private int width;
    31. private int height;
    32. private String text;
    33. // 是否在Loading中
    34. private boolean isLoading = false;
    35. public LoadingButton(Context context) {
    36. this(context, null);
    37. }
    38. public LoadingButton(Context context, AttributeSet attrs) {
    39. this(context, attrs, -1);
    40. }
    41. public LoadingButton(Context context, AttributeSet attrs, int defStyle) {
    42. super(context, attrs, defStyle);
    43. init(context);
    44. }
    45. private void init(Context context) {
    46. this.context = context;
    47. setGravity(Gravity.CENTER);
    48. }
    49. @Override
    50. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    51. super.onLayout(changed, left, top, right, bottom);
    52. if (width == 0) width = getMeasuredWidth();
    53. if (height == 0) height = getMeasuredHeight();
    54. }
    55. /**
    56. * 播放按钮缩成Loading的动画
    57. */
    58. private void showStartLoadAnimation() {
    59. ValueAnimator animator = new ValueAnimator().ofInt(width, height);
    60. animator.setDuration(reduceDuration);
    61. if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
    62. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    63. @Override
    64. public void onAnimationUpdate(ValueAnimator animation) {
    65. getLayoutParams().width = (int) animation.getAnimatedValue();
    66. requestLayout();
    67. }
    68. });
    69. animator.addListener(new AnimatorListenerAdapter() {
    70. @Override
    71. public void onAnimationStart(Animator animation) {
    72. setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
    73. setEnabled(false);
    74. text = getText().toString();
    75. setText("");
    76. }
    77. @Override
    78. public void onAnimationEnd(Animator animation) {
    79. showLoadingAnimation();
    80. }
    81. });
    82. animator.start();
    83. }
    84. /**
    85. * 播放Loading动画
    86. */
    87. private void showLoadingAnimation() {
    88. RotateAnimation animation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    89. animation.setDuration(rotateDuration);
    90. animation.setInterpolator(rotateInterpolator != null ? rotateInterpolator : new LinearInterpolator());
    91. animation.setRepeatCount(-1);
    92. setBackgroundDrawable(context.getResources().getDrawable(R.drawable.circle_loading));
    93. if (startListener != null) {
    94. startListener.onStart();
    95. } else if (listener != null) {
    96. listener.onStart();
    97. }
    98. startAnimation(animation);
    99. isLoading = true;
    100. }
    101. /**
    102. * 播放Loading拉伸成按钮的动画
    103. */
    104. private void showFinishLoadAnimation() {
    105. ValueAnimator animator = new ValueAnimator().ofInt(height, width);
    106. animator.setDuration(reduceDuration);
    107. if (reduceInterpolator != null) animator.setInterpolator(reduceInterpolator);
    108. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    109. @Override
    110. public void onAnimationUpdate(ValueAnimator animation) {
    111. getLayoutParams().width = (int) animation.getAnimatedValue();
    112. requestLayout();
    113. }
    114. });
    115. animator.addListener(new AnimatorListenerAdapter() {
    116. @Override
    117. public void onAnimationStart(Animator animation) {
    118. setBackgroundDrawable(context.getResources().getDrawable(R.drawable.button_main_color_selector));
    119. setEnabled(false);
    120. }
    121. @Override
    122. public void onAnimationEnd(Animator animation) {
    123. setText(text);
    124. setEnabled(true);
    125. if (finishListener != null) {
    126. finishListener.onFinish();
    127. } else if (listener != null) {
    128. listener.onFinish();
    129. }
    130. }
    131. });
    132. animator.start();
    133. isLoading = false;
    134. }
    135. /**
    136. * 开始Loading
    137. */
    138. public void startLoading() {
    139. if (!isLoading) {
    140. clearAnimation();
    141. showStartLoadAnimation();
    142. }
    143. }
    144. /**
    145. * 开始Loading
    146. *
    147. * @param listener Loading开始时的回调
    148. */
    149. public void startLoading(OnStartListener listener) {
    150. if (!isLoading) {
    151. this.startListener = listener;
    152. clearAnimation();
    153. showStartLoadAnimation();
    154. }
    155. }
    156. /**
    157. * 结束Loading
    158. */
    159. public void finishLoading() {
    160. if (isLoading) {
    161. clearAnimation();
    162. showFinishLoadAnimation();
    163. }
    164. }
    165. /**
    166. * 结束Loading
    167. *
    168. * @param listener Loading结束时的回调
    169. */
    170. public void finishLoading(OnFinishListener listener) {
    171. if (isLoading) {
    172. this.finishListener = listener;
    173. clearAnimation();
    174. showFinishLoadAnimation();
    175. }
    176. }
    177. /**
    178. * 设置Loading开始和结束时的回调接口
    179. *
    180. * @param listener
    181. */
    182. public void setOnLoadingListener(OnLoadingListener listener) {
    183. this.listener = listener;
    184. }
    185. /**
    186. * 设置按钮缩成Loading动画的时间
    187. *
    188. * @param reduceDuration 时间,单位毫秒
    189. */
    190. public void setReduceDuration(int reduceDuration) {
    191. this.reduceDuration = reduceDuration;
    192. }
    193. /**
    194. * 设置Loading动画旋转周期
    195. *
    196. * @param rotateDuration 旋转周期,单位毫秒
    197. */
    198. public void setRotateDuration(int rotateDuration) {
    199. this.rotateDuration = rotateDuration;
    200. }
    201. /**
    202. * 获取是否正在Loading
    203. *
    204. * @return
    205. */
    206. public boolean isLoading() {
    207. return isLoading;
    208. }
    209. /**
    210. * 设置Loading旋转动画控制器
    211. *
    212. * @param rotateInterpolator
    213. */
    214. public void setRotateInterpolator(Interpolator rotateInterpolator) {
    215. this.rotateInterpolator = rotateInterpolator;
    216. }
    217. /**
    218. * 按钮缩成Loading动画的控制器
    219. *
    220. * @param reduceInterpolator
    221. */
    222. public void setReduceInterpolator(Interpolator reduceInterpolator) {
    223. this.reduceInterpolator = reduceInterpolator;
    224. }
    225. /**
    226. * Loading开始时的回调接口
    227. */
    228. public interface OnStartListener {
    229. void onStart();
    230. }
    231. /**
    232. * Loading结束时的回调接口
    233. */
    234. public interface OnFinishListener {
    235. void onFinish();
    236. }
    237. /**
    238. * Loading开始和结束时的回调接口
    239. */
    240. public interface OnLoadingListener {
    241. void onStart();
    242. void onFinish();
    243. }
    244. }

    button_main_color_up.xml

    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android">
    3. "20dp" />
    4. "#45a8ca" />
    5. android:endColor="#45a8ca"
    6. android:startColor="#6fd1e7" />

    button_main_color_down.xml

    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android">
    3. "20dp" />
    4. "#45a8aa" />
    5. android:endColor="#45a8aa"
    6. android:startColor="#6fd1c7" />

    button_main_color_selector.xml

    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android">
    3. "@drawable/button_main_color_up" android:state_pressed="false">
    4. "@drawable/button_main_color_down" android:state_pressed="true">

    circle_loading.xml代码

    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android"
    3. android:innerRadius="18dp"
    4. android:shape="ring"
    5. android:thickness="2dp"
    6. android:useLevel="false">
    7. "#45a8ca" />
    8. android:endColor="#45a8ca"
    9. android:startColor="#0000"
    10. android:type="sweep" />

    在activity.xml里面的代码为:

    1. android:id="@+id/load_btn"
    2. android:layout_width="match_parent"
    3. android:layout_height="40dp"
    4. android:layout_margin="10dp"
    5. android:background="@drawable/button_main_color_selector"
    6. android:text="CLICK"
    7. android:textColor="#ffffff"
    8. app:layout_constraintBottom_toBottomOf="parent"
    9. app:layout_constraintEnd_toEndOf="parent"
    10. app:layout_constraintStart_toStartOf="parent"
    11. app:layout_constraintTop_toTopOf="parent" />

    在activity里的代码为(开始加载):

    1. findViewById(R.id.load_btn).setOnClickListener {
    2. (it as LoadingButton).startLoading()
    3. }

    结束加载:finishLoading

    方式三

    LoadingButton的代码
    1. package com.oneway.demo.loadingbutton_master
    2. import android.content.Context
    3. import android.util.AttributeSet
    4. import android.util.Log
    5. import android.view.LayoutInflater
    6. import android.view.View
    7. import android.widget.ProgressBar
    8. import androidx.constraintlayout.widget.ConstraintLayout
    9. /**
    10. * 封装的LoadingButton按钮
    11. *
    12. * @author WY+ 22/9/19.
    13. */
    14. class LoadingButton(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
    15. // 是否在Loading中
    16. private var isLoading = false
    17. private var view: View? = null
    18. private var progressBar: ProgressBar? = null
    19. init {
    20. // 自定义TitleLayout的相关属性
    21. view = LayoutInflater.from(context).inflate(R.layout.layout_loading_button, this, true)
    22. progressBar = view?.findViewById(R.id.pb_loading)
    23. }
    24. /**
    25. * 重写点击事件
    26. */
    27. override fun setOnClickListener(l: OnClickListener?) {
    28. super.setOnClickListener {
    29. // Log.e("wang", "点击事件==点击的时候会进入这里")
    30. progressBar?.visibility = View.VISIBLE // 显示loading
    31. l?.onClick(view) // 回调给调用方
    32. }
    33. }
    34. fun complete() {
    35. progressBar?.visibility = View.GONE
    36. }
    37. }
    layout_loading_button.xml代码
    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. android:id="@+id/cl_loading"
    5. android:layout_width="match_parent"
    6. android:layout_height="wrap_content"
    7. android:padding="8dp">
    8. android:id="@+id/pb_loading"
    9. android:layout_width="24dp"
    10. android:layout_height="24dp"
    11. android:layout_marginRight="8dp"
    12. android:visibility="gone"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintEnd_toStartOf="@+id/tv_loading"
    15. app:layout_constraintHorizontal_chainStyle="packed"
    16. app:layout_constraintStart_toStartOf="parent"
    17. app:layout_constraintTop_toTopOf="parent" />
    18. android:id="@+id/tv_loading"
    19. android:layout_width="wrap_content"
    20. android:layout_height="wrap_content"
    21. android:text="login"
    22. android:textColor="@color/white"
    23. app:layout_constraintBottom_toBottomOf="parent"
    24. app:layout_constraintEnd_toEndOf="parent"
    25. app:layout_constraintStart_toEndOf="@+id/pb_loading"
    26. app:layout_constraintTop_toTopOf="parent" />

    使用:第一步在xml里面添加(跟普通的控件使用方式一样)

    1. android:id="@+id/lb_login"
    2. android:layout_width="90dp"
    3. android:layout_height="wrap_content"
    4. android:background="@color/purple_200"
    5. android:text="Hello World!"
    6. app:layout_constraintBottom_toBottomOf="parent"
    7. app:layout_constraintEnd_toEndOf="parent"
    8. app:layout_constraintStart_toStartOf="parent"
    9. app:layout_constraintTop_toTopOf="parent" />

    activity里面调用点击事件:

    1. val mLoadingButton = findViewById(R.id.lb_login)
    2. mLoadingButton.setOnClickListener {
    3. Log.e("wang", "点击==开始异步网络请求")
    4. Handler(Looper.myLooper()!!).postDelayed({
    5. Log.e("wang", "拿到请求结果")
    6. mLoadingButton.complete()
    7. }, 3000)
    8. }

  • 相关阅读:
    【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