├── LoadingViewManager.java └── README.md /LoadingViewManager.java: -------------------------------------------------------------------------------- 1 | import android.app.Activity; 2 | import android.app.Fragment; 3 | import android.graphics.Color; 4 | import android.os.Build; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | import android.util.Log; 8 | import android.util.TypedValue; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.RelativeLayout; 12 | import android.widget.TextView; 13 | 14 | import com.wang.avi.AVLoadingIndicatorView; 15 | 16 | /** 17 | * @author BarefootBKK 18 | * @date 2020/02/02 19 | */ 20 | public class LoadingViewManager { 21 | public final static int MATCH_PARENT = RelativeLayout.LayoutParams.MATCH_PARENT; 22 | public final static int WRAP_CONTENT = RelativeLayout.LayoutParams.WRAP_CONTENT; 23 | 24 | private static LoadingViewContainer loadingViewContainer; 25 | 26 | public static LoadingViewContainer with(Activity activity) { 27 | loadingViewContainer = new LoadingViewContainer(activity); 28 | return loadingViewContainer; 29 | } 30 | 31 | public static LoadingViewContainer with(Fragment fragment) { 32 | return with(fragment.getActivity()); 33 | } 34 | 35 | public LoadingViewManager(Activity activity) { 36 | loadingViewContainer = new LoadingViewContainer(activity); 37 | } 38 | 39 | public LoadingViewManager(Fragment fragment) { 40 | this(fragment.getActivity()); 41 | } 42 | 43 | public LoadingViewContainer getLoadingViewContainer() { 44 | return loadingViewContainer; 45 | } 46 | 47 | public static void dismiss() { 48 | dismiss(false); 49 | } 50 | 51 | public static void dismiss(boolean isForcedDismiss) { 52 | if (loadingViewContainer != null) { 53 | loadingViewContainer.dismiss(isForcedDismiss); 54 | loadingViewContainer = null; 55 | } 56 | } 57 | 58 | public static void updateHintText(String hintText) { 59 | if (loadingViewContainer != null) { 60 | loadingViewContainer.setHintText(hintText); 61 | } 62 | } 63 | 64 | public static void updateAnimation(String animationName) { 65 | if (loadingViewContainer != null) { 66 | loadingViewContainer.setAnimationStyle(animationName); 67 | } 68 | } 69 | 70 | public static boolean isShowing() { 71 | return loadingViewContainer != null && loadingViewContainer.isShowing(); 72 | } 73 | 74 | public interface OnAnimatingListener { 75 | void onAnimating(); 76 | void onDismiss(); 77 | } 78 | 79 | public static class LoadingViewContainer { 80 | private ViewGroup parentView; 81 | private CardView innerRectangle; 82 | private RelativeLayout innerRelativeLayout; 83 | private RelativeLayout loadingLayoutContainer; 84 | private View loadingLayoutOutsideView; 85 | private View innerRectangleCover; 86 | private AVLoadingIndicatorView avLoadingIndicatorView; 87 | private RelativeLayout.LayoutParams animationLayoutParams; 88 | private RelativeLayout.LayoutParams textLayoutParams; 89 | private RelativeLayout.LayoutParams innerRectangleParams; 90 | private TextView loadingTextView; 91 | private int size; 92 | private int defaultAnimText = 20; 93 | private Activity mActivity; 94 | private long minAnimTime = 1000; 95 | private long maxAnimTime = 600000; 96 | private boolean isForcedDismiss = false; 97 | private boolean isSetToDismiss = false; 98 | private boolean isDismissed = false; 99 | private OnAnimatingListener animatingListener; 100 | 101 | public LoadingViewContainer(Activity activity) { 102 | this.mActivity = activity; 103 | this.parentView = (ViewGroup)((ViewGroup)activity.findViewById(android.R.id.content)).getChildAt(0); 104 | buildLayout(); 105 | } 106 | 107 | @SuppressWarnings("ResourceType") 108 | private void buildLayout() { 109 | size = mActivity.getResources().getDisplayMetrics().widthPixels; 110 | // 主容器 111 | loadingLayoutContainer = new RelativeLayout(mActivity); 112 | // api21 版本才可使用此功能 113 | if (Build.VERSION.SDK_INT >= 21) { 114 | loadingLayoutContainer.setElevation(999f); 115 | } 116 | loadingLayoutContainer.setOnClickListener(new View.OnClickListener() { 117 | @Override 118 | public void onClick(View v) { 119 | // 防止其它控件影响 120 | } 121 | }); 122 | loadingLayoutContainer.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 123 | // 外部背景控件 124 | loadingLayoutOutsideView = new View(mActivity); 125 | loadingLayoutOutsideView.setBackgroundColor(Color.parseColor("#000000")); 126 | loadingLayoutOutsideView.setAlpha(0.5f); 127 | loadingLayoutOutsideView.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 128 | // 内部方形背景 129 | innerRectangle = new CardView(mActivity); 130 | innerRectangle.setCardElevation(0); 131 | innerRectangle.setCardBackgroundColor(Color.parseColor("#00000000")); 132 | innerRectangle.setRadius(30f); 133 | innerRectangleParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); 134 | innerRectangleParams.addRule(RelativeLayout.CENTER_IN_PARENT); 135 | innerRectangle.setLayoutParams(innerRectangleParams); 136 | // 内部方形RelativeLayout 137 | innerRelativeLayout = new RelativeLayout(mActivity); 138 | // 内部方形cover 139 | innerRectangleCover = new View(mActivity); 140 | innerRectangleCover.setBackgroundColor(Color.parseColor("#6B6969")); 141 | innerRectangleCover.setAlpha(0.8f); 142 | // 动画控件 143 | avLoadingIndicatorView = new AVLoadingIndicatorView(mActivity); 144 | animationLayoutParams = new RelativeLayout.LayoutParams(size / 7, size / 7); 145 | avLoadingIndicatorView.setId(1); 146 | avLoadingIndicatorView.setIndicator("BallSpinFadeLoaderIndicator"); 147 | // 提示控件 148 | loadingTextView = new TextView(mActivity); 149 | textLayoutParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); 150 | loadingTextView.setMaxWidth(size / 3); 151 | loadingTextView.setTextColor(Color.parseColor("#ffffff")); 152 | loadingTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); 153 | loadingTextView.setText("loading"); 154 | // 其他设置 155 | setShowInnerRectangle(false); 156 | setLoadingContentMargins(50); 157 | } 158 | 159 | public LoadingViewContainer setLoadingContentMargins(int margins) { 160 | return setLoadingContentMargins(margins, margins, margins, margins); 161 | } 162 | 163 | public LoadingViewContainer setLoadingContentMargins(int left, int top, int right, int bottom) { 164 | return setLoadingContentMargins(left, top, right, bottom, defaultAnimText); 165 | } 166 | 167 | public LoadingViewContainer setAnimationSize(double multiple) { 168 | int value = (int)(size * multiple); 169 | return setAnimationSize(value, value); 170 | } 171 | 172 | public LoadingViewContainer setAnimationSize(int width, int height) { 173 | if (width > 0 && height > 0) { 174 | animationLayoutParams.width = width; 175 | animationLayoutParams.height = height; 176 | } 177 | return this; 178 | } 179 | 180 | public LoadingViewContainer setLoadingContentMargins(int left, int top, int right, int bottom, int animTextMargin) { 181 | // 加载动画控件 182 | animationLayoutParams.topMargin = top; 183 | animationLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL); 184 | // 字体控件 185 | textLayoutParams.leftMargin = left; 186 | textLayoutParams.rightMargin = right; 187 | textLayoutParams.bottomMargin = bottom; 188 | textLayoutParams.topMargin = animTextMargin; 189 | return this; 190 | } 191 | 192 | public LoadingViewContainer setInnerRectangleRadius(float radius) { 193 | if (radius >= 0) { 194 | innerRectangle.setRadius(radius); 195 | } 196 | return this; 197 | } 198 | 199 | public LoadingViewContainer setLoadingContentTopMargin(int top) { 200 | animationLayoutParams.topMargin = top; 201 | return this; 202 | } 203 | 204 | public LoadingViewContainer setLoadingContentLeftMargin(int left) { 205 | textLayoutParams.leftMargin = left; 206 | return this; 207 | } 208 | 209 | public LoadingViewContainer setLoadingContentRightMargin(int right) { 210 | textLayoutParams.rightMargin = right; 211 | return this; 212 | } 213 | 214 | public LoadingViewContainer setLoadingContentBottomMargin(int bottom) { 215 | textLayoutParams.bottomMargin = bottom; 216 | return this; 217 | } 218 | 219 | public LoadingViewContainer setAnimTextMargin(int margin) { 220 | textLayoutParams.topMargin = margin; 221 | return this; 222 | } 223 | 224 | public LoadingViewContainer setInnerRectangleColor(String color) { 225 | return setInnerRectangleColor(Color.parseColor(color)); 226 | } 227 | 228 | public LoadingViewContainer setInnerRectangleColor(int color) { 229 | innerRectangleCover.setBackgroundColor(color); 230 | return this; 231 | } 232 | 233 | public LoadingViewContainer setShowInnerRectangle(boolean showInnerRectangle) { 234 | if (!showInnerRectangle) { 235 | innerRectangleCover.setVisibility(View.INVISIBLE); 236 | } else { 237 | innerRectangleCover.setVisibility(View.VISIBLE); 238 | } 239 | return this; 240 | } 241 | 242 | public LoadingViewContainer setInnerRectangleAlpha(float alpha) { 243 | if (alpha >= 0 && alpha <= 1) { 244 | innerRectangleCover.setAlpha(alpha); 245 | } 246 | return this; 247 | } 248 | 249 | public LoadingViewContainer setHintTextMaxWidth(double val) { 250 | if (val > 0 && val <= 1) { 251 | loadingTextView.setMaxWidth((int) (size * val)); 252 | } 253 | return this; 254 | } 255 | 256 | public LoadingViewContainer setHintTextColor(int color) { 257 | loadingTextView.setTextColor(color); 258 | return this; 259 | } 260 | 261 | public LoadingViewContainer setHintTextSize(int size) { 262 | loadingTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, size); 263 | return this; 264 | } 265 | 266 | public LoadingViewContainer setHintText(String msg) { 267 | loadingTextView.setText(msg); 268 | return this; 269 | } 270 | 271 | public LoadingViewContainer setOutsideAlpha(float alpha) { 272 | if (alpha >= 0 && alpha <= 1) { 273 | loadingLayoutOutsideView.setAlpha(alpha); 274 | } 275 | return this; 276 | } 277 | 278 | public LoadingViewContainer setOnTouchOutsideListener(View.OnClickListener clickListener) { 279 | loadingLayoutOutsideView.setOnClickListener(clickListener); 280 | return this; 281 | } 282 | 283 | public LoadingViewContainer setAnimationStyle(String indicatorName) { 284 | avLoadingIndicatorView.setIndicator(indicatorName); 285 | return this; 286 | } 287 | 288 | public LoadingViewContainer setOnAnimatingListener(OnAnimatingListener animatingListener) { 289 | this.animatingListener = animatingListener; 290 | return this; 291 | } 292 | 293 | public LoadingViewContainer setTouchOutsideToDismiss(boolean isDismiss) { 294 | if (isDismiss) { 295 | loadingLayoutOutsideView.setOnClickListener(new View.OnClickListener() { 296 | @Override 297 | public void onClick(View v) { 298 | dismiss(); 299 | } 300 | }); 301 | } 302 | return this; 303 | } 304 | 305 | public LoadingViewContainer setMaxAnimTime(long maxAnimTime) { 306 | if (maxAnimTime >= 0) { 307 | this.maxAnimTime = maxAnimTime; 308 | } 309 | return this; 310 | } 311 | 312 | public LoadingViewContainer setMinAnimTime(long minAnimTime) { 313 | if (minAnimTime >= 0) { 314 | this.minAnimTime = minAnimTime; 315 | } 316 | return this; 317 | } 318 | 319 | public void dismiss(boolean isForcedDismiss) { 320 | this.isForcedDismiss = isForcedDismiss; 321 | this.isSetToDismiss = true; 322 | if (isForcedDismiss) { 323 | dismiss(); 324 | } 325 | } 326 | 327 | public boolean isShowing() { 328 | return this.isDismissed; 329 | } 330 | 331 | private void dismiss() { 332 | isDismissed = true; 333 | avLoadingIndicatorView.hide(); 334 | parentView.removeView(loadingLayoutContainer); 335 | if (animatingListener != null) { 336 | animatingListener.onDismiss(); 337 | } 338 | } 339 | 340 | /** 341 | * 开始构建 342 | */ 343 | public void build() { 344 | animationLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL); 345 | textLayoutParams.addRule(RelativeLayout.BELOW, avLoadingIndicatorView.getId()); 346 | innerRelativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); 347 | loadingTextView.setLayoutParams(textLayoutParams); 348 | avLoadingIndicatorView.setLayoutParams(animationLayoutParams); 349 | /** 350 | * 把子容器加到父容器中 351 | */ 352 | // 1 353 | innerRelativeLayout.addView(avLoadingIndicatorView); 354 | innerRelativeLayout.addView(loadingTextView); 355 | // 2 356 | innerRectangle.addView(innerRelativeLayout); 357 | innerRectangle.measure(0, 0); 358 | innerRectangleCover.setLayoutParams(new RelativeLayout.LayoutParams(innerRectangle.getMeasuredWidth(), innerRectangle.getMeasuredHeight())); 359 | innerRectangle.addView(innerRectangleCover); 360 | innerRectangle.bringChildToFront(innerRelativeLayout); 361 | // 3 362 | loadingLayoutContainer.addView(loadingLayoutOutsideView); 363 | loadingLayoutContainer.addView(innerRectangle); 364 | // 设置 365 | loadingLayoutContainer.bringChildToFront(innerRectangle); 366 | avLoadingIndicatorView.show(); 367 | // 4 368 | parentView.addView(loadingLayoutContainer); 369 | parentView.bringChildToFront(loadingLayoutContainer); 370 | parentView.updateViewLayout(loadingLayoutContainer, loadingLayoutContainer.getLayoutParams()); 371 | 372 | new Thread(new Runnable() { 373 | @Override 374 | public void run() { 375 | MyHandler mHandler = new MyHandler(mActivity); 376 | long time = 0; 377 | while (true) { 378 | try { 379 | if (time <= maxAnimTime && !isForcedDismiss) { 380 | if (animatingListener != null) { 381 | animatingListener.onAnimating(); 382 | } 383 | if (time >= minAnimTime && isSetToDismiss) { 384 | mHandler.sendEmptyMessage(0); 385 | break; 386 | } 387 | } else { 388 | break; 389 | } 390 | time += 100; 391 | Thread.sleep(100); 392 | } catch (Exception e) { 393 | Log.d("测试", "动画出错: " + e.toString()); 394 | } 395 | } 396 | mHandler.sendEmptyMessage(5); 397 | } 398 | }).start(); 399 | } 400 | 401 | class MyHandler extends Handler { 402 | WeakReference activityWeakReference; 403 | 404 | MyHandler(Activity activity) { 405 | this.activityWeakReference = new WeakReference<>(activity); 406 | } 407 | 408 | @Override 409 | public void handleMessage(Message msg) { 410 | super.handleMessage(msg); 411 | if (activityWeakReference != null) { 412 | if (!isDismissed) { 413 | dismiss(); 414 | } 415 | } 416 | } 417 | } 418 | } 419 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LoadingViewManager-For-Android 2 | 3 | **这是一个能快速创建【加载动画】的封装类,无需任何布局文件,并搭配多种加载动画** 4 | 5 | 6 | 7 | ## 准备工作 8 | 9 | #### 在build.gradle(app)中加入依赖 10 | 11 | ``` 12 | implementation 'com.wang.avi:library:2.1.3' 13 | implementation 'com.squareup.assertj:assertj-android-cardview-v7:1.2.0' 14 | ``` 15 | 16 | #### 引入LoadingViewManager 17 | 18 | 下载本项目的```LoadingViewManager.java```文件,将其复制到自己的安卓项目中 19 | 20 | 21 | ## 快速开始 22 | 23 | #### 构建动画 24 | 25 | ``` 26 | LoadingViewManager.with(Activity或Fragment).setHintText("加载提示").build(); 27 | ``` 28 | 29 | #### 关闭动画 30 | 31 | ``` 32 | LoadingViewManager.dismiss(); 33 | ``` 34 | 35 | 36 | ## 更多用法 37 | 38 | ### 概览 39 | 40 | ``` 41 | LoadingViewManager.with(this) // Activity或Fragment 42 | .setHintText("加载中") // 提示信息 43 | .setAnimationStyle("BallClipRotatePulseIndicator") // 修改动画样式,传入样式名称 44 | .setShowInnerRectangle(true) // 是否显示矩形框 45 | .setTouchOutsideToDismiss(true) // 是否点击动画外部消失 46 | .setOutsideAlpha(0.5f) // 设置外部背景透明度 47 | .setInnerRectangleAlpha(0.8f) // 设置矩形框透明度 48 | .setLoadingContentMargins(20, 40, 20, 50) // 设置动画与矩形框的距离,间接也设置了矩形框大小 49 | .setMinAnimTime(2000) // 设置动画的最短时长 50 | .setAnimationSize(400, 400) // 设置动画样式大小 51 | .setHintTextSize(50) // 设置提示文本的大小 52 | .setInnerRectangleColor("#000") // 设置矩形框颜色 53 | .setOnTouchOutsideListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | // 可自定义点击动画外部分的响应 57 | } 58 | }) 59 | .setOnAnimatingListener(new LoadingViewManager.OnAnimatingListener() { // 动画加载中的监听器 60 | @Override 61 | public void onAnimating() { 62 | // 加载中 63 | } 64 | 65 | @Override 66 | public void onDismiss() { 67 | // 动画完成(消失)后 68 | } 69 | }) 70 | .build(); // 开始构建 71 | ``` 72 | 73 | ### 高级 74 | 75 | #### 动画加载中,更新文本信息或动画样式 76 | 77 | ``` 78 | LoadingViewManager.updateHintText("更新提示"); 79 | 80 | LoadingViewManager.updateAnimation("动画样式名称"); 81 | ``` 82 | 83 | #### 强制关闭动画 84 | 85 | ``` 86 | LoadingViewManager.dismiss(true); // 参数:isForcedDismiss 是否强制关闭 87 | ``` 88 | 89 | #### 参数默认值示例 90 | 91 | ``` 92 | minAnimTime = 1000 93 | 94 | maxAnimTime = 600000 95 | 96 | setLoadingContentMargins(50, 50, 50, 50, 20) 97 | 98 | setAnimationSize(0.1429) 99 | 100 | textSize = 14 101 | 102 | setHintTextMaxWidth(0.3333) 103 | ``` 104 | 105 | #### 动画样式与样式名称 106 | 107 | 108 | 109 | ``` 110 | // 第一行 111 | BallPulseIndicator、BallGridPulseIndicator、BallClipRotateIndicator、BallClipRotatePulseIndicator 112 | 113 | // 第二行 114 | SquareSpinIndicator、BallClipRotateMultipleIndicator、BallPulseRiseIndicator、BallRotateIndicator 115 | 116 | // 第三行 117 | CubeTransitionIndicator、BallZigZagIndicator、BallZigZagDeflectIndicator、BallTrianglePathIndicator 118 | 119 | // 第四行 120 | BallScaleIndicator、LineScaleIndicator、LineScalePartyIndicator、BallScaleMultipleIndicator 121 | 122 | // 第五行 123 | BallPulseSyncIndicator、BallBeatIndicator、LineScalePulseOutIndicator、LineScalePulseOutRapidIndicator 124 | 125 | // 第六行 126 | BallScaleRippleIndicator、BallScaleRippleMultipleIndicator、BallSpinFadeLoaderIndicator、LineSpinFadeLoaderIndicator 127 | 128 | // 第七行 129 | TriangleSkewSpinIndicator、PacmanIndicator、BallGridBeatIndicator、SemiCircleSpinIndicator 130 | ``` 131 | 132 | ## 感谢 133 | 134 | - [AVLoadingIndicatorView](https://github.com/hanzhanbing/AVLoadingIndicatorView) 135 | --------------------------------------------------------------------------------