├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── androidman │ │ └── loading │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── top │ │ │ └── androidman │ │ │ └── loading │ │ │ ├── DefaultLoadingAdapter.java │ │ │ ├── ImageFactory.java │ │ │ ├── LoadingApp.java │ │ │ ├── MainActivity.java │ │ │ └── Style.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xxhdpi │ │ ├── icon_empty.png │ │ ├── icon_failed.png │ │ ├── icon_loading.png │ │ └── icon_no_wifi.png │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── layout_default_loading_view.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── top │ └── androidman │ └── loading │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── loading ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── androidman │ │ └── loading │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── top │ │ │ └── androidman │ │ │ └── loading │ │ │ └── Loading.java │ └── res │ │ ├── drawable │ │ └── loading.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── top │ └── androidman │ └── loading │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 这可能是解耦程度最好的全局Loading框架 2 | ## 3 | ### 背景 4 | 几乎每一个App都会有一个Loading动画,用来让用户知道程序在运作而不是卡死从而缓解用户焦虑,提升用户体验。 5 | Loading动画结束后一般会有三种情况: 6 | - 操作成功,loading动画消失,显示正确的页面内容 7 | - 操作失败,loading动画消失,显示失败页面,让用户可以点击重试 8 | - 空页面,虽然请求成功但是没有数据返回,所以此时loading动画消失,显示空页面状态 9 | 10 | 所以总结起来,一般一个页面有以下四种状态 11 | 1. 加载状态 12 | 2. 成功状态 13 | 3. 失败状态 14 | 4. 空状态 15 | 16 | 对于一个设计良好的APP来说一般全局页面会保持一致,比如加载状态,失败状态和空状态等。但是也有可能不同的页面需要不同的各种状态,比如消息页面展示消息为空的空页面,订单页面展示订单为空的空页面;也可能是不同的页面需要不同的失败状态等 17 | 18 | ### 传统方案 19 | #### 方案一 20 | 1. 在页面的xml中写上各种状态的布局 21 | 2. 根据页面展现过程中控制各个布局的显示和隐藏 22 | 23 | 此方案耦合度极高,难以维护和修改,当App页面默认状态需要更改时代价太大,不利于维护 24 | 25 | #### 方案二 26 | 1. 自定义一个有各种状态的自定义view, 27 | 2. 这个自定义view加入到BaseFragment或BaseActivity页面的xml中 28 | 3. 在base类中提供showLoading(),showSuccess(),showFaile(),showEmpty()等方法供子类在合适的时机调用 29 | 30 | 此方案相较于第一种方案有了很大提升,用户可以对自定义的LoadingView样式进行修改,这样全局就可以得到改变,但是此方案仍然需要在xml中添加代码,存在耦合关系,不利于扩展 31 | 32 | ### 解耦方案 33 | 要解耦就先梳理一下我们需要实现的点: 34 | 1. 支持不同样式的加载、成功、失败和空状态,例如,可能有多种状态的加载样式,也可能有多种状态的空状态等 35 | 2. 整个Loading的相关东西不写到具体的页面中,利于扩展和维护 36 | 3. 支持在各种状态时添加重试逻辑,例如失败状态时点击重试,空状态时点击重新请求数据等 37 | 4. 能指定区域进行加载,例如局部刷新等 38 | 39 | 实现思路 40 | 1. 要实现第一点,兼顾不同状态可能有各种不同样式,需要根据不同的状态创建不同的view供我们在展示相应状态时使用 41 | 2. 实现第二点需要找到一个合适的时机,将我们创建的不同状态的view根据我们创建时的样式展示出来 42 | 3. 在用户需要点击重试时,用户可以加入回调,从而可以实现用户自己的逻辑 43 | 4. 要实现第四点需要找到需要加载的区域,然后在此区域上加上我们需要的布局即可 44 | 45 | ### 终极方案 Loading 46 | Loading是一个轻量级,深度解耦的加载框架,完全由用户控制,只有一个Java文件,你甚至可以直接把这个文件源码拷贝到你的工程中使用。 47 | 48 | 0. **演示** 49 | 50 | Activity|view|空状态|失败状态 51 | :---:|:---:|:---:|:---: 52 | ||| 53 | 1. 引入 54 | 55 | [ ![Download](https://api.bintray.com/packages/androidman/maven/loading/images/download.svg?version=1.0.0) ](https://bintray.com/androidman/maven/loading/1.0.0/link) 56 | 57 | ``` 58 | compile 'top.androidman.loading:loading:1.0.0' 59 | ``` 60 | 2.创建全局的默认Adapter,在Adapter中根据type创建不同的布局实现 61 | ``` 62 | public class DefaultLoadingAdapter extends Loading.Adapter { 63 | 64 | private Context mContext; 65 | 66 | public DefaultLoadingAdapter(Context context) { 67 | this.mContext = context; 68 | } 69 | 70 | @Override 71 | public View generateView(int viewType) { 72 | View defaultLoadingView = LayoutInflater.from(mContext).inflate(R.layout.layout_default_loading_view,null); 73 | ImageView image = defaultLoadingView.findViewById(R.id.image); 74 | TextView text = defaultLoadingView.findViewById(R.id.text); 75 | int imageResource = -1; 76 | String textResource = ""; 77 | 78 | defaultLoadingView.setVisibility(View.VISIBLE); 79 | switch (viewType) { 80 | case Style.LOADING: 81 | imageResource = R.drawable.loading; 82 | textResource = "正在加载。。。"; 83 | break; 84 | case Style.SUCCESS: 85 | defaultLoadingView.setVisibility(View.GONE); 86 | break; 87 | case Style.EMPTY: 88 | imageResource = R.drawable.icon_empty; 89 | textResource = "没有内容哦。。。"; 90 | break; 91 | case Style.FAILED: 92 | imageResource = R.drawable.icon_failed; 93 | textResource = "加载失败。。。"; 94 | break; 95 | case Style.NO_WIFI: 96 | imageResource = R.drawable.icon_no_wifi; 97 | textResource = "网络出错啦,点击重试。。。"; 98 | break; 99 | default: 100 | break; 101 | } 102 | image.setImageResource(imageResource); 103 | text.setText(textResource); 104 | 105 | return defaultLoadingView; 106 | } 107 | } 108 | ``` 109 | 当然完全可以创建更加复杂的布局,然后返回即可,另外如果有多种样式的Loading、成功、失败、空状态也可以全部定义出来然后返回即可。 110 | 111 | 3. 在Application中进行注册 112 | ``` 113 | Loading.getIns().setAdapter(new DefaultLoadingAdapter(this)); 114 | ``` 115 | 4. 然后你就可以在任何地方开心的进行使用了(根据创建View时type进行展示,如果是想整个activity中进行展示,在target方法中传入activity即可,如果只是想在某个view上进行展示,传入这个view就可以啦) 116 | ``` 117 | Loading.getIns().target(activity).show(Style.LOADING); 118 | ``` 119 | 或者 120 | ``` 121 | Loading.getIns().target(view).show(Style.SUCCESS); 122 | ``` 123 | ### 高级用法 124 | 每个布局都可能会加一些重试的策略在里面,这个时候只需要调用如下方案即可轻松完成 125 | ``` 126 | Loading.getIns().wrap(view).show(Style.FAILED, new Loading.OnRetryListener() { 127 | @Override 128 | public void retry() { 129 | picUrl = ImageFactory.getNormalImage(); 130 | loadData(); 131 | } 132 | }); 133 | ``` 134 | 其实,不仅是失败时候,任何状态下都可以加入这个重试的回调,都可以执行 135 | 136 | ### 最后的唠叨 137 | 可能小伙伴们都注意到了**Style.LOADING**、**Style.SUCCESS**、**Style.EMPTY**、**Style.FAILED**等状态,其实这个状态是小伙伴自己定义的,就是自己定义不同状态创建不同的View,然后在展示的时候根据不同的情况show不同的type即可,所以建议把Style写到一个集中的地方,方便全局调用,例如: 138 | ``` 139 | public final class Style { 140 | 141 | public static final int LOADING = 0x1; 142 | public static final int SUCCESS = 0x2; 143 | public static final int FAILED = 0x3; 144 | public static final int EMPTY = 0x4; 145 | public static final int NO_WIFI = 0x5; 146 | 147 | @IntDef({LOADING, SUCCESS, FAILED, EMPTY}) 148 | @Retention(RetentionPolicy.SOURCE) 149 | public @interface Loading { 150 | } 151 | 152 | } 153 | ``` 154 | 155 | 当然也可以直接写成全局常量,只要方便调用即可 156 | 157 | github传送门:[点这里](https://github.com/ansnail/Loading) 158 | 159 | ### 鸣谢 160 | 此方案思路来自于 https://github.com/luckybilly/Gloading ,对原作者表示感谢 -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "top.androidman.loading" 7 | minSdkVersion 21 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | dataBinding { 20 | enabled = true 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation 'com.android.support:appcompat-v7:28.0.0' 27 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 28 | testImplementation 'junit:junit:4.12' 29 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 30 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 31 | implementation 'top.androidman.loading:loading:1.0.0' 32 | api 'com.github.bumptech.glide:glide:4.8.0' 33 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/top/androidman/loading/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.chongding.loading; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.chongding.loading", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/top/androidman/loading/DefaultLoadingAdapter.java: -------------------------------------------------------------------------------- 1 | package top.androidman.loading; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | 10 | import top.androidman.loadinglibary.Loading; 11 | 12 | /** 13 | * @author yanjie 14 | * @version 1.0 15 | * @date 2019-04-28 16:38 16 | * @description 默认全局Adapter, 17 | */ 18 | public class DefaultLoadingAdapter extends Loading.Adapter { 19 | 20 | private Context mContext; 21 | 22 | public DefaultLoadingAdapter(Context context) { 23 | this.mContext = context; 24 | } 25 | 26 | @Override 27 | public View generateView(int viewType) { 28 | View defaultLoadingView = LayoutInflater.from(mContext).inflate(R.layout.layout_default_loading_view, null); 29 | ImageView image = defaultLoadingView.findViewById(R.id.image); 30 | TextView text = defaultLoadingView.findViewById(R.id.text); 31 | int imageResource = -1; 32 | String textResource = ""; 33 | 34 | defaultLoadingView.setVisibility(View.VISIBLE); 35 | switch (viewType) { 36 | case Style.LOADING: 37 | imageResource = R.drawable.loading; 38 | textResource = "正在加载。。。"; 39 | break; 40 | case Style.SUCCESS: 41 | defaultLoadingView.setVisibility(View.GONE); 42 | break; 43 | case Style.EMPTY: 44 | imageResource = R.drawable.icon_empty; 45 | textResource = "没有内容哦。。。"; 46 | break; 47 | case Style.FAILED: 48 | imageResource = R.drawable.icon_failed; 49 | textResource = "加载失败。。。"; 50 | break; 51 | case Style.NO_WIFI: 52 | imageResource = R.drawable.icon_no_wifi; 53 | textResource = "网络出错啦,点击重试。。。"; 54 | break; 55 | default: 56 | break; 57 | } 58 | image.setImageResource(imageResource); 59 | text.setText(textResource); 60 | 61 | return defaultLoadingView; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/top/androidman/loading/ImageFactory.java: -------------------------------------------------------------------------------- 1 | package top.androidman.loading; 2 | 3 | import java.util.Locale; 4 | 5 | /** 6 | * @author yanjie 7 | * @version 1.0 8 | * @date 2019-05-09 16:40 9 | */ 10 | public class ImageFactory { 11 | 12 | public static String getErrorImage() { 13 | return "http://www." + System.currentTimeMillis() + ".com/abc.png"; 14 | } 15 | 16 | public static String getNormalImage() { 17 | int id = (int) (Math.random() * 100000); 18 | return String.format(Locale.CHINA, "https://www.thiswaifudoesnotexist.net/example-%d.jpg", id); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/top/androidman/loading/LoadingApp.java: -------------------------------------------------------------------------------- 1 | package top.androidman.loading; 2 | 3 | import android.app.Application; 4 | 5 | import top.androidman.loadinglibary.Loading; 6 | 7 | 8 | /** 9 | * @author yanjie 10 | * @version 1.0 11 | * @date 2019-06-21 17:46 12 | * @description 13 | */ 14 | public class LoadingApp extends Application { 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | Loading.getIns().setAdapter(new DefaultLoadingAdapter(this)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/top/androidman/loading/MainActivity.java: -------------------------------------------------------------------------------- 1 | package top.androidman.loading; 2 | 3 | import android.databinding.DataBindingUtil; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.View; 10 | import android.widget.Toast; 11 | 12 | import com.bumptech.glide.Glide; 13 | import com.bumptech.glide.load.DataSource; 14 | import com.bumptech.glide.load.engine.GlideException; 15 | import com.bumptech.glide.request.RequestListener; 16 | import com.bumptech.glide.request.target.Target; 17 | 18 | import top.androidman.loading.databinding.ActivityMainBinding; 19 | import top.androidman.loadinglibary.Loading; 20 | 21 | public class MainActivity extends AppCompatActivity { 22 | 23 | private Handler mHandler = new Handler(); 24 | 25 | private ActivityMainBinding mBinding; 26 | 27 | private boolean image1Success; 28 | private boolean image2Success; 29 | 30 | private String picUrl; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | getSupportActionBar().hide(); 36 | mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 37 | setContentView(mBinding.getRoot()); 38 | Loading.getIns().target(this).show(Style.LOADING); 39 | Glide.with(this).load(ImageFactory.getNormalImage()).into(mBinding.ivImage1); 40 | Glide.with(this).load(ImageFactory.getNormalImage()).into(mBinding.ivImage2); 41 | mHandler.postDelayed(new Runnable() { 42 | @Override 43 | public void run() { 44 | Loading.getIns().target(MainActivity.this).show(Style.SUCCESS); 45 | } 46 | }, 3000); 47 | } 48 | 49 | 50 | public void loadImage1(View view) { 51 | Loading.getIns().target(mBinding.ivImage1).show(Style.LOADING); 52 | 53 | Glide.with(this) 54 | .load(ImageFactory.getNormalImage()) 55 | .listener(new RequestListener() { 56 | @Override 57 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { 58 | return false; 59 | } 60 | 61 | @Override 62 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { 63 | Loading.getIns().target(mBinding.ivImage1).show(Style.SUCCESS); 64 | return false; 65 | } 66 | }) 67 | .into(mBinding.ivImage1); 68 | } 69 | 70 | public void loadImage2(View view) { 71 | picUrl = ImageFactory.getErrorImage(); 72 | loadData(); 73 | } 74 | 75 | public void loadImageAll(View view) { 76 | image1Success = false; 77 | image2Success = false; 78 | Loading.getIns().target(mBinding.llContainer).show(Style.LOADING); 79 | Glide.with(this) 80 | .load(ImageFactory.getNormalImage()) 81 | .listener(new RequestListener() { 82 | @Override 83 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { 84 | return false; 85 | } 86 | 87 | @Override 88 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { 89 | image1Success = true; 90 | if (image2Success) { 91 | Loading.getIns().target(mBinding.llContainer).show(Style.SUCCESS); 92 | } 93 | return false; 94 | } 95 | }) 96 | .into(mBinding.ivImage1); 97 | 98 | Glide.with(this) 99 | .load(ImageFactory.getNormalImage()) 100 | .listener(new RequestListener() { 101 | @Override 102 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { 103 | return false; 104 | } 105 | 106 | @Override 107 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { 108 | image2Success = true; 109 | if (image1Success) { 110 | Loading.getIns().target(mBinding.llContainer).show(Style.SUCCESS); 111 | } 112 | return false; 113 | } 114 | }) 115 | .into(mBinding.ivImage2); 116 | } 117 | 118 | private void loadData() { 119 | Loading.getIns().target(mBinding.ivImage2).show(Style.LOADING); 120 | Glide.with(this) 121 | .load(picUrl) 122 | .listener(new RequestListener() { 123 | @Override 124 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { 125 | Loading.getIns().target(mBinding.ivImage2).show(Style.FAILED, new Loading.OnRetryListener() { 126 | @Override 127 | public void retry() { 128 | picUrl = ImageFactory.getNormalImage(); 129 | loadData(); 130 | } 131 | }); 132 | return false; 133 | } 134 | 135 | @Override 136 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { 137 | Loading.getIns().target(mBinding.ivImage2).show(Style.SUCCESS); 138 | return false; 139 | } 140 | }) 141 | .into(mBinding.ivImage2); 142 | } 143 | 144 | public void loadEmpty(View view) { 145 | Loading.getIns().target(mBinding.llContainer).show(Style.LOADING); 146 | mHandler.postDelayed(new Runnable() { 147 | @Override 148 | public void run() { 149 | Loading.getIns().target(mBinding.llContainer).show(Style.NO_WIFI, new Loading.OnRetryListener() { 150 | @Override 151 | public void retry() { 152 | Loading.getIns().target(mBinding.llContainer).show(Style.LOADING); 153 | mHandler.postDelayed(new Runnable() { 154 | @Override 155 | public void run() { 156 | Loading.getIns().target(mBinding.llContainer).show(Style.EMPTY, new Loading.OnRetryListener() { 157 | @Override 158 | public void retry() { 159 | Toast.makeText(MainActivity.this, "空状态", Toast.LENGTH_SHORT).show(); 160 | } 161 | }); 162 | } 163 | }, 3000); 164 | } 165 | }); 166 | } 167 | }, 3000); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /app/src/main/java/top/androidman/loading/Style.java: -------------------------------------------------------------------------------- 1 | package top.androidman.loading; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * @author yanjie 10 | * @version 1.0 11 | * @date 2019/4/16 上午10:31 12 | * @description 13 | */ 14 | public final class Style { 15 | 16 | /////////////////////////////////////////////////////////////////////////// 17 | // loading的各种状态开始 18 | /////////////////////////////////////////////////////////////////////////// 19 | 20 | public static final int LOADING = 0x1; 21 | public static final int SUCCESS = 0x2; 22 | public static final int FAILED = 0x3; 23 | public static final int EMPTY = 0x4; 24 | public static final int NO_WIFI = 0x5; 25 | 26 | @IntDef({LOADING, SUCCESS, FAILED, EMPTY}) 27 | @Retention(RetentionPolicy.SOURCE) 28 | public @interface Loading { 29 | } 30 | 31 | /////////////////////////////////////////////////////////////////////////// 32 | // loading的各种状态结束 33 | /////////////////////////////////////////////////////////////////////////// 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansnail/Loading/4a43c917e26371f75e0cc48d084efdc0ebf3eb48/app/src/main/res/drawable-xxhdpi/icon_empty.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansnail/Loading/4a43c917e26371f75e0cc48d084efdc0ebf3eb48/app/src/main/res/drawable-xxhdpi/icon_failed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansnail/Loading/4a43c917e26371f75e0cc48d084efdc0ebf3eb48/app/src/main/res/drawable-xxhdpi/icon_loading.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_no_wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansnail/Loading/4a43c917e26371f75e0cc48d084efdc0ebf3eb48/app/src/main/res/drawable-xxhdpi/icon_no_wifi.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 15 | 16 | 20 | 21 | 25 | 26 | 27 | 28 |