├── sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_empty.png
│ │ │ │ ├── ic_error.png
│ │ │ │ ├── ic_extend.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_no_network.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── status_content.xml
│ │ │ │ ├── status_loading.xml
│ │ │ │ ├── status_error.xml
│ │ │ │ ├── status_extend.xml
│ │ │ │ ├── status_no_network.xml
│ │ │ │ ├── status_empty.xml
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── enlogy
│ │ │ └── mystatusview
│ │ │ └── MainActivity.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── enlogy
│ │ │ └── statusview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── enlogy
│ │ └── statusview
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── statusview
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── attrs.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-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── enlogy
│ │ │ └── statusview
│ │ │ ├── StatusView.java
│ │ │ ├── StatusLinearLayout.java
│ │ │ ├── StatusFrameLayout.java
│ │ │ └── StatusRelativeLayout.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── enlogy
│ │ │ └── statusview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── enlogy
│ │ └── statusview
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── img
├── logo.png
└── effect.gif
├── apk
└── StatusViewSample.apk
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── caches
│ └── build_file_checksums.ser
├── runConfigurations.xml
├── gradle.xml
├── misc.xml
└── codeStyles
│ └── Project.xml
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/statusview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample','statusview'
2 |
--------------------------------------------------------------------------------
/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/img/logo.png
--------------------------------------------------------------------------------
/img/effect.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/img/effect.gif
--------------------------------------------------------------------------------
/apk/StatusViewSample.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/apk/StatusViewSample.apk
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | StatusView
3 |
4 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/statusview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | StatusView
3 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_empty.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_error.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_extend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_extend.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_no_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_no_network.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enlogy/StatusView/HEAD/statusview/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/statusview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jan 25 15:26:17 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/statusview/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #ffffff
7 |
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/statusview/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/statusview/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/enlogy/statusview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/statusview/src/test/java/com/enlogy/statusview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/statusview/src/main/java/com/enlogy/statusview/StatusView.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by enlogy on 2019/1/24 0024.
7 | */
8 | public interface StatusView {
9 | void showContent();
10 | void showEmptyContent();
11 | void showErrorContent();
12 | void showNoNetworkContent();
13 | void showLoadingContent();
14 | void showExtendContent();
15 | void setOnItemClickListener(int viewId, View.OnClickListener listener);
16 | int getViewStatus();
17 | int STATUS_CONTENT = 0x00;
18 | int STATUS_LOADING = 0x01;
19 | int STATUS_EMPTY = 0x02;
20 | int STATUS_ERROR = 0x03;
21 | int STATUS_NO_NETWORK = 0x04;
22 | int STATUS_EXTEND = 0x05;
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/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 |
--------------------------------------------------------------------------------
/statusview/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 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/enlogy/statusview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
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.enlogy.statusview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
22 |
--------------------------------------------------------------------------------
/statusview/src/androidTest/java/com/enlogy/statusview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
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.enlogy.statusview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_extend.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_no_network.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/status_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/statusview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 |
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | versionCode 4
10 | versionName "1.0.3"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:27.1.1'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 | }
29 | group='com.github.Enlogty'
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.enlogy.mystatusview"
7 | minSdkVersion 15
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.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:28.0.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 | implementation project(':statusview')
29 | //implementation 'com.enlogy:statusview:1.0.0'
30 | }
31 |
--------------------------------------------------------------------------------
/statusview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/statusview/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
62 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/enlogy/mystatusview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.mystatusview;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import android.widget.Toast;
8 |
9 | import com.enlogy.statusview.StatusView;
10 |
11 | public class MainActivity extends AppCompatActivity {
12 | private Button btn1;
13 | private Button btn2;
14 | private Button btn3;
15 | private Button btn4;
16 | private Button btn5;
17 | private Button btn6;
18 | private StatusView statusView;
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main);
23 | btn1 = findViewById(R.id.btn1);
24 | btn2 = findViewById(R.id.btn2);
25 | btn3 = findViewById(R.id.btn3);
26 | btn4 = findViewById(R.id.btn4);
27 | btn5 = findViewById(R.id.btn5);
28 | btn6 = findViewById(R.id.btn6);
29 | statusView = findViewById(R.id.status_view);
30 | btn1.setOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | statusView.showContent();
34 | }
35 | });
36 | btn2.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | statusView.showEmptyContent();
40 |
41 | }
42 | });
43 | btn3.setOnClickListener(new View.OnClickListener() {
44 | @Override
45 | public void onClick(View v) {
46 | statusView.showErrorContent();
47 | }
48 | });
49 | btn4.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | statusView.showNoNetworkContent();
53 | }
54 | });
55 | btn5.setOnClickListener(new View.OnClickListener() {
56 | @Override
57 | public void onClick(View v) {
58 | statusView.showLoadingContent();
59 | }
60 | });
61 | btn6.setOnClickListener(new View.OnClickListener() {
62 | @Override
63 | public void onClick(View v) {
64 | statusView.showExtendContent();
65 | }
66 | });
67 | statusView.setOnItemClickListener(R.id.tv_empty, new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | Toast.makeText(MainActivity.this,"Empty Content !!!",Toast.LENGTH_SHORT).show();
71 | }
72 | });
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | # StatusView 介绍
6 | [](https://jitpack.io/#Enlogty/StatusView)
7 |
8 | 可以帮助android开发者减轻多种状态页面切换的代码量,如NoNetwork、Error、Empty等页面轻松切换,xml中自定义视图内容。
9 | 自动保存view的状态,不会因为切换页面而丢失状态。
10 | ## 引入
11 | [licensesvg]: https://img.shields.io/badge/License-Apache--2.0-brightgreen.svg
12 |
13 | * Gradle
14 | ```
15 | allprojects {
16 | repositories {
17 | ...
18 | maven { url 'https://jitpack.io' }
19 | }
20 | }
21 | ```
22 | ```
23 | implementation 'com.github.Enlogty:StatusView:1.0.3'
24 | ```
25 |
26 |
27 | ## 使用
28 |
29 | * #### xml中使用,默认显示ContentView里面的视图
30 | * #### StatusRelativeLayout可以根据需求更改为StatusFrameLayout或者StatusLinearLayout
31 | ```xml
32 |
42 |
43 | or
44 | //当StatusRelativeLayout布局里面同时存在child view和 app:rContentView="@layout/status_content"时,默认显示rContentView
45 | 的内容,如果只存在child view则显示child view。
46 |
47 | //推荐,此种形式布局层次更少
48 |
57 |
62 |
63 |
69 |
70 |
71 | ```
72 | * #### 代码中切换布局
73 | ```java
74 | //声明
75 | private StatusView statusView;
76 | //使用,单一调用直接切换视图
77 | statusView.showContent();//主视图
78 | statusView.showEmptyContent();//空视图
79 | statusView.showErrorContent();//错误视图
80 | statusView.showNoNetworkContent();//无网络视图
81 | statusView.showLoadingContent();//加载中视图
82 | statusView.showExtendContent();//扩展视图
83 | ```
84 | * #### 任意视图chlid view的点击监听
85 | ```java
86 | //声明
87 | private StatusView statusView;
88 | //使用,根据xml中对应view的id,进行点击事件的监听
89 | statusView.setOnItemClickListener(R.id.tv, new View.OnClickListener() {
90 | @Override
91 | public void onClick(View v) {
92 | Toast.makeText(MainActivity.this,"Hello World !!!",Toast.LENGTH_SHORT).show();
93 | }
94 | });
95 | ```
96 | ## 说明
97 | * #### 自定义属性说明
98 | ```xml
99 | 使用StatusRelativeLayout时,自定义属性对应r开头
100 | rContentView 主视图
101 | rEmptyView 空视图
102 | rErrorView 错误视图
103 | rExtendView 扩展视图
104 | rLoadingView 加载中视图
105 | rNoNetworkView 无网络视图
106 |
107 | or
108 |
109 | 使用StatusFrameLayout时,自定义属性对应f开头
110 | fContentView 主视图
111 | fEmptyView 空视图
112 | fErrorView 错误视图
113 | fExtendView 扩展视图
114 | fLoadingView 加载中视图
115 | fNoNetworkView 无网络视图
116 |
117 | or
118 |
119 | 使用StatusLinearLayout时,自定义属性对应l开头
120 | lContentView 主视图
121 | lEmptyView 空视图
122 | lErrorView 错误视图
123 | lExtendView 扩展视图
124 | lLoadingView 加载中视图
125 | lNoNetworkView 无网络视图
126 | ```
127 | * #### 其它常用方法、常量
128 | ```java
129 | //状态码
130 | StatusView.STATUS_CONTENT 主视图
131 | StatusView.STATUS_LOADING 加载中视图
132 | StatusView.STATUS_EMPTY 空视图
133 | StatusView.STATUS_ERROR 错误视图
134 | StatusView.STATUS_NO_NETWORK 无网络视图
135 | StatusView.STATUS_EXTEND 扩展视图
136 | //方法
137 | //返回当前的试图状态
138 | int viewStatus = statusView.getViewStatus();
139 | ```
140 |
141 | ## 效果
142 | [apk下载](https://github.com/Enlogty/StatusView/blob/master/apk/StatusViewSample.apk?raw=true)
143 |
144 | 
145 |
146 | ### [StatusView](https://github.com/Enlogty/StatusView)
147 |
148 |
149 | ![][licensesvg]
150 | ## License
151 | ```
152 | Copyright (C) Enlogty(https://github.com/Enlogty/StatusView)
153 |
154 | Licensed under the Apache License, Version 2.0 (the "License");
155 | you may not use this file except in compliance with the License.
156 | You may obtain a copy of the License at
157 |
158 | http://www.apache.org/licenses/LICENSE-2.0
159 |
160 | Unless required by applicable law or agreed to in writing, software
161 | distributed under the License is distributed on an "AS IS" BASIS,
162 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163 | See the License for the specific language governing permissions and
164 | limitations under the License.
165 | ```
166 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # view to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/sample/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 |
--------------------------------------------------------------------------------
/statusview/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 |
--------------------------------------------------------------------------------
/statusview/src/main/java/com/enlogy/statusview/StatusLinearLayout.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.Nullable;
6 | import android.util.AttributeSet;
7 | import android.util.SparseArray;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.LinearLayout;
12 |
13 | /**
14 | * Multistate view
15 | * Created by enlogy on 2019/1/24 0024.
16 | */
17 | public class StatusLinearLayout extends LinearLayout implements StatusView {
18 | private LayoutInflater inflater;
19 | private int contentViewResId;
20 | private int loadingViewResId;
21 | private int emptyViewResId;
22 | private int errorViewResId;
23 | private int noNetworkViewResId;
24 | private int extendViewResId;
25 | private SparseArray contentVisibilityStatusArray;
26 | private SparseArray views = new SparseArray<>();
27 | private View contentView;
28 | private View emptyView;
29 | private View loadingView;
30 | private View noNetworkView;
31 | private View errorView;
32 | private View extendView;
33 | private static final int defValue = -1;
34 | private int viewStatus = defValue;
35 | private ViewGroup defViewGroup;
36 | private static final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
37 |
38 | public StatusLinearLayout(Context context) {
39 | this(context, null);
40 | }
41 |
42 | public StatusLinearLayout(Context context, @Nullable AttributeSet attrs) {
43 | this(context, attrs, 0);
44 | }
45 |
46 | public StatusLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
47 | super(context, attrs, defStyleAttr);
48 | inflater = LayoutInflater.from(context);
49 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.StatusLinearLayout, defStyleAttr, 0);
50 | contentViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lContentView, defValue);
51 | loadingViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lLoadingView, defValue);
52 | emptyViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lEmptyView, defValue);
53 | errorViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lErrorView, defValue);
54 | noNetworkViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lNoNetworkView, defValue);
55 | extendViewResId = typedArray.getResourceId(R.styleable.StatusLinearLayout_lExtendView, defValue);
56 | typedArray.recycle();
57 | }
58 |
59 | @Override
60 | protected void onFinishInflate() {
61 | super.onFinishInflate();
62 | initDefaultContentView();
63 | saveAllViewToArray();
64 | showContent();
65 | }
66 |
67 | /**
68 | * Initialization view to record the current state
69 | */
70 | private void initDefaultContentView() {
71 | defViewGroup = this;
72 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
73 | saveViewsToClick(defViewGroup, views);
74 | }
75 |
76 | /**
77 | * Display default content view
78 | */
79 | @Override
80 | public void showContent() {
81 | if (viewStatus == STATUS_CONTENT) {
82 | return;
83 | }
84 | if (contentViewResId != defValue) {
85 | removeAllViews();
86 | if (contentView == null) {
87 | contentView = inflater.inflate(contentViewResId, this, false);
88 | if (contentView instanceof ViewGroup) {
89 | saveViewsToClick((ViewGroup) contentView, views);
90 | }
91 | }
92 | addView(contentView, params);
93 | } else {
94 | removeOldView();
95 | invalidateViewVisibleFromStatus(defViewGroup, contentVisibilityStatusArray);
96 | }
97 | viewStatus = STATUS_CONTENT;
98 | }
99 |
100 | /**
101 | * Display empty content view
102 | */
103 | @Override
104 | public void showEmptyContent() {
105 | if (viewStatus == STATUS_EMPTY) {
106 | return;
107 | }
108 | removeOldView();
109 | viewStatus = STATUS_EMPTY;
110 | if (emptyViewResId != defValue) {
111 | if (emptyView == null) {
112 | emptyView = inflater.inflate(emptyViewResId, this, false);
113 | if (emptyView instanceof ViewGroup) {
114 | saveViewsToClick((ViewGroup) emptyView, views);
115 | }
116 | }
117 | addView(emptyView, params);
118 | }
119 | }
120 |
121 | /**
122 | * Remove the previous view
123 | */
124 | private void removeOldView() {
125 | switch (viewStatus) {
126 | case STATUS_CONTENT:
127 | if (contentViewResId != defValue) {
128 | removeView(contentView);
129 | } else {
130 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
131 | setAllViewGone(defViewGroup);
132 | }
133 | break;
134 | case STATUS_ERROR:
135 | removeView(errorView);
136 | break;
137 | case STATUS_LOADING:
138 | removeView(loadingView);
139 | break;
140 | case STATUS_EXTEND:
141 | removeView(extendView);
142 | break;
143 | case STATUS_NO_NETWORK:
144 | removeView(noNetworkView);
145 | break;
146 | case STATUS_EMPTY:
147 | removeView(emptyView);
148 | break;
149 | default:
150 | break;
151 | }
152 | }
153 |
154 | /**
155 | * Set all view to gone
156 | *
157 | * @param defViewGroup Operated object
158 | */
159 | private static void setAllViewGone(ViewGroup defViewGroup) {
160 | int childCount = defViewGroup.getChildCount();
161 | for (int i = 0; i < childCount; i++) {
162 | View child = defViewGroup.getChildAt(i);
163 | child.setVisibility(GONE);
164 | }
165 | }
166 |
167 | /**
168 | * Display error content view
169 | */
170 | @Override
171 | public void showErrorContent() {
172 | if (viewStatus == STATUS_ERROR) {
173 | return;
174 | }
175 | removeOldView();
176 | viewStatus = STATUS_ERROR;
177 | if (errorViewResId != defValue) {
178 | if (errorView == null) {
179 | errorView = inflater.inflate(errorViewResId, this, false);
180 | if (errorView instanceof ViewGroup) {
181 | saveViewsToClick((ViewGroup) errorView, views);
182 | }
183 | }
184 | addView(errorView, params);
185 | }
186 | }
187 |
188 | /**
189 | * Display no network content view
190 | */
191 | @Override
192 | public void showNoNetworkContent() {
193 | if (viewStatus == STATUS_NO_NETWORK) {
194 | return;
195 | }
196 | removeOldView();
197 | viewStatus = STATUS_NO_NETWORK;
198 | if (noNetworkViewResId != defValue) {
199 | if (noNetworkView == null) {
200 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
201 | if (noNetworkView instanceof ViewGroup) {
202 | saveViewsToClick((ViewGroup) noNetworkView, views);
203 | }
204 | }
205 | addView(noNetworkView, params);
206 | }
207 | }
208 |
209 | /**
210 | * Display loading content view
211 | */
212 | @Override
213 | public void showLoadingContent() {
214 | if (viewStatus == STATUS_LOADING) {
215 | return;
216 | }
217 | removeOldView();
218 | viewStatus = STATUS_LOADING;
219 | if (loadingViewResId != defValue) {
220 | if (loadingView == null) {
221 | loadingView = inflater.inflate(loadingViewResId, this, false);
222 | if (loadingView instanceof ViewGroup) {
223 | saveViewsToClick((ViewGroup) loadingView, views);
224 | }
225 | }
226 | addView(loadingView, params);
227 | }
228 | }
229 |
230 | /**
231 | * Display extend content view
232 | */
233 | @Override
234 | public void showExtendContent() {
235 | if (viewStatus == STATUS_EXTEND) {
236 | return;
237 | }
238 | removeOldView();
239 | viewStatus = STATUS_EXTEND;
240 | if (extendViewResId != defValue) {
241 | if (extendView == null) {
242 | extendView = inflater.inflate(extendViewResId, this, false);
243 | if (extendView instanceof ViewGroup) {
244 | saveViewsToClick((ViewGroup) extendView, views);
245 | }
246 | }
247 | addView(extendView, params);
248 | }
249 | }
250 |
251 | /**
252 | * Trying to click response listening
253 | *
254 | * @param viewId view id
255 | * @param listener listener
256 | */
257 | @Override
258 | public void setOnItemClickListener(int viewId, OnClickListener listener) {
259 | View view = getView(viewId);
260 | if (view != null) {
261 | view.setOnClickListener(listener);
262 | }
263 | }
264 |
265 | /**
266 | * An view to return the corresponding ID
267 | *
268 | * @param viewId view id
269 | * @return view
270 | */
271 | private View getView(int viewId) {
272 | return views.get(viewId);
273 | }
274 |
275 | /**
276 | * Returns the status currently displayed
277 | *
278 | * @return status
279 | */
280 | @Override
281 | public int getViewStatus() {
282 | return viewStatus;
283 | }
284 |
285 | /**
286 | * Save the visible state of the current view
287 | *
288 | * @param viewGroup Operated object
289 | * @return Current status array
290 | */
291 | private SparseArray saveViewVisibleStatus(ViewGroup viewGroup) {
292 | int childCount = viewGroup.getChildCount();
293 | SparseArray sparseArray = new SparseArray<>(childCount);
294 | for (int i = 0; i < childCount; i++) {
295 | View child = viewGroup.getChildAt(i);
296 | sparseArray.put(child.getId(), child.getVisibility());
297 | }
298 | return sparseArray;
299 | }
300 |
301 | /**
302 | * Save an view to click
303 | *
304 | * @param viewGroup Operated object
305 | * @return Current status array
306 | */
307 | private void saveViewsToClick(ViewGroup viewGroup, SparseArray sparseArray) {
308 | int childCount = viewGroup.getChildCount();
309 | for (int i = 0; i < childCount; i++) {
310 | View child = viewGroup.getChildAt(i);
311 | sparseArray.put(child.getId(), child);
312 | }
313 | }
314 |
315 | /**
316 | * Update the visible state of the current view
317 | *
318 | * @param viewGroup Operated object
319 | * @param sparseArray State array
320 | */
321 | private void invalidateViewVisibleFromStatus(ViewGroup viewGroup, SparseArray sparseArray) {
322 | int childCount = viewGroup.getChildCount();
323 | for (int i = 0; i < childCount; i++) {
324 | View child = viewGroup.getChildAt(i);
325 | int visible = sparseArray.get(child.getId(), defValue);
326 | if (visible == defValue) {
327 | child.setVisibility(VISIBLE);
328 | } else {
329 | child.setVisibility(visible);
330 | }
331 | }
332 | }
333 |
334 | /**
335 | * Save view to Array
336 | */
337 | private void saveAllViewToArray() {
338 | if (contentViewResId != defValue) {
339 | contentView = inflater.inflate(contentViewResId, this, false);
340 | if (contentView instanceof ViewGroup) {
341 | saveViewsToClick((ViewGroup) contentView, views);
342 | }
343 | }
344 | if (emptyViewResId != defValue) {
345 | emptyView = inflater.inflate(emptyViewResId, this, false);
346 | if (emptyView instanceof ViewGroup) {
347 | saveViewsToClick((ViewGroup) emptyView, views);
348 | }
349 | }
350 | if (errorViewResId != defValue) {
351 | errorView = inflater.inflate(errorViewResId, this, false);
352 | if (errorView instanceof ViewGroup) {
353 | saveViewsToClick((ViewGroup) errorView, views);
354 | }
355 | }
356 | if (noNetworkViewResId != defValue) {
357 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
358 | if (noNetworkView instanceof ViewGroup) {
359 | saveViewsToClick((ViewGroup) noNetworkView, views);
360 | }
361 | }
362 | if (loadingViewResId != defValue) {
363 | loadingView = inflater.inflate(loadingViewResId, this, false);
364 | if (loadingView instanceof ViewGroup) {
365 | saveViewsToClick((ViewGroup) loadingView, views);
366 | }
367 | }
368 | if (extendViewResId != defValue) {
369 | extendView = inflater.inflate(extendViewResId, this, false);
370 | if (extendView instanceof ViewGroup) {
371 | saveViewsToClick((ViewGroup) extendView, views);
372 | }
373 | }
374 | }
375 | }
376 |
--------------------------------------------------------------------------------
/statusview/src/main/java/com/enlogy/statusview/StatusFrameLayout.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.util.AttributeSet;
8 | import android.util.SparseArray;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.FrameLayout;
13 |
14 | /**
15 | * Multistate view
16 | * Created by enlogy on 2019/1/24 0024.
17 | */
18 | public class StatusFrameLayout extends FrameLayout implements StatusView {
19 | private LayoutInflater inflater;
20 | private int contentViewResId;
21 | private int loadingViewResId;
22 | private int emptyViewResId;
23 | private int errorViewResId;
24 | private int noNetworkViewResId;
25 | private int extendViewResId;
26 | private SparseArray contentVisibilityStatusArray;
27 | private SparseArray views = new SparseArray<>();
28 | private View contentView;
29 | private View emptyView;
30 | private View loadingView;
31 | private View noNetworkView;
32 | private View errorView;
33 | private View extendView;
34 | private static final int defValue = -1;
35 | private int viewStatus = defValue;
36 | private ViewGroup defViewGroup;
37 | private static final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
38 |
39 | public StatusFrameLayout(@NonNull Context context) {
40 | this(context, null);
41 | }
42 |
43 | public StatusFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
44 | this(context, attrs, 0);
45 | }
46 |
47 | public StatusFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
48 | super(context, attrs, defStyleAttr);
49 | inflater = LayoutInflater.from(context);
50 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.StatusFrameLayout, defStyleAttr, 0);
51 | contentViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fContentView, defValue);
52 | loadingViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fLoadingView, defValue);
53 | emptyViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fEmptyView, defValue);
54 | errorViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fErrorView, defValue);
55 | noNetworkViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fNoNetworkView, defValue);
56 | extendViewResId = typedArray.getResourceId(R.styleable.StatusFrameLayout_fExtendView, defValue);
57 | typedArray.recycle();
58 | }
59 |
60 | @Override
61 | protected void onFinishInflate() {
62 | super.onFinishInflate();
63 | initDefaultContentView();
64 | saveAllViewToArray();
65 | showContent();
66 | }
67 |
68 | /**
69 | * Initialization view to record the current state
70 | */
71 | private void initDefaultContentView() {
72 | defViewGroup = this;
73 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
74 | saveViewsToClick(defViewGroup, views);
75 | }
76 |
77 | /**
78 | * Display default content view
79 | */
80 | @Override
81 | public void showContent() {
82 | if (viewStatus == STATUS_CONTENT) {
83 | return;
84 | }
85 | if (contentViewResId != defValue) {
86 | removeAllViews();
87 | if (contentView == null) {
88 | contentView = inflater.inflate(contentViewResId, this, false);
89 | if (contentView instanceof ViewGroup) {
90 | saveViewsToClick((ViewGroup) contentView, views);
91 | }
92 | }
93 | addView(contentView, params);
94 | } else {
95 | removeOldView();
96 | invalidateViewVisibleFromStatus(defViewGroup, contentVisibilityStatusArray);
97 | }
98 | viewStatus = STATUS_CONTENT;
99 | }
100 |
101 | /**
102 | * Display empty content view
103 | */
104 | @Override
105 | public void showEmptyContent() {
106 | if (viewStatus == STATUS_EMPTY) {
107 | return;
108 | }
109 | removeOldView();
110 | viewStatus = STATUS_EMPTY;
111 | if (emptyViewResId != defValue) {
112 | if (emptyView == null) {
113 | emptyView = inflater.inflate(emptyViewResId, this, false);
114 | if (emptyView instanceof ViewGroup) {
115 | saveViewsToClick((ViewGroup) emptyView, views);
116 | }
117 | }
118 | addView(emptyView, params);
119 | }
120 | }
121 |
122 | /**
123 | * Remove the previous view
124 | */
125 | private void removeOldView() {
126 | switch (viewStatus) {
127 | case STATUS_CONTENT:
128 | if (contentViewResId != defValue) {
129 | removeView(contentView);
130 | } else {
131 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
132 | setAllViewGone(defViewGroup);
133 | }
134 | break;
135 | case STATUS_ERROR:
136 | removeView(errorView);
137 | break;
138 | case STATUS_LOADING:
139 | removeView(loadingView);
140 | break;
141 | case STATUS_EXTEND:
142 | removeView(extendView);
143 | break;
144 | case STATUS_NO_NETWORK:
145 | removeView(noNetworkView);
146 | break;
147 | case STATUS_EMPTY:
148 | removeView(emptyView);
149 | break;
150 | default:
151 | break;
152 | }
153 | }
154 |
155 | /**
156 | * Set all view to gone
157 | *
158 | * @param defViewGroup Operated object
159 | */
160 | private static void setAllViewGone(ViewGroup defViewGroup) {
161 | int childCount = defViewGroup.getChildCount();
162 | for (int i = 0; i < childCount; i++) {
163 | View child = defViewGroup.getChildAt(i);
164 | child.setVisibility(GONE);
165 | }
166 | }
167 |
168 | /**
169 | * Display error content view
170 | */
171 | @Override
172 | public void showErrorContent() {
173 | if (viewStatus == STATUS_ERROR) {
174 | return;
175 | }
176 | removeOldView();
177 | viewStatus = STATUS_ERROR;
178 | if (errorViewResId != defValue) {
179 | if (errorView == null) {
180 | errorView = inflater.inflate(errorViewResId, this, false);
181 | if (errorView instanceof ViewGroup) {
182 | saveViewsToClick((ViewGroup) errorView, views);
183 | }
184 | }
185 | addView(errorView, params);
186 | }
187 | }
188 |
189 | /**
190 | * Display no network content view
191 | */
192 | @Override
193 | public void showNoNetworkContent() {
194 | if (viewStatus == STATUS_NO_NETWORK) {
195 | return;
196 | }
197 | removeOldView();
198 | viewStatus = STATUS_NO_NETWORK;
199 | if (noNetworkViewResId != defValue) {
200 | if (noNetworkView == null) {
201 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
202 | if (noNetworkView instanceof ViewGroup) {
203 | saveViewsToClick((ViewGroup) noNetworkView, views);
204 | }
205 | }
206 | addView(noNetworkView, params);
207 | }
208 | }
209 |
210 | /**
211 | * Display loading content view
212 | */
213 | @Override
214 | public void showLoadingContent() {
215 | if (viewStatus == STATUS_LOADING) {
216 | return;
217 | }
218 | removeOldView();
219 | viewStatus = STATUS_LOADING;
220 | if (loadingViewResId != defValue) {
221 | if (loadingView == null) {
222 | loadingView = inflater.inflate(loadingViewResId, this, false);
223 | if (loadingView instanceof ViewGroup) {
224 | saveViewsToClick((ViewGroup) loadingView, views);
225 | }
226 | }
227 | addView(loadingView, params);
228 | }
229 | }
230 |
231 | /**
232 | * Display extend content view
233 | */
234 | @Override
235 | public void showExtendContent() {
236 | if (viewStatus == STATUS_EXTEND) {
237 | return;
238 | }
239 | removeOldView();
240 | viewStatus = STATUS_EXTEND;
241 | if (extendViewResId != defValue) {
242 | if (extendView == null) {
243 | extendView = inflater.inflate(extendViewResId, this, false);
244 | if (extendView instanceof ViewGroup) {
245 | saveViewsToClick((ViewGroup) extendView, views);
246 | }
247 | }
248 | addView(extendView, params);
249 | }
250 | }
251 |
252 | /**
253 | * Trying to click response listening
254 | *
255 | * @param viewId view id
256 | * @param listener listener
257 | */
258 | @Override
259 | public void setOnItemClickListener(int viewId, OnClickListener listener) {
260 | View view = getView(viewId);
261 | if (view != null) {
262 | view.setOnClickListener(listener);
263 | }
264 | }
265 |
266 | /**
267 | * An view to return the corresponding ID
268 | *
269 | * @param viewId view id
270 | * @return view
271 | */
272 | private View getView(int viewId) {
273 | return views.get(viewId);
274 | }
275 |
276 | /**
277 | * Returns the status currently displayed
278 | *
279 | * @return status
280 | */
281 | @Override
282 | public int getViewStatus() {
283 | return viewStatus;
284 | }
285 |
286 | /**
287 | * Save the visible state of the current view
288 | *
289 | * @param viewGroup Operated object
290 | * @return Current status array
291 | */
292 | private SparseArray saveViewVisibleStatus(ViewGroup viewGroup) {
293 | int childCount = viewGroup.getChildCount();
294 | SparseArray sparseArray = new SparseArray<>(childCount);
295 | for (int i = 0; i < childCount; i++) {
296 | View child = viewGroup.getChildAt(i);
297 | sparseArray.put(child.getId(), child.getVisibility());
298 | }
299 | return sparseArray;
300 | }
301 |
302 | /**
303 | * Save an view to click
304 | *
305 | * @param viewGroup Operated object
306 | * @return Current status array
307 | */
308 | private void saveViewsToClick(ViewGroup viewGroup, SparseArray sparseArray) {
309 | int childCount = viewGroup.getChildCount();
310 | for (int i = 0; i < childCount; i++) {
311 | View child = viewGroup.getChildAt(i);
312 | sparseArray.put(child.getId(), child);
313 | }
314 | }
315 |
316 | /**
317 | * Update the visible state of the current view
318 | *
319 | * @param viewGroup Operated object
320 | * @param sparseArray State array
321 | */
322 | private void invalidateViewVisibleFromStatus(ViewGroup viewGroup, SparseArray sparseArray) {
323 | int childCount = viewGroup.getChildCount();
324 | for (int i = 0; i < childCount; i++) {
325 | View child = viewGroup.getChildAt(i);
326 | int visible = sparseArray.get(child.getId(), defValue);
327 | if (visible == defValue) {
328 | child.setVisibility(VISIBLE);
329 | } else {
330 | child.setVisibility(visible);
331 | }
332 | }
333 | }
334 |
335 | /**
336 | * Save view to Array
337 | */
338 | private void saveAllViewToArray() {
339 | if (contentViewResId != defValue) {
340 | contentView = inflater.inflate(contentViewResId, this, false);
341 | if (contentView instanceof ViewGroup) {
342 | saveViewsToClick((ViewGroup) contentView, views);
343 | }
344 | }
345 | if (emptyViewResId != defValue) {
346 | emptyView = inflater.inflate(emptyViewResId, this, false);
347 | if (emptyView instanceof ViewGroup) {
348 | saveViewsToClick((ViewGroup) emptyView, views);
349 | }
350 | }
351 | if (errorViewResId != defValue) {
352 | errorView = inflater.inflate(errorViewResId, this, false);
353 | if (errorView instanceof ViewGroup) {
354 | saveViewsToClick((ViewGroup) errorView, views);
355 | }
356 | }
357 | if (noNetworkViewResId != defValue) {
358 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
359 | if (noNetworkView instanceof ViewGroup) {
360 | saveViewsToClick((ViewGroup) noNetworkView, views);
361 | }
362 | }
363 | if (loadingViewResId != defValue) {
364 | loadingView = inflater.inflate(loadingViewResId, this, false);
365 | if (loadingView instanceof ViewGroup) {
366 | saveViewsToClick((ViewGroup) loadingView, views);
367 | }
368 | }
369 | if (extendViewResId != defValue) {
370 | extendView = inflater.inflate(extendViewResId, this, false);
371 | if (extendView instanceof ViewGroup) {
372 | saveViewsToClick((ViewGroup) extendView, views);
373 | }
374 | }
375 | }
376 | }
377 |
--------------------------------------------------------------------------------
/statusview/src/main/java/com/enlogy/statusview/StatusRelativeLayout.java:
--------------------------------------------------------------------------------
1 | package com.enlogy.statusview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.util.SparseArray;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.RelativeLayout;
12 |
13 | /**
14 | * Multistate view
15 | * Created by enlogy on 2019/1/24 0024.
16 | */
17 | public class StatusRelativeLayout extends RelativeLayout implements StatusView {
18 | private LayoutInflater inflater;
19 | private int contentViewResId;
20 | private int loadingViewResId;
21 | private int emptyViewResId;
22 | private int errorViewResId;
23 | private int noNetworkViewResId;
24 | private int extendViewResId;
25 | private SparseArray contentVisibilityStatusArray;
26 | private SparseArray views = new SparseArray<>();
27 | private View contentView;
28 | private View emptyView;
29 | private View loadingView;
30 | private View noNetworkView;
31 | private View errorView;
32 | private View extendView;
33 | private static final int defValue = -1;
34 | private int viewStatus = defValue;
35 | private ViewGroup defViewGroup;
36 | private static final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
37 |
38 | public StatusRelativeLayout(Context context) {
39 | this(context, null);
40 | }
41 |
42 | public StatusRelativeLayout(Context context, AttributeSet attrs) {
43 | this(context, attrs, 0);
44 | }
45 |
46 | public StatusRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
47 | super(context, attrs, defStyleAttr);
48 | inflater = LayoutInflater.from(context);
49 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.StatusRelativeLayout, defStyleAttr, 0);
50 | contentViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rContentView, defValue);
51 | loadingViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rLoadingView, defValue);
52 | emptyViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rEmptyView, defValue);
53 | errorViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rErrorView, defValue);
54 | noNetworkViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rNoNetworkView, defValue);
55 | extendViewResId = typedArray.getResourceId(R.styleable.StatusRelativeLayout_rExtendView, defValue);
56 | typedArray.recycle();
57 | }
58 |
59 | @Override
60 | protected void onFinishInflate() {
61 | super.onFinishInflate();
62 | initDefaultContentView();
63 | saveAllViewToArray();
64 | showContent();
65 | }
66 |
67 | /**
68 | * Initialization view to record the current state
69 | */
70 | private void initDefaultContentView() {
71 | defViewGroup = this;
72 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
73 | saveViewsToClick(defViewGroup, views);
74 | }
75 |
76 | /**
77 | * Display default content view
78 | */
79 | @Override
80 | public void showContent() {
81 | if (viewStatus == STATUS_CONTENT) {
82 | return;
83 | }
84 | if (contentViewResId != defValue) {
85 | removeAllViews();
86 | if (contentView == null) {
87 | contentView = inflater.inflate(contentViewResId, this, false);
88 | if (contentView instanceof ViewGroup) {
89 | saveViewsToClick((ViewGroup) contentView, views);
90 | }
91 | }
92 | addView(contentView, params);
93 | } else {
94 | removeOldView();
95 | invalidateViewVisibleFromStatus(defViewGroup, contentVisibilityStatusArray);
96 | }
97 | viewStatus = STATUS_CONTENT;
98 | }
99 |
100 | /**
101 | * Display empty content view
102 | */
103 | @Override
104 | public void showEmptyContent() {
105 | if (viewStatus == STATUS_EMPTY) {
106 | return;
107 | }
108 | removeOldView();
109 | viewStatus = STATUS_EMPTY;
110 | if (emptyViewResId != defValue) {
111 | if (emptyView == null) {
112 | emptyView = inflater.inflate(emptyViewResId, this, false);
113 | if (emptyView instanceof ViewGroup) {
114 | saveViewsToClick((ViewGroup) emptyView, views);
115 | }
116 | }
117 | addView(emptyView, params);
118 | }
119 | }
120 |
121 | /**
122 | * Remove the previous view
123 | */
124 | private void removeOldView() {
125 | switch (viewStatus) {
126 | case STATUS_CONTENT:
127 | if (contentViewResId != defValue) {
128 | removeView(contentView);
129 | } else {
130 | contentVisibilityStatusArray = saveViewVisibleStatus(defViewGroup);
131 | setAllViewGone(defViewGroup);
132 | }
133 | break;
134 | case STATUS_ERROR:
135 | removeView(errorView);
136 | break;
137 | case STATUS_LOADING:
138 | removeView(loadingView);
139 | break;
140 | case STATUS_EXTEND:
141 | removeView(extendView);
142 | break;
143 | case STATUS_NO_NETWORK:
144 | removeView(noNetworkView);
145 | break;
146 | case STATUS_EMPTY:
147 | removeView(emptyView);
148 | break;
149 | default:
150 | break;
151 | }
152 | }
153 |
154 | /**
155 | * Set all view to gone
156 | *
157 | * @param defViewGroup Operated object
158 | */
159 | private static void setAllViewGone(ViewGroup defViewGroup) {
160 | int childCount = defViewGroup.getChildCount();
161 | for (int i = 0; i < childCount; i++) {
162 | View child = defViewGroup.getChildAt(i);
163 | child.setVisibility(GONE);
164 | }
165 | }
166 |
167 | /**
168 | * Display error content view
169 | */
170 | @Override
171 | public void showErrorContent() {
172 | if (viewStatus == STATUS_ERROR) {
173 | return;
174 | }
175 | removeOldView();
176 | viewStatus = STATUS_ERROR;
177 | if (errorViewResId != defValue) {
178 | if (errorView == null) {
179 | errorView = inflater.inflate(errorViewResId, this, false);
180 | if (errorView instanceof ViewGroup) {
181 | saveViewsToClick((ViewGroup) errorView, views);
182 | }
183 | }
184 | addView(errorView, params);
185 | }
186 | }
187 |
188 | /**
189 | * Display no network content view
190 | */
191 | @Override
192 | public void showNoNetworkContent() {
193 | if (viewStatus == STATUS_NO_NETWORK) {
194 | return;
195 | }
196 | removeOldView();
197 | viewStatus = STATUS_NO_NETWORK;
198 | if (noNetworkViewResId != defValue) {
199 | if (noNetworkView == null) {
200 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
201 | if (noNetworkView instanceof ViewGroup) {
202 | saveViewsToClick((ViewGroup) noNetworkView, views);
203 | }
204 | }
205 | addView(noNetworkView, params);
206 | }
207 | }
208 |
209 | /**
210 | * Display loading content view
211 | */
212 | @Override
213 | public void showLoadingContent() {
214 | if (viewStatus == STATUS_LOADING) {
215 | return;
216 | }
217 | removeOldView();
218 | viewStatus = STATUS_LOADING;
219 | if (loadingViewResId != defValue) {
220 | if (loadingView == null) {
221 | loadingView = inflater.inflate(loadingViewResId, this, false);
222 | if (loadingView instanceof ViewGroup) {
223 | saveViewsToClick((ViewGroup) loadingView, views);
224 | }
225 | }
226 | addView(loadingView, params);
227 | }
228 | }
229 |
230 | /**
231 | * Display extend content view
232 | */
233 | @Override
234 | public void showExtendContent() {
235 | if (viewStatus == STATUS_EXTEND) {
236 | return;
237 | }
238 | removeOldView();
239 | viewStatus = STATUS_EXTEND;
240 | if (extendViewResId != defValue) {
241 | if (extendView == null) {
242 | extendView = inflater.inflate(extendViewResId, this, false);
243 | if (extendView instanceof ViewGroup) {
244 | saveViewsToClick((ViewGroup) extendView, views);
245 | }
246 | }
247 | addView(extendView, params);
248 | }
249 | }
250 |
251 | /**
252 | * Trying to click response listening
253 | *
254 | * @param viewId view id
255 | * @param listener listener
256 | */
257 | @Override
258 | public void setOnItemClickListener(int viewId, OnClickListener listener) {
259 | View view = getView(viewId);
260 | Log.d("TestR", "setOnItemClickListener");
261 | if (view != null) {
262 | Log.d("TestR", "view != null");
263 | view.setOnClickListener(listener);
264 | }
265 | }
266 |
267 | /**
268 | * An view to return the corresponding ID
269 | *
270 | * @param viewId view id
271 | * @return view
272 | */
273 | private View getView(int viewId) {
274 | return views.get(viewId);
275 | }
276 |
277 | /**
278 | * Returns the status currently displayed
279 | *
280 | * @return status
281 | */
282 | @Override
283 | public int getViewStatus() {
284 | return viewStatus;
285 | }
286 |
287 | /**
288 | * Save the visible state of the current view
289 | *
290 | * @param viewGroup Operated object
291 | * @return Current status array
292 | */
293 | private SparseArray saveViewVisibleStatus(ViewGroup viewGroup) {
294 | int childCount = viewGroup.getChildCount();
295 | SparseArray sparseArray = new SparseArray<>(childCount);
296 | for (int i = 0; i < childCount; i++) {
297 | View child = viewGroup.getChildAt(i);
298 | sparseArray.put(child.getId(), child.getVisibility());
299 | }
300 | return sparseArray;
301 | }
302 |
303 | /**
304 | * Save an view to click
305 | *
306 | * @param viewGroup Operated object
307 | * @return Current status array
308 | */
309 | private void saveViewsToClick(ViewGroup viewGroup, SparseArray sparseArray) {
310 | int childCount = viewGroup.getChildCount();
311 | for (int i = 0; i < childCount; i++) {
312 | View child = viewGroup.getChildAt(i);
313 | sparseArray.put(child.getId(), child);
314 | }
315 | }
316 |
317 | /**
318 | * Update the visible state of the current view
319 | *
320 | * @param viewGroup Operated object
321 | * @param sparseArray State array
322 | */
323 | private void invalidateViewVisibleFromStatus(ViewGroup viewGroup, SparseArray sparseArray) {
324 | int childCount = viewGroup.getChildCount();
325 | for (int i = 0; i < childCount; i++) {
326 | View child = viewGroup.getChildAt(i);
327 | int visible = sparseArray.get(child.getId(), defValue);
328 | if (visible == defValue) {
329 | child.setVisibility(VISIBLE);
330 | } else {
331 | child.setVisibility(visible);
332 | }
333 | }
334 | }
335 |
336 | /**
337 | * Save view to Array
338 | */
339 | private void saveAllViewToArray() {
340 | if (contentViewResId != defValue) {
341 | contentView = inflater.inflate(contentViewResId, this, false);
342 | if (contentView instanceof ViewGroup) {
343 | saveViewsToClick((ViewGroup) contentView, views);
344 | }
345 | }
346 | if (emptyViewResId != defValue) {
347 | emptyView = inflater.inflate(emptyViewResId, this, false);
348 | if (emptyView instanceof ViewGroup) {
349 | saveViewsToClick((ViewGroup) emptyView, views);
350 | }
351 | }
352 | if (errorViewResId != defValue) {
353 | errorView = inflater.inflate(errorViewResId, this, false);
354 | if (errorView instanceof ViewGroup) {
355 | saveViewsToClick((ViewGroup) errorView, views);
356 | }
357 | }
358 | if (noNetworkViewResId != defValue) {
359 | noNetworkView = inflater.inflate(noNetworkViewResId, this, false);
360 | if (noNetworkView instanceof ViewGroup) {
361 | saveViewsToClick((ViewGroup) noNetworkView, views);
362 | }
363 | }
364 | if (loadingViewResId != defValue) {
365 | loadingView = inflater.inflate(loadingViewResId, this, false);
366 | if (loadingView instanceof ViewGroup) {
367 | saveViewsToClick((ViewGroup) loadingView, views);
368 | }
369 | }
370 | if (extendViewResId != defValue) {
371 | extendView = inflater.inflate(extendViewResId, this, false);
372 | if (extendView instanceof ViewGroup) {
373 | saveViewsToClick((ViewGroup) extendView, views);
374 | }
375 | }
376 | }
377 | }
378 |
--------------------------------------------------------------------------------