├── .gitignore
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── build.gradle
├── build.xml
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ ├── ic_error_network.png
│ │ └── ic_error_unkown.png
│ ├── drawable-mdpi
│ │ ├── ic_error_network.png
│ │ └── ic_error_unkown.png
│ ├── drawable-xhdpi
│ │ ├── ic_error_network.png
│ │ └── ic_error_unkown.png
│ ├── drawable
│ │ ├── btn_retry.xml
│ │ └── color_retry_button.xml
│ ├── layout
│ │ ├── msv__error_network.xml
│ │ ├── msv__error_unknown.xml
│ │ └── msv__loading.xml
│ ├── values-fr
│ │ └── msv__strings.xml
│ └── values
│ │ ├── msv__attrs.xml
│ │ ├── msv__strings.xml
│ │ └── msv__styles.xml
└── src
│ └── com
│ └── meetme
│ └── android
│ └── multistateview
│ └── MultiStateView.java
├── sample
├── build.gradle
├── proguard-rules.txt
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── meetme
│ │ └── android
│ │ └── multistateview
│ │ └── sample
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── main.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── screenshots
├── sample_content.png
├── sample_general_error.png
├── sample_loading.png
└── sample_network_error.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .gradle/
3 | *.iml
4 | local.properties
5 | .idea/
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MultiStateView
2 | Handles multiple display states for data-centric views
3 |
4 | - Content state; shows the inner content of the View (as defined in XML)
5 | - Loading state; shows a Loading state (as specified either via the `loadingLayout` attribute, or the default layout (`res/layout/msv__loading.xml`)
6 |
7 | The following shows examples (using default layouts) for **Loading**, **General Error**, **Network Error**, and the **Content** states (where we've made the "Hello World" the content) in respective order.
8 |
9 |  
10 |
11 |  
12 |
13 | ## Usage
14 |
15 | - For whatever `View` you want to switch out with `MultiStateView`, wrap the `View` in a `MultiStateView` node.
16 | - In code, get your reference to the child of `MultiStateView` via `MultiStateView#getContentView()` and cast that value as needed. There's no good reason to put an `android:id` on the child `View`.
17 |
18 | **Example**
19 |
20 | - Assuming you're starting with:
21 |
22 | ```xml
23 |
28 |
29 |
33 |
34 |
35 | ```
36 |
37 | - You should end up with something like:
38 |
39 | ```xml
40 |
45 |
46 |
50 |
51 |
54 |
55 |
56 |
57 |
58 | ```
59 |
60 | **Example Notes**
61 | 0. `android:id="@+id/list"` was moved from the `ListView` to the `MultiStateView`
62 | 0. It was also renamed to `list_container` to note that it now is the parent of the `ListView`
63 | 0. Any references in code should now use `MultiStateView#getContentView()` casted to `ListView` to reference the `ListView` child. There's no good reason to put an `id` on the `ListView`. See below.
64 |
65 | - In code,
66 |
67 | ```java
68 | ListView list = (ListView) findViewById(R.id.list);
69 | ```
70 |
71 | - Becomes
72 |
73 | ```java
74 | MultiStateView container = (MultiStateView) findViewById(R.id.list_container);
75 | ListView list = (ListView) container.getContentView();
76 | ```
77 |
78 | - To control the state of the `MultiStateView`, use the `MultiStateView#setState(State)` method.
79 |
80 | ```java
81 | container.setState(State.LOADING);
82 | ```
83 |
84 | - By default, "Loading" indication uses the loading layout provided in the library (`res/layout/msv__loading.xml`). To customize, you can add the custom attribute `msvLoadingLayout` to the `MultiStateView` in XML with a reference to the layout to inflate.
85 |
86 | ## Contributors
87 | - [Dallas Gutauckis](http://github.com/dallasgutauckis)
88 |
89 | ## License
90 |
91 | Apache 2.0
92 |
93 | Copyright 2013 MeetMe, Inc.
94 |
95 | Licensed under the Apache License, Version 2.0 (the "License");
96 | you may not use this file except in compliance with the License.
97 | You may obtain a copy of the License at
98 |
99 | http://www.apache.org/licenses/LICENSE-2.0
100 |
101 | Unless required by applicable law or agreed to in writing, software
102 | distributed under the License is distributed on an "AS IS" BASIS,
103 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
104 | See the License for the specific language governing permissions and
105 | limitations under the License.
106 |
107 | ## Contributing
108 |
109 | To make contributions, fork this repository, commit your changes, and submit a pull request.
110 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 | dependencies {
6 | classpath 'com.android.tools.build:gradle:1.3.1'
7 | }
8 | }
9 |
10 | task wrapper(type: Wrapper) {
11 | gradleVersion = '2.6'
12 | }
13 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 16 10:54:32 EDT 2015
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-2.6-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | gen
3 | *.apk
4 | *.keystore
5 | .hg/
6 | local.properties
7 | *.DS_Store
8 | *.BridgeSort
9 | out/
10 | tmp/
11 |
--------------------------------------------------------------------------------
/library/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | MultiStateView
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | buildToolsVersion "23.0.1"
5 | compileSdkVersion 23
6 | // Allow publishing both debug and release variants
7 | publishNonDefault true
8 |
9 | defaultConfig {
10 | targetSdkVersion 22
11 | minSdkVersion 3
12 | }
13 |
14 | sourceSets {
15 | main {
16 | manifest.srcFile 'AndroidManifest.xml'
17 | java.srcDirs = ['src']
18 | res.srcDirs = ['res']
19 | assets.srcDirs = ['assets']
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile 'com.android.support:support-annotations:+'
26 | }
27 |
--------------------------------------------------------------------------------
/library/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
56 |
57 |
69 |
70 |
71 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/library/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | android.library=true
14 | # Project target.
15 | target=android-17
16 |
--------------------------------------------------------------------------------
/library/res/drawable-hdpi/ic_error_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-hdpi/ic_error_network.png
--------------------------------------------------------------------------------
/library/res/drawable-hdpi/ic_error_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-hdpi/ic_error_unkown.png
--------------------------------------------------------------------------------
/library/res/drawable-mdpi/ic_error_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-mdpi/ic_error_network.png
--------------------------------------------------------------------------------
/library/res/drawable-mdpi/ic_error_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-mdpi/ic_error_unkown.png
--------------------------------------------------------------------------------
/library/res/drawable-xhdpi/ic_error_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-xhdpi/ic_error_network.png
--------------------------------------------------------------------------------
/library/res/drawable-xhdpi/ic_error_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/library/res/drawable-xhdpi/ic_error_unkown.png
--------------------------------------------------------------------------------
/library/res/drawable/btn_retry.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/library/res/drawable/color_retry_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/library/res/layout/msv__error_network.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
20 |
21 |
30 |
31 |
39 |
40 |
--------------------------------------------------------------------------------
/library/res/layout/msv__error_unknown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
20 |
21 |
30 |
31 |
39 |
40 |
--------------------------------------------------------------------------------
/library/res/layout/msv__loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/library/res/values-fr/msv__strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Erreur réseau
5 | Oops! Une erreur :/
6 | Tapez pour réessayer
7 |
8 |
--------------------------------------------------------------------------------
/library/res/values/msv__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 |
--------------------------------------------------------------------------------
/library/res/values/msv__strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Network Error
5 | Oops! We messed up.
6 | Tap to retry
7 |
8 |
--------------------------------------------------------------------------------
/library/res/values/msv__styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
--------------------------------------------------------------------------------
/library/src/com/meetme/android/multistateview/MultiStateView.java:
--------------------------------------------------------------------------------
1 | package com.meetme.android.multistateview;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.os.Build;
7 | import android.os.Parcel;
8 | import android.os.Parcelable;
9 | import android.support.annotation.NonNull;
10 | import android.support.annotation.Nullable;
11 | import android.util.AttributeSet;
12 | import android.util.Log;
13 | import android.util.SparseArray;
14 | import android.view.View;
15 | import android.widget.FrameLayout;
16 | import android.widget.TextView;
17 |
18 | import java.util.Locale;
19 |
20 | /**
21 | * A view designed to wrap a single child (the "content") and hide/show that content based on the current "state" (see {@link ContentState}) of this
22 | * View. Note that this layout can only have one direct descendant which is used as the "content" view
23 | */
24 | @SuppressWarnings("NullableProblems")
25 | public class MultiStateView extends FrameLayout {
26 | private static final String TAG = "MultiStateView";
27 | private final MultiStateViewData mViewState = new MultiStateViewData(ContentState.CONTENT);
28 |
29 | private View mContentView;
30 | private View mLoadingView;
31 | private View mNetworkErrorView;
32 | private View mGeneralErrorView;
33 | private OnClickListener mTapToRetryClickListener;
34 |
35 | public MultiStateView(Context context) {
36 | this(context, null);
37 | }
38 |
39 | public MultiStateView(Context context, AttributeSet attrs) {
40 | this(context, attrs, 0);
41 | }
42 |
43 | public MultiStateView(Context context, AttributeSet attrs, int defStyle) {
44 | super(context, attrs, defStyle);
45 | // Start out with a default handler/looper
46 | parseAttrs(context, attrs);
47 | }
48 |
49 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
50 | @Override
51 | public boolean canScrollVertically(int direction) {
52 | // This allows us to pass along whether our child is vertically scrollable or not (useful for SwipeRefreshLayout, for example)
53 | return super.canScrollVertically(direction)
54 | || (getState() == ContentState.CONTENT && mContentView != null && mContentView.canScrollVertically(direction));
55 | }
56 |
57 |
58 | /**
59 | * Parses the incoming attributes from XML inflation
60 | *
61 | * @param context
62 | * @param attrs
63 | */
64 | private void parseAttrs(Context context, AttributeSet attrs) {
65 | TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MultiStateView, 0, 0);
66 |
67 | try {
68 | setLoadingLayoutResourceId(a.getResourceId(R.styleable.MultiStateView_msvLoadingLayout, R.layout.msv__loading));
69 | setGeneralErrorLayoutResourceId(a.getResourceId(R.styleable.MultiStateView_msvErrorUnknownLayout, R.layout.msv__error_unknown));
70 | setNetworkErrorLayoutResourceId(a.getResourceId(R.styleable.MultiStateView_msvErrorNetworkLayout, R.layout.msv__error_network));
71 |
72 | String tmpString;
73 |
74 | tmpString = a.getString(R.styleable.MultiStateView_msvErrorTitleNetworkStringId);
75 |
76 | if (tmpString == null) {
77 | tmpString = context.getString(R.string.error_title_network);
78 | }
79 |
80 | setNetworkErrorTitleString(tmpString);
81 |
82 | tmpString = a.getString(R.styleable.MultiStateView_msvErrorTitleUnknownStringId);
83 |
84 | if (tmpString == null) {
85 | tmpString = context.getString(R.string.error_title_unknown);
86 | }
87 |
88 | setGeneralErrorTitleString(tmpString);
89 |
90 | tmpString = a.getString(R.styleable.MultiStateView_msvErrorTapToRetryStringId);
91 |
92 | if (tmpString == null) {
93 | tmpString = context.getString(R.string.tap_to_retry);
94 | }
95 |
96 | setTapToRetryString(tmpString);
97 |
98 | setState(a.getInt(R.styleable.MultiStateView_msvState, ContentState.CONTENT.nativeInt));
99 | } finally {
100 | a.recycle();
101 | }
102 | }
103 |
104 | private void setNetworkErrorLayoutResourceId(int resourceId) {
105 | mViewState.networkErrorLayoutResId = resourceId;
106 | }
107 |
108 | private void setGeneralErrorLayoutResourceId(int resourceId) {
109 | mViewState.generalErrorLayoutResId = resourceId;
110 | }
111 |
112 | private void setNetworkErrorTitleString(String string) {
113 | mViewState.networkErrorTitleString = string;
114 | }
115 |
116 | public String getNetworkErrorTitleString() {
117 | return mViewState.networkErrorTitleString;
118 | }
119 |
120 | private void setGeneralErrorTitleString(String string) {
121 | mViewState.generalErrorTitleString = string;
122 | }
123 |
124 | public void setCustomErrorString(String string) {
125 | mViewState.customErrorString = string;
126 |
127 | if (mGeneralErrorView != null) {
128 | TextView view = ((TextView) mGeneralErrorView.findViewById(R.id.error_title));
129 |
130 | if (view != null) {
131 | view.setText(string);
132 | }
133 | }
134 | }
135 |
136 | public String getGeneralErrorTitleString() {
137 | return mViewState.generalErrorTitleString;
138 | }
139 |
140 | private void setTapToRetryString(String string) {
141 | mViewState.tapToRetryString = string;
142 | }
143 |
144 | public String getTapToRetryString() {
145 | return mViewState.tapToRetryString;
146 | }
147 |
148 | public int getLoadingLayoutResourceId() {
149 | return mViewState.loadingLayoutResId;
150 | }
151 |
152 | public void setLoadingLayoutResourceId(int loadingLayout) {
153 | this.mViewState.loadingLayoutResId = loadingLayout;
154 | }
155 |
156 | /**
157 | * @return the {@link ContentState} the view is currently in
158 | */
159 | @NonNull
160 | public ContentState getState() {
161 | return mViewState.state != null ? mViewState.state : ContentState.CONTENT;
162 | }
163 |
164 | /**
165 | * Configures the view to be in the given state. This method is an internal method used for parsing the native integer value used in attributes
166 | * in XML.
167 | *
168 | * @param nativeInt
169 | * @see ContentState
170 | * @see #setState(ContentState)
171 | */
172 | private void setState(int nativeInt) {
173 | setState(ContentState.getState(nativeInt));
174 | }
175 |
176 | /**
177 | * Configures the view to be in the given state, hiding and showing internally maintained-views as needed
178 | *
179 | * @param state
180 | */
181 | public void setState(final ContentState state) {
182 | if (state == mViewState.state) {
183 | if (BuildConfig.DEBUG) Log.v(TAG, "Already in state " + mViewState.state);
184 | // No change
185 | return;
186 | }
187 |
188 | final View contentView = getContentView();
189 |
190 | if (contentView == null) {
191 | if (BuildConfig.DEBUG) Log.v(TAG, "Content not yet set, waiting...");
192 | return;
193 | }
194 |
195 | // Hide the previous state view
196 | final ContentState previousState = mViewState.state;
197 | View previousView = getStateView(previousState);
198 |
199 | if (previousView != null) {
200 | if (BuildConfig.DEBUG) Log.v(TAG, "Hiding previous state " + previousState);
201 | previousView.setVisibility(View.GONE);
202 | }
203 |
204 | // Show the new state view
205 | View newStateView = getStateView(state);
206 |
207 | if (newStateView != null) {
208 | if (state == ContentState.ERROR_GENERAL) {
209 | TextView view = ((TextView) newStateView.findViewById(R.id.error_title));
210 |
211 | if (view != null) {
212 | view.setText(getGeneralErrorTitleString());
213 | }
214 | }
215 |
216 | if (BuildConfig.DEBUG) Log.v(TAG, "Showing new state " + state);
217 | newStateView.setVisibility(View.VISIBLE);
218 | }
219 |
220 | mViewState.state = state;
221 |
222 | if (BuildConfig.DEBUG) {
223 | dumpState();
224 |
225 | // Now check if there are multiple visible children and emit a warning if so
226 | boolean hasVisible = false;
227 |
228 | for (int i = 0; i < getChildCount(); i++) {
229 | View v = getChildAt(i);
230 |
231 | if (v != null && v.getVisibility() != View.GONE) {
232 | // This should not happen
233 | if (hasVisible) Log.w(TAG, "MultiStateView has multiple visible children!");
234 | hasVisible = true;
235 | }
236 | }
237 | }
238 | }
239 |
240 | /** Dump the current state of the view. Requires {@link BuildConfig#DEBUG}. */
241 | public void dumpState() {
242 | if (!BuildConfig.DEBUG) return;
243 |
244 | Log.v(TAG, "/-- Start Dump State ---");
245 | Log.v(TAG, "| Current state = " + mViewState.state);
246 | Log.v(TAG, "| Children: " + getChildCount());
247 |
248 | for (int i = 0; i < getChildCount(); i++) {
249 | View child = getChildAt(i);
250 | ContentState state = null;
251 |
252 | if (child == mContentView) {
253 | state = ContentState.CONTENT;
254 | } else if (child == mGeneralErrorView) {
255 | state = ContentState.ERROR_GENERAL;
256 | } else if (child == mNetworkErrorView) {
257 | state = ContentState.ERROR_NETWORK;
258 | } else if (child == mLoadingView) {
259 | state = ContentState.LOADING;
260 | }
261 |
262 | Log.v(TAG, String.format(Locale.US, "| - #%d: %s (%s) -> %s",
263 | i, child, state, (child != null && child.getVisibility() == View.VISIBLE ? "visible" : "gone")));
264 | }
265 |
266 | Log.v(TAG, "\\-- End Dump State ---");
267 | }
268 |
269 | /**
270 | * Returns the given view corresponding to the specified {@link ContentState}
271 | *
272 | * @param state
273 | * @return
274 | */
275 | @Nullable
276 | public View getStateView(ContentState state) {
277 | if (state == null) return null;
278 |
279 | switch (state) {
280 | case ERROR_NETWORK:
281 | return getNetworkErrorView();
282 |
283 | case ERROR_GENERAL:
284 | return getGeneralErrorView();
285 |
286 | case LOADING:
287 | return getLoadingView();
288 |
289 | case CONTENT:
290 | return getContentView();
291 | }
292 |
293 | return null;
294 | }
295 |
296 | /**
297 | * Returns the view to be displayed for the case of a network error
298 | *
299 | * @return
300 | */
301 | @NonNull
302 | public View getNetworkErrorView() {
303 | if (mNetworkErrorView == null) {
304 | mNetworkErrorView = View.inflate(getContext(), mViewState.networkErrorLayoutResId, null);
305 |
306 | ((TextView) mNetworkErrorView.findViewById(R.id.error_title)).setText(getNetworkErrorTitleString());
307 | ((TextView) mNetworkErrorView.findViewById(R.id.tap_to_retry)).setText(getTapToRetryString());
308 |
309 | mNetworkErrorView.setOnClickListener(mTapToRetryClickListener);
310 |
311 | addView(mNetworkErrorView);
312 | }
313 |
314 | return mNetworkErrorView;
315 | }
316 |
317 | /**
318 | * Returns the view to be displayed for the case of an unknown error
319 | *
320 | * @return
321 | */
322 | @NonNull
323 | public View getGeneralErrorView() {
324 | if (mGeneralErrorView == null) {
325 | mGeneralErrorView = View.inflate(getContext(), mViewState.generalErrorLayoutResId, null);
326 |
327 | ((TextView) mGeneralErrorView.findViewById(R.id.error_title)).setText(getGeneralErrorTitleString());
328 | ((TextView) mGeneralErrorView.findViewById(R.id.tap_to_retry)).setText(getTapToRetryString());
329 |
330 | mGeneralErrorView.setOnClickListener(mTapToRetryClickListener);
331 |
332 | addView(mGeneralErrorView);
333 | }
334 |
335 | return mGeneralErrorView;
336 | }
337 |
338 | /**
339 | * Builds the loading view if not currently built, and returns the view
340 | */
341 | @NonNull
342 | public View getLoadingView() {
343 | if (mLoadingView == null) {
344 | mLoadingView = View.inflate(getContext(), mViewState.loadingLayoutResId, null);
345 |
346 | addView(mLoadingView);
347 | }
348 |
349 | return mLoadingView;
350 | }
351 |
352 | public void setOnTapToRetryClickListener(View.OnClickListener listener) {
353 | mTapToRetryClickListener = listener;
354 |
355 | if (mNetworkErrorView != null) {
356 | mNetworkErrorView.setOnClickListener(listener);
357 | }
358 |
359 | if (mGeneralErrorView != null) {
360 | mGeneralErrorView.setOnClickListener(listener);
361 | }
362 | }
363 |
364 | /**
365 | * Adds the given view as content, throwing an {@link IllegalStateException} if a content view is already set (this layout can only have one
366 | * direct descendant)
367 | *
368 | * @param contentView
369 | */
370 | private void addContentView(View contentView) {
371 | if (mContentView != null && mContentView != contentView) {
372 | throw new IllegalStateException("Can't add more than one view to MultiStateView");
373 | }
374 |
375 | setContentView(contentView);
376 | }
377 |
378 | /**
379 | * @return the view being used as "content" within the view (the developer-provided content -- doesn't ever give back internally maintained views
380 | * (like the loading layout))
381 | */
382 | @Nullable
383 | public View getContentView() {
384 | return mContentView;
385 | }
386 |
387 | /**
388 | * Sets the content view of this view. This does nothing to eradicate the inflated or any pre-existing descendant
389 | *
390 | * @param contentView
391 | */
392 | public void setContentView(View contentView) {
393 | mContentView = contentView;
394 |
395 | setState(mViewState.state);
396 | }
397 |
398 | private boolean isViewInternal(View view) {
399 | return view == mNetworkErrorView || view == mGeneralErrorView || view == mLoadingView;
400 | }
401 |
402 | @Override
403 | protected Parcelable onSaveInstanceState() {
404 | Parcelable state = super.onSaveInstanceState();
405 | SavedState myState = new SavedState(state);
406 | myState.state = mViewState;
407 | if (BuildConfig.DEBUG) Log.v(TAG, "Saved state: " + myState.state);
408 | return myState;
409 | }
410 |
411 | @Override
412 | protected void onRestoreInstanceState(Parcelable state) {
413 | if (state instanceof SavedState) {
414 | SavedState myState = (SavedState) state;
415 | setViewState(myState.state);
416 | state = myState.getSuperState();
417 | }
418 |
419 | super.onRestoreInstanceState(state);
420 | }
421 |
422 | private void setViewState(MultiStateViewData state) {
423 | if (BuildConfig.DEBUG) Log.v(TAG, "Restoring state: " + state);
424 | setState(state.state);
425 | setTapToRetryString(state.tapToRetryString);
426 | setGeneralErrorTitleString(state.generalErrorTitleString);
427 | setNetworkErrorTitleString(state.networkErrorTitleString);
428 | setGeneralErrorLayoutResourceId(state.generalErrorLayoutResId);
429 | setNetworkErrorLayoutResourceId(state.networkErrorLayoutResId);
430 | setLoadingLayoutResourceId(state.loadingLayoutResId);
431 | setCustomErrorString(state.customErrorString);
432 | }
433 |
434 | @Override
435 | public void addView(View child) {
436 | if (!isViewInternal(child)) {
437 | addContentView(child);
438 | }
439 |
440 | super.addView(child);
441 | }
442 |
443 | @Override
444 | public void addView(View child, int index) {
445 | if (!isViewInternal(child)) {
446 | addContentView(child);
447 | }
448 |
449 | super.addView(child, index);
450 | }
451 |
452 | @Override
453 | public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
454 | if (!isViewInternal(child)) {
455 | addContentView(child);
456 | }
457 |
458 | super.addView(child, index, params);
459 | }
460 |
461 | @Override
462 | public void addView(View child, int width, int height) {
463 | if (!isViewInternal(child)) {
464 | addContentView(child);
465 | }
466 |
467 | super.addView(child, width, height);
468 | }
469 |
470 | @Override
471 | public void addView(View child, android.view.ViewGroup.LayoutParams params) {
472 | if (!isViewInternal(child)) {
473 | addContentView(child);
474 | }
475 |
476 | super.addView(child, params);
477 | }
478 |
479 | /**
480 | * States of the MultiStateView
481 | */
482 | public static enum ContentState {
483 | /**
484 | * Used to indicate that content should be displayed to the user
485 | *
486 | * @see R.attr#msvState
487 | */
488 | CONTENT(0x00),
489 | /**
490 | * Used to indicate that the Loading indication should be displayed to the user
491 | *
492 | * @see R.attr#msvState
493 | */
494 | LOADING(0x01),
495 | /**
496 | * Used to indicate that the Network Error indication should be displayed to the user
497 | *
498 | * @see R.attr#msvState
499 | */
500 | ERROR_NETWORK(0x02),
501 | /**
502 | * Used to indicate that the Unknown Error indication should be displayed to the user
503 | *
504 | * @see R.attr#msvState
505 | */
506 | ERROR_GENERAL(0x03);
507 |
508 | public final int nativeInt;
509 | private static final SparseArray sStates = new SparseArray();
510 |
511 | static {
512 | for (ContentState scaleType : values()) {
513 | sStates.put(scaleType.nativeInt, scaleType);
514 | }
515 | }
516 |
517 | public static ContentState getState(int nativeInt) {
518 | if (nativeInt >= 0) {
519 | return sStates.get(nativeInt);
520 | }
521 |
522 | return null;
523 | }
524 |
525 | private ContentState(int nativeValue) {
526 | this.nativeInt = nativeValue;
527 | }
528 | }
529 |
530 | public static class SavedState extends View.BaseSavedState {
531 | MultiStateViewData state;
532 |
533 | public SavedState(Parcelable superState) {
534 | super(superState);
535 | }
536 |
537 | private SavedState(Parcel in) {
538 | super(in);
539 | state = in.readParcelable(MultiStateViewData.class.getClassLoader());
540 | }
541 |
542 | @Override
543 | public void writeToParcel(Parcel out, int flags) {
544 | super.writeToParcel(out, flags);
545 | out.writeParcelable(state, flags);
546 | }
547 |
548 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
549 | public SavedState createFromParcel(Parcel in) {
550 | return new SavedState(in);
551 | }
552 |
553 | public SavedState[] newArray(int size) {
554 | return new SavedState[size];
555 | }
556 | };
557 | }
558 |
559 | public static class MultiStateViewData implements Parcelable {
560 | public String customErrorString;
561 | public int loadingLayoutResId;
562 | public int generalErrorLayoutResId;
563 | public int networkErrorLayoutResId;
564 | public String networkErrorTitleString;
565 | public String generalErrorTitleString;
566 | public String tapToRetryString;
567 | public ContentState state;
568 |
569 | public MultiStateViewData(ContentState contentState) {
570 | state = contentState;
571 | }
572 |
573 | private MultiStateViewData(Parcel in) {
574 | customErrorString = in.readString();
575 | loadingLayoutResId = in.readInt();
576 | generalErrorLayoutResId = in.readInt();
577 | networkErrorLayoutResId = in.readInt();
578 | networkErrorTitleString = in.readString();
579 | generalErrorTitleString = in.readString();
580 | tapToRetryString = in.readString();
581 | state = ContentState.valueOf(in.readString());
582 | }
583 |
584 | public int describeContents() {
585 | return 0;
586 | }
587 |
588 | public void writeToParcel(Parcel dest, int flags) {
589 | dest.writeString(customErrorString);
590 | dest.writeInt(loadingLayoutResId);
591 | dest.writeInt(generalErrorLayoutResId);
592 | dest.writeInt(networkErrorLayoutResId);
593 | dest.writeString(networkErrorTitleString);
594 | dest.writeString(generalErrorTitleString);
595 | dest.writeString(tapToRetryString);
596 | dest.writeString(state.name());
597 | }
598 |
599 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
600 | public MultiStateViewData createFromParcel(Parcel in) {
601 | return new MultiStateViewData(in);
602 | }
603 |
604 | public MultiStateViewData[] newArray(int size) {
605 | return new MultiStateViewData[size];
606 | }
607 | };
608 |
609 | @Override
610 | public String toString() {
611 | if (BuildConfig.DEBUG) {
612 | return String.format(Locale.US, "MultiStateViewData{state=%s}", state);
613 | }
614 |
615 | return super.toString();
616 | }
617 | }
618 | }
619 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "19.1.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 8
9 | targetSdkVersion 19
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.android.support:appcompat-v7:20.+'
23 | compile project(':library')
24 | }
25 |
--------------------------------------------------------------------------------
/sample/proguard-rules.txt:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/dallas/android/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the ProGuard
5 | # include property in project.properties.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/meetme/android/multistateview/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.meetme.android.multistateview.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.ActionBarActivity;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 | import android.widget.TextView;
8 |
9 | import com.meetme.android.multistateview.MultiStateView;
10 |
11 |
12 | public class MainActivity extends ActionBarActivity {
13 | MultiStateView.ContentState mState;
14 |
15 | private MultiStateView mMultiStateView;
16 |
17 | private TextView mExampleOfHowToGetContentView;
18 |
19 | private TextView mStateView;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_main);
25 |
26 | mStateView = (TextView) findViewById(R.id.state);
27 | mMultiStateView = (MultiStateView) findViewById(R.id.content);
28 | }
29 |
30 | @Override
31 | protected void onPostCreate(Bundle savedInstanceState) {
32 | super.onPostCreate(savedInstanceState);
33 |
34 | mState = mMultiStateView.getState();
35 | mExampleOfHowToGetContentView = (TextView) mMultiStateView.getContentView();
36 | }
37 |
38 | @Override
39 | protected void onResume() {
40 | super.onResume();
41 | setStateText(mState);
42 | }
43 |
44 | private void setStateText(MultiStateView.ContentState state) {
45 | mStateView.setText(String.format("State: %s", state));
46 | }
47 |
48 |
49 | @Override
50 | public boolean onCreateOptionsMenu(Menu menu) {
51 | // Inflate the menu; this adds items to the action bar if it is present.
52 | getMenuInflater().inflate(R.menu.main, menu);
53 | return true;
54 | }
55 |
56 | @Override
57 | public boolean onOptionsItemSelected(MenuItem item) {
58 | // Handle action bar item clicks here. The action bar will
59 | // automatically handle clicks on the Home/Up button, so long
60 | // as you specify a parent activity in AndroidManifest.xml.
61 | int id = item.getItemId();
62 |
63 | if (id == R.id.action_rotate_state) {
64 | // This is only done because we're rotating state; you'd typically just call direct to mMultiStateView#setState(ContentState)
65 | MultiStateView.ContentState newState = MultiStateView.ContentState.values()[(mState.ordinal() + 1) % MultiStateView.ContentState.values().length];
66 |
67 | setState(newState);
68 | return true;
69 | }
70 |
71 | return super.onOptionsItemSelected(item);
72 | }
73 |
74 | public void setState(MultiStateView.ContentState state) {
75 | setStateText(state);
76 | mMultiStateView.setState(state);
77 | mState = state;
78 | }
79 | }
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/sample/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/sample/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/sample/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/sample/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
18 |
19 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/sample/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MultiStateView Sample
5 | Hello world!
6 | Next State
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/screenshots/sample_content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/screenshots/sample_content.png
--------------------------------------------------------------------------------
/screenshots/sample_general_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/screenshots/sample_general_error.png
--------------------------------------------------------------------------------
/screenshots/sample_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/screenshots/sample_loading.png
--------------------------------------------------------------------------------
/screenshots/sample_network_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MeetMe/Android-MultiStateView/02b621661bd38af7a8618933f88e27607bd79358/screenshots/sample_network_error.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':library', ':sample'
2 |
--------------------------------------------------------------------------------