├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── jntm.jpg
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── 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
│ │ │ ├── layout
│ │ │ │ ├── rlv_item.xml
│ │ │ │ ├── fragment_multi_state.xml
│ │ │ │ ├── activity_refresh_state.xml
│ │ │ │ ├── layout_content.xml
│ │ │ │ ├── multi_lottie_waiting.xml
│ │ │ │ ├── activity_mock_net.xml
│ │ │ │ ├── multi_lottie_other.xml
│ │ │ │ ├── activity_view_pager2.xml
│ │ │ │ ├── activity_multi_state.xml
│ │ │ │ ├── activity_multi_fragment.xml
│ │ │ │ ├── activity_lottie_ext.xml
│ │ │ │ ├── activity_smart_refresh_layout2.xml
│ │ │ │ ├── activity_smart_refresh_layout.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_api.xml
│ │ │ │ └── activity_multi_view.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── zy
│ │ │ │ └── demo
│ │ │ │ ├── state
│ │ │ │ ├── WithBindingState.kt
│ │ │ │ ├── LottieWaitingState.kt
│ │ │ │ └── LottieOtherState.kt
│ │ │ │ ├── MultiFragmentActivity.kt
│ │ │ │ ├── ViewPager2Activity.kt
│ │ │ │ ├── MultiStateActivity.kt
│ │ │ │ ├── base
│ │ │ │ ├── JavaFragment.java
│ │ │ │ ├── BaseActivity.kt
│ │ │ │ ├── MultiStateBinding.kt
│ │ │ │ ├── App.kt
│ │ │ │ ├── Test.java
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ └── Fun.kt
│ │ │ │ ├── MultiViewActivity.kt
│ │ │ │ ├── MultiStateFragment.kt
│ │ │ │ ├── RefreshStateActivity.kt
│ │ │ │ ├── ApiActivity.kt
│ │ │ │ ├── LottieExtActivity.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MockNetActivity.kt
│ │ │ │ ├── SmartRefreshLayoutActivity2.kt
│ │ │ │ └── SmartRefreshLayoutActivity.kt
│ │ ├── AndroidManifest.xml
│ │ └── assets
│ │ │ └── lottie_waiting.json
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zy
│ │ │ └── multistatepage
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zy
│ │ └── multistatepage
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── multistatepage
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ │ ├── values
│ │ │ │ └── colors.xml
│ │ │ ├── mipmap
│ │ │ │ ├── state_empty.webp
│ │ │ │ └── state_error.webp
│ │ │ └── layout
│ │ │ │ ├── mult_state_loading.xml
│ │ │ │ ├── mult_state_empty.xml
│ │ │ │ └── mult_state_error.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── zy
│ │ │ └── multistatepage
│ │ │ ├── OnNotifyListener.kt
│ │ │ ├── MultiStateExt.kt
│ │ │ ├── MultiState.kt
│ │ │ ├── state
│ │ │ ├── SuccessState.kt
│ │ │ ├── LoadingState.kt
│ │ │ ├── EmptyState.kt
│ │ │ └── ErrorState.kt
│ │ │ ├── MultiStateConfig.kt
│ │ │ ├── MultiStatePage.kt
│ │ │ └── MultiStateContainer.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── zy
│ │ │ └── multistatepage
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── zy
│ │ └── multistatepage
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
├── maven.gradle
└── build.gradle
├── jitpack.yml
├── imgs
├── api.gif
├── net.gif
├── QRCode.png
├── code.png
├── lottie.gif
├── view.gif
├── activity.gif
├── fragment.gif
├── background.png
├── state_call.gif
└── viewpager2.gif
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── gradlew
├── README.md
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/multistatepage/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk17
3 |
--------------------------------------------------------------------------------
/imgs/api.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/api.gif
--------------------------------------------------------------------------------
/imgs/net.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/net.gif
--------------------------------------------------------------------------------
/imgs/QRCode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/QRCode.png
--------------------------------------------------------------------------------
/imgs/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/code.png
--------------------------------------------------------------------------------
/imgs/lottie.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/lottie.gif
--------------------------------------------------------------------------------
/imgs/view.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/view.gif
--------------------------------------------------------------------------------
/imgs/activity.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/activity.gif
--------------------------------------------------------------------------------
/imgs/fragment.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/fragment.gif
--------------------------------------------------------------------------------
/imgs/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/background.png
--------------------------------------------------------------------------------
/imgs/state_call.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/state_call.gif
--------------------------------------------------------------------------------
/imgs/viewpager2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/imgs/viewpager2.gif
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MultiStatePage
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/multistatepage/consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # 保持继承了MultiState的类不被混淆
2 | -keep public class * extends com.zy.multistatepage.MultiState { *; }
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/jntm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xxhdpi/jntm.jpg
--------------------------------------------------------------------------------
/multistatepage/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/multistatepage/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #fff
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/multistatepage/src/main/res/mipmap/state_empty.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/multistatepage/src/main/res/mipmap/state_empty.webp
--------------------------------------------------------------------------------
/multistatepage/src/main/res/mipmap/state_error.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/multistatepage/src/main/res/mipmap/state_error.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhao-Yan-Yan/MultiStatePage/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/OnNotifyListener.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | /**
4 | * @author: yanz
5 | */
6 | fun interface OnNotifyListener {
7 | fun onNotify(multiState: T)
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 29 20:12:38 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/MultiStateExt.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import android.app.Activity
4 | import android.view.View
5 |
6 | /**
7 | * @author: yanz
8 | */
9 | fun View.bindMultiState() = MultiStatePage.bindMultiState(this)
10 |
11 | fun Activity.bindMultiState() = MultiStatePage.bindMultiState(this)
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/state/WithBindingState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.state
2 |
3 | import com.zy.demo.base.MultiStateBinding
4 | import com.zy.demo.databinding.MultiLottieOtherBinding
5 |
6 | /**
7 | * @author: yanz
8 | */
9 | class WithBindingState : MultiStateBinding() {
10 |
11 | override fun onMultiStateViewCreate() {
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "MultiStatePage"
16 | include ':multistatepage'
17 | include ':app'
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MultiFragmentActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import com.zy.demo.base.BaseActivity
4 | import com.zy.demo.databinding.ActivityMultiFragmentBinding
5 |
6 | class MultiFragmentActivity : BaseActivity() {
7 |
8 | override fun initPage() {
9 | supportFragmentManager.beginTransaction()
10 | .replace(R.id.fl, MultiStateFragment.newInstance())
11 | .commit()
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/rlv_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zy/multistatepage/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_multi_state.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/multistatepage/src/test/java/com/zy/multistatepage/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_refresh_state.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/multi_lottie_waiting.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_mock_net.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/multi_lottie_other.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/multistatepage/src/main/res/layout/mult_state_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_pager2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/MultiState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 |
7 | /**
8 | * @author: yanz
9 | */
10 | abstract class MultiState {
11 |
12 | /**
13 | * 创建stateView
14 | */
15 | abstract fun onCreateView(
16 | context: Context,
17 | inflater: LayoutInflater,
18 | container: MultiStateContainer,
19 | ): View
20 |
21 | /**
22 | * stateView创建完成
23 | */
24 | abstract fun onViewCreated(view: View)
25 |
26 |
27 | open fun onHiddenChanged(hide: Boolean) {
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/ViewPager2Activity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.viewpager2.adapter.FragmentStateAdapter
5 | import com.zy.demo.base.BaseActivity
6 | import com.zy.demo.databinding.ActivityViewPager2Binding
7 |
8 | class ViewPager2Activity : BaseActivity() {
9 |
10 | override fun initPage() {
11 | viewBinding.viewpager2.offscreenPageLimit = 5
12 | viewBinding.viewpager2.adapter = object : FragmentStateAdapter(this) {
13 | override fun getItemCount(): Int = 5
14 | override fun createFragment(position: Int): Fragment = MultiStateFragment.newInstance()
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/state/SuccessState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage.state
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import com.zy.multistatepage.MultiState
7 | import com.zy.multistatepage.MultiStateContainer
8 | import com.zy.multistatepage.R
9 |
10 | /**
11 | * @author: yanz
12 | */
13 | class SuccessState : MultiState() {
14 | override fun onCreateView(
15 | context: Context,
16 | inflater: LayoutInflater,
17 | container: MultiStateContainer
18 | ): View {
19 | return View(context)
20 | }
21 |
22 | override fun onViewCreated(view: View) = Unit
23 |
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/state/LottieWaitingState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.state
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import com.zy.demo.R
7 | import com.zy.multistatepage.MultiState
8 | import com.zy.multistatepage.MultiStateContainer
9 |
10 | /**
11 | * @author: yanz
12 | */
13 | class LottieWaitingState : MultiState() {
14 | override fun onCreateView(
15 | context: Context,
16 | inflater: LayoutInflater,
17 | container: MultiStateContainer,
18 | ): View {
19 | return inflater.inflate(R.layout.multi_lottie_waiting, container, false)
20 | }
21 |
22 | override fun onViewCreated(view: View) {
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_multi_state.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_multi_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MultiStateActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import com.zy.demo.base.BaseActivity
4 | import com.zy.demo.base.mockError
5 | import com.zy.demo.base.showEmpty
6 | import com.zy.demo.databinding.ActivityMultiStateBinding
7 | import com.zy.multistatepage.bindMultiState
8 | import com.zy.multistatepage.state.EmptyState
9 | import kotlinx.coroutines.MainScope
10 | import kotlinx.coroutines.delay
11 | import kotlinx.coroutines.launch
12 |
13 | class MultiStateActivity : BaseActivity() {
14 |
15 | override fun initPage() {
16 | val multiStateActivityRoot = bindMultiState().apply { showEmpty() }
17 | MainScope().launch {
18 | delay(3000)
19 | mockError(multiStateActivityRoot)
20 | }
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zy/multistatepage/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zy.multistatepage", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/state/LottieOtherState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.state
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import com.zy.demo.R
7 | import com.zy.multistatepage.MultiState
8 | import com.zy.multistatepage.MultiStateContainer
9 |
10 | /**
11 | * @author: yanz
12 | */
13 | class LottieOtherState : MultiState() {
14 |
15 | var retry: (() -> Unit)? = null
16 |
17 | override fun onCreateView(
18 | context: Context,
19 | inflater: LayoutInflater,
20 | container: MultiStateContainer
21 | ): View {
22 | return inflater.inflate(R.layout.multi_lottie_other, container, false)
23 | }
24 |
25 | override fun onViewCreated(view: View) {
26 | view.findViewById(R.id.view).setOnClickListener { retry?.invoke() }
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/multistatepage/src/androidTest/java/com/zy/multistatepage/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zy.multistatepage.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/multistatepage/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
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_lottie_ext.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/JavaFragment.java:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.fragment.app.Fragment;
11 |
12 | import com.zy.demo.R;
13 | import com.zy.multistatepage.MultiStateContainer;
14 | import com.zy.multistatepage.MultiStatePage;
15 |
16 | /**
17 | * @author: yanz
18 | */
19 | class JavaFragment extends Fragment {
20 | @Nullable
21 | @Override
22 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
23 | View root = inflater.inflate(R.layout.activity_main, container, false);
24 | MultiStateContainer multiStateContainer = MultiStatePage.bindMultiState(root);
25 | return multiStateContainer;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/multistatepage/maven.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | afterEvaluate {
3 | publishing {
4 | publications {
5 | // Creates a Maven publication called "release".
6 | release(MavenPublication) {
7 | // Applies the component for the release build variant.
8 | from components.release
9 | // You can then customize attributes of the publication as shown below.
10 | groupId = 'com.github.Zhao-Yan-Yan'
11 | artifactId = 'MultiStatePage'
12 | version = '2.0.6'
13 | }
14 | // Creates a Maven publication called “debug”.
15 | debug(MavenPublication) {
16 | // Applies the component for the debug build variant.
17 | from components.debug
18 | groupId = 'com.github.Zhao-Yan-Yan'
19 | artifactId = 'MultiStatePage'
20 | version = '2.0.6'
21 | }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MultiViewActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import com.zy.demo.base.BaseActivity
4 | import com.zy.demo.base.mockError
5 | import com.zy.demo.base.mockSuccess
6 | import com.zy.demo.base.showLoading
7 | import com.zy.demo.databinding.ActivityMultiViewBinding
8 | import com.zy.multistatepage.bindMultiState
9 |
10 | class MultiViewActivity : BaseActivity() {
11 | override fun initPage() {
12 |
13 | mockError(viewBinding.mscText)
14 |
15 | val multiState1 = viewBinding.fl1.bindMultiState()
16 | mockError(multiState1)
17 |
18 | val multiState2 = viewBinding.fl2.bindMultiState()
19 | mockError(multiState2)
20 |
21 | val multiState3 = viewBinding.fl3.bindMultiState()
22 | mockError(multiState3)
23 |
24 | val multiState4 = viewBinding.fl4.bindMultiState()
25 | mockError(multiState4)
26 |
27 | val multiState5 = viewBinding.fl5.bindMultiState()
28 | mockError(multiState5)
29 | }
30 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/res/layout/mult_state_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.viewbinding.ViewBinding
7 | import java.lang.reflect.ParameterizedType
8 |
9 | /**
10 | * @author: yanz
11 | */
12 | abstract class BaseActivity : AppCompatActivity() {
13 | lateinit var viewBinding: VB
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | viewBinding = getViewBindingForActivity(layoutInflater)
17 | setContentView(viewBinding.root)
18 | initPage()
19 | }
20 |
21 | abstract fun initPage()
22 |
23 | @Suppress("UNCHECKED_CAST")
24 | private fun getViewBindingForActivity(layoutInflater: LayoutInflater): VB {
25 | val type = javaClass.genericSuperclass as ParameterizedType
26 | val aClass = type.actualTypeArguments[0] as Class<*>
27 | val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
28 | return method.invoke(null, layoutInflater) as VB
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MultiStateFragment.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import com.zy.demo.base.BaseFragment
8 | import com.zy.demo.base.mockError
9 | import com.zy.demo.databinding.FragmentMultiStateBinding
10 | import com.zy.multistatepage.MultiStateContainer
11 | import com.zy.multistatepage.bindMultiState
12 | import com.zy.multistatepage.state.LoadingState
13 |
14 | class MultiStateFragment : BaseFragment() {
15 | private lateinit var multiState: MultiStateContainer
16 | override fun onCreateView(
17 | inflater: LayoutInflater,
18 | container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View {
21 | val root = super.onCreateView(inflater, container, savedInstanceState)
22 | multiState = root!!.bindMultiState()
23 | multiState.show()
24 | return multiState
25 | }
26 |
27 | override fun initPage() {
28 | mockError(multiState)
29 | }
30 |
31 | companion object {
32 | fun newInstance(): MultiStateFragment {
33 | return MultiStateFragment()
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/multistatepage/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 | apply from: 'maven.gradle'
6 |
7 | android {
8 | namespace 'com.zy.multistatepage'
9 | compileSdk 33
10 | defaultConfig {
11 | minSdk 21
12 | targetSdk 33
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | consumerProguardFiles "consumer-rules.pro"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | compileOptions {
24 | sourceCompatibility JavaVersion.VERSION_1_8
25 | targetCompatibility JavaVersion.VERSION_1_8
26 | }
27 | kotlinOptions {
28 | jvmTarget = '1.8'
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation 'androidx.core:core-ktx:1.10.1'
34 | implementation 'androidx.appcompat:appcompat:1.6.1'
35 |
36 | testImplementation 'junit:junit:4.13.2'
37 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
39 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/res/layout/mult_state_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
25 |
26 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/RefreshStateActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import androidx.lifecycle.lifecycleScope
4 | import com.zy.demo.base.BaseActivity
5 | import com.zy.demo.databinding.ActivityRefreshStateBinding
6 | import com.zy.multistatepage.bindMultiState
7 | import com.zy.multistatepage.state.ErrorState
8 | import com.zy.multistatepage.state.LoadingState
9 | import kotlinx.coroutines.delay
10 | import kotlinx.coroutines.launch
11 |
12 | class RefreshStateActivity : BaseActivity() {
13 | private var count = 0
14 | override fun initPage() {
15 | val multiStateActivityRoot = bindMultiState()
16 |
17 | lifecycleScope.launch {
18 | multiStateActivityRoot.show()
19 | delay(2000)
20 | val errorState = ErrorState()
21 | errorState.retry {
22 | lifecycleScope.launch {
23 | multiStateActivityRoot.show()
24 | delay(2000)
25 | multiStateActivityRoot.show(errorState) {
26 | it.setErrorMsg("鸡你太美 ${++count}")
27 | it.setErrorIcon(R.mipmap.jntm)
28 | }
29 | }
30 | }
31 | multiStateActivityRoot.show(errorState)
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/MultiStateBinding.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.viewbinding.ViewBinding
8 | import com.zy.multistatepage.MultiState
9 | import com.zy.multistatepage.MultiStateContainer
10 | import java.lang.reflect.ParameterizedType
11 |
12 | /**
13 | * @author: yanz
14 | */
15 | abstract class MultiStateBinding : MultiState() {
16 |
17 | lateinit var viewBinding: VB
18 |
19 | override fun onCreateView(
20 | context: Context,
21 | inflater: LayoutInflater,
22 | container: MultiStateContainer
23 | ): View {
24 | val parameterizedType = javaClass.genericSuperclass as ParameterizedType
25 | val clazz = parameterizedType.actualTypeArguments[0] as Class<*>
26 | val inflate = clazz.getDeclaredMethod(
27 | "inflate",
28 | LayoutInflater::class.java,
29 | ViewGroup::class.java,
30 | Boolean::class.java
31 | )
32 | viewBinding = inflate.invoke(null, inflate, container, false) as VB
33 | return viewBinding.root
34 | }
35 |
36 | override fun onViewCreated(view: View) {
37 | onMultiStateViewCreate()
38 | }
39 |
40 | abstract fun onMultiStateViewCreate()
41 | }
--------------------------------------------------------------------------------
/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=-Xmx2048m
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 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
23 | android.nonTransitiveRClass=false
24 | android.defaults.buildfeatures.buildconfig=true
25 | android.nonFinalResIds=false
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/App.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base
2 |
3 | import android.app.Application
4 | import com.scwang.smart.refresh.footer.ClassicsFooter
5 | import com.scwang.smart.refresh.header.ClassicsHeader
6 | import com.scwang.smart.refresh.layout.SmartRefreshLayout
7 | import com.zy.demo.R
8 | import com.zy.multistatepage.MultiStateConfig
9 | import com.zy.multistatepage.MultiStatePage
10 |
11 | /**
12 | * @author: yanz
13 | */
14 | class App : Application() {
15 | override fun onCreate() {
16 | super.onCreate()
17 | val config = MultiStateConfig.Builder()
18 | .alphaDuration(300)
19 | .errorIcon(R.mipmap.state_error)
20 | .emptyIcon(R.mipmap.state_empty)
21 | .emptyMsg("emptyMsg")
22 | .loadingMsg("loadingMsg")
23 | .errorMsg("errorMsg")
24 | .build()
25 |
26 | MultiStatePage.config(config)
27 | }
28 |
29 | companion object {
30 | init {
31 | //设置全局的Header构建器
32 | SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout ->
33 | ClassicsHeader(context)
34 | }
35 | //设置全局的Footer构建器
36 | SmartRefreshLayout.setDefaultRefreshFooterCreator { context, layout ->
37 | ClassicsFooter(context).apply {
38 | setDrawableSize(20f)
39 | }
40 | }
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/state/LoadingState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage.state
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.widget.TextView
8 | import com.zy.multistatepage.MultiState
9 | import com.zy.multistatepage.MultiStateContainer
10 | import com.zy.multistatepage.MultiStatePage
11 | import com.zy.multistatepage.R
12 |
13 | /**
14 | * @author: yanz
15 | */
16 | class LoadingState : MultiState() {
17 | private lateinit var tvLoadingMsg: TextView
18 | override fun onCreateView(
19 | context: Context,
20 | inflater: LayoutInflater,
21 | container: MultiStateContainer,
22 | ): View {
23 | return inflater.inflate(R.layout.mult_state_loading, container, false)
24 | }
25 |
26 | override fun onViewCreated(view: View) {
27 | tvLoadingMsg = view.findViewById(R.id.tv_loading_msg)
28 | setLoadingMsg(MultiStatePage.config.loadingMsg)
29 | }
30 |
31 | override fun onHiddenChanged(hide: Boolean) {
32 | super.onHiddenChanged(hide)
33 | if (hide) {
34 | Log.e("TAG", "LoadingState: 隐藏了")
35 | } else {
36 | Log.e("TAG", "LoadingState: 显示了")
37 | }
38 | }
39 |
40 | fun setLoadingMsg(loadingMsg: String) {
41 | tvLoadingMsg.text = loadingMsg
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/ApiActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import android.widget.Toast
4 | import com.zy.demo.databinding.ActivityApiBinding
5 | import com.zy.demo.state.LottieWaitingState
6 | import com.zy.demo.base.BaseActivity
7 | import com.zy.demo.state.LottieOtherState
8 | import com.zy.multistatepage.bindMultiState
9 | import com.zy.multistatepage.state.*
10 |
11 | class ApiActivity : BaseActivity() {
12 | override fun initPage() {
13 |
14 | val multiState = viewBinding.fl.bindMultiState()
15 |
16 | viewBinding.btnLoading.setOnClickListener {
17 | multiState.show()
18 | }
19 |
20 | viewBinding.btnSuccess.setOnClickListener {
21 | multiState.show()
22 | }
23 |
24 | viewBinding.btnEmpty.setOnClickListener {
25 | multiState.show()
26 | }
27 |
28 | viewBinding.btnError.setOnClickListener {
29 | multiState.show()
30 | }
31 |
32 | viewBinding.btnLottie1.setOnClickListener {
33 | multiState.show()
34 | }
35 |
36 | val lottieOtherState = LottieOtherState()
37 | viewBinding.btnLottie2.setOnClickListener {
38 | lottieOtherState.retry = {
39 | Toast.makeText(this, "retry...", Toast.LENGTH_SHORT).show()
40 | }
41 | multiState.show(lottieOtherState)
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/state/EmptyState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage.state
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import androidx.annotation.DrawableRes
9 | import com.zy.multistatepage.MultiState
10 | import com.zy.multistatepage.MultiStateContainer
11 | import com.zy.multistatepage.MultiStatePage
12 | import com.zy.multistatepage.R
13 |
14 | /**
15 | * @author: yanz
16 | */
17 | class EmptyState : MultiState() {
18 |
19 | private lateinit var tvEmptyMsg: TextView
20 | private lateinit var imgEmpty: ImageView
21 |
22 | override fun onCreateView(
23 | context: Context,
24 | inflater: LayoutInflater,
25 | container: MultiStateContainer
26 | ): View {
27 | return inflater.inflate(R.layout.mult_state_empty, container, false)
28 | }
29 |
30 | override fun onViewCreated(view: View) {
31 | tvEmptyMsg = view.findViewById(R.id.tv_empty_msg)
32 | imgEmpty = view.findViewById(R.id.img_empty)
33 |
34 | setEmptyMsg(MultiStatePage.config.emptyMsg)
35 | setEmptyIcon(MultiStatePage.config.emptyIcon)
36 | }
37 |
38 | fun setEmptyMsg(emptyMsg: String) {
39 | tvEmptyMsg.text = emptyMsg
40 | }
41 |
42 | fun setEmptyIcon(@DrawableRes emptyIcon: Int) {
43 | imgEmpty.setImageResource(emptyIcon)
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/Test.java:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Toast;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | import com.zy.multistatepage.MultiStateContainer;
11 | import com.zy.multistatepage.MultiStatePage;
12 | import com.zy.multistatepage.OnNotifyListener;
13 | import com.zy.demo.state.LottieOtherState;
14 |
15 | /**
16 | * @author: yanz
17 | */
18 | class Test extends Activity {
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 |
23 | super.onCreate(savedInstanceState);
24 |
25 | View view = new View(this);
26 |
27 | MultiStatePage.bindMultiState(this);
28 | MultiStatePage.bindMultiState(view);
29 |
30 | MultiStateContainer multiStateContainer = MultiStatePage.bindMultiState(view);
31 |
32 | multiStateContainer.show(LottieOtherState.class);
33 |
34 | multiStateContainer.show(LottieOtherState.class, true, new OnNotifyListener() {
35 | @Override
36 | public void onNotify(LottieOtherState multiState) {
37 | System.out.println("");
38 | }
39 | });
40 |
41 | LottieOtherState lottieOtherState = new LottieOtherState();
42 | lottieOtherState.setRetry(() -> {
43 | Toast.makeText(this, "", Toast.LENGTH_SHORT);
44 | return null;
45 | });
46 | multiStateContainer.show(lottieOtherState);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/LottieExtActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import com.zy.demo.databinding.ActivityLottieExtBinding
4 | import com.zy.multistatepage.MultiStateContainer
5 | import com.zy.multistatepage.MultiStatePage
6 | import com.zy.demo.base.BaseActivity
7 | import com.zy.multistatepage.state.ErrorState
8 | import com.zy.demo.state.LottieWaitingState
9 | import com.zy.multistatepage.state.SuccessState
10 | import kotlinx.coroutines.MainScope
11 | import kotlinx.coroutines.delay
12 | import kotlinx.coroutines.launch
13 |
14 | class LottieExtActivity : BaseActivity() {
15 | override fun initPage() {
16 | MultiStatePage.bindMultiState(viewBinding.fl)
17 | val multiState = MultiStatePage.bindMultiState(viewBinding.fl)
18 | mockError(multiState)
19 | }
20 |
21 |
22 | private fun mockError(multiStateContainer: MultiStateContainer) {
23 | MainScope().launch {
24 | multiStateContainer.show()
25 | val delayTime = (10..30).random() * 100.toLong()
26 | delay(delayTime)
27 | multiStateContainer.show {
28 | it.retry { mockSuccess(multiStateContainer) }
29 | }
30 | }
31 | }
32 |
33 | private fun mockSuccess(multiStateContainer: MultiStateContainer) {
34 | MainScope().launch {
35 | multiStateContainer.show()
36 | val delayTime = (10..30).random() * 100.toLong()
37 | delay(delayTime)
38 | multiStateContainer.show()
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import com.zy.demo.databinding.ActivityMainBinding
4 | import com.zy.demo.base.BaseActivity
5 | import com.zy.demo.base.startActivity
6 |
7 | class MainActivity : BaseActivity() {
8 |
9 | override fun initPage() {
10 | //Activity 中使用
11 | viewBinding.btnActivity.setOnClickListener {
12 | startActivity()
13 | }
14 | //Fragment中使用
15 | viewBinding.btnFragment.setOnClickListener {
16 | startActivity()
17 | }
18 | //同时处理多个View
19 | viewBinding.btnView.setOnClickListener {
20 | startActivity()
21 | }
22 | //ViewPager2中使用
23 | viewBinding.btnViewpager2.setOnClickListener {
24 | startActivity()
25 | }
26 | //State 拓展
27 | viewBinding.btnLottie.setOnClickListener {
28 | startActivity()
29 | }
30 | viewBinding.btnApi.setOnClickListener {
31 | startActivity()
32 | }
33 | //State 刷新
34 | viewBinding.btnRefresh.setOnClickListener {
35 | startActivity()
36 | }
37 | //结合网络请求
38 | viewBinding.btnNet.setOnClickListener {
39 | startActivity()
40 | }
41 |
42 | viewBinding.smartRefreshLayout.setOnClickListener {
43 | startActivity()
44 | }
45 |
46 | viewBinding.smartRefreshLayout2.setOnClickListener {
47 | startActivity()
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.viewbinding.ViewBinding
9 | import java.lang.reflect.ParameterizedType
10 |
11 | /**
12 | * @author: yanz
13 | */
14 | abstract class BaseFragment : Fragment() {
15 | lateinit var viewBinding: VB
16 | private var isLazyLoad = true
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View? {
22 | viewBinding = getViewBindingForFragment(inflater, container)
23 | return viewBinding.root
24 | }
25 |
26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
27 | super.onViewCreated(view, savedInstanceState)
28 | }
29 |
30 | override fun onResume() {
31 | super.onResume()
32 | if (isLazyLoad) {
33 | initPage()
34 | isLazyLoad = false
35 | }
36 | }
37 |
38 | abstract fun initPage()
39 |
40 | @Suppress("UNCHECKED_CAST")
41 | fun getViewBindingForFragment(layoutInflater: LayoutInflater, container: ViewGroup?): VB {
42 | val type = javaClass.genericSuperclass as ParameterizedType
43 | val aClass = type.actualTypeArguments[0] as Class<*>
44 | val method = aClass.getDeclaredMethod(
45 | "inflate",
46 | LayoutInflater::class.java,
47 | ViewGroup::class.java,
48 | Boolean::class.java
49 | )
50 | return method.invoke(null, layoutInflater, container, false) as VB
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/MockNetActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import androidx.lifecycle.lifecycleScope
4 | import com.zy.demo.databinding.ActivityMockNetBinding
5 | import com.zy.multistatepage.MultiStateContainer
6 | import com.zy.demo.base.BaseActivity
7 | import com.zy.multistatepage.bindMultiState
8 | import com.zy.multistatepage.state.ErrorState
9 | import com.zy.demo.state.LottieWaitingState
10 | import com.zy.multistatepage.state.SuccessState
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import kotlinx.coroutines.withContext
14 | import okhttp3.OkHttpClient
15 | import okhttp3.Request
16 | import java.lang.Exception
17 |
18 | class MockNetActivity : BaseActivity() {
19 | private lateinit var multiState: MultiStateContainer
20 | override fun initPage() {
21 | multiState = viewBinding.content.bindMultiState()
22 | loadData()
23 | }
24 |
25 | private fun loadData() {
26 | lifecycleScope.launch {
27 | try {
28 | multiState.show()
29 | val request =
30 | Request.Builder().url("https://wanandroid.com/wxarticle/chapters/json").build()
31 | val okHttpClient = OkHttpClient.Builder().build()
32 | val call = okHttpClient.newCall(request)
33 | val response = withContext(Dispatchers.IO) { call.execute().body()?.string() }
34 | multiState.show()
35 | viewBinding.content.text = response
36 | } catch (e: Exception) {
37 | e.printStackTrace()
38 | multiState.show {
39 | it.retry { loadData() }
40 | //可以直接设置 state 中的变量 刷新state
41 | it.setErrorMsg(e.message.toString())
42 | }
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | .DS_Store
6 | /build
7 | captures
8 | .externalNativeBuild
9 | .cxx
10 | ### Android template
11 | # Built application files
12 | *.apk
13 | *.aar
14 | *.ap_
15 | *.aab
16 |
17 | # Files for the ART/Dalvik VM
18 | *.dex
19 |
20 | # Java class files
21 | *.class
22 |
23 | # Generated files
24 | bin/
25 | gen/
26 | out/
27 | # Uncomment the following line in case you need and you don't have the release build type files in your app
28 | # release/
29 |
30 | # Gradle files
31 | .gradle/
32 | build/
33 |
34 | # Local configuration file (sdk path, etc)
35 | local.properties
36 |
37 | # Proguard folder generated by Eclipse
38 | proguard/
39 |
40 | # Log Files
41 | *.log
42 |
43 | # Android Studio Navigation editor temp files
44 | .navigation/
45 |
46 | # Android Studio captures folder
47 | captures/
48 |
49 | # IntelliJ
50 | *.iml
51 | .idea/workspace.xml
52 | .idea/tasks.xml
53 | .idea/gradle.xml
54 | .idea/assetWizardSettings.xml
55 | .idea/dictionaries
56 | .idea/libraries
57 | # Android Studio 3 in .gitignore file.
58 | .idea/caches
59 | .idea/modules.xml
60 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
61 | .idea/navEditor.xml
62 |
63 | # Keystore files
64 | # Uncomment the following lines if you do not want to check your keystore files in.
65 | #*.jks
66 | #*.keystore
67 |
68 | # External native build folder generated in Android Studio 2.2 and later
69 | .externalNativeBuild
70 | .cxx/
71 |
72 | # Google Services (e.g. APIs or Firebase)
73 | # google-services.json
74 |
75 | # Freeline
76 | freeline.py
77 | freeline/
78 | freeline_project_description.json
79 |
80 | # fastlane
81 | fastlane/report.xml
82 | fastlane/Preview.html
83 | fastlane/screenshots
84 | fastlane/test_output
85 | fastlane/readme.md
86 |
87 | # Version control
88 | vcs.xml
89 |
90 | # lint
91 | lint/intermediates/
92 | lint/generated/
93 | lint/outputs/
94 | lint/tmp/
95 | # lint/reports/
96 |
97 |
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/state/ErrorState.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage.state
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.widget.ImageView
8 | import android.widget.TextView
9 | import androidx.annotation.DrawableRes
10 | import com.zy.multistatepage.MultiState
11 | import com.zy.multistatepage.MultiStateContainer
12 | import com.zy.multistatepage.MultiStatePage
13 | import com.zy.multistatepage.R
14 |
15 | /**
16 | * @author: yanz
17 | */
18 | class ErrorState : MultiState() {
19 |
20 | private lateinit var tvErrorMsg: TextView
21 | private lateinit var imgError: ImageView
22 | private lateinit var tvRetry: TextView
23 |
24 | private var retry: OnRetryClickListener? = null
25 |
26 | override fun onCreateView(
27 | context: Context,
28 | inflater: LayoutInflater,
29 | container: MultiStateContainer
30 | ): View {
31 | return inflater.inflate(R.layout.mult_state_error, container, false)
32 | }
33 |
34 | override fun onViewCreated(view: View) {
35 | tvErrorMsg = view.findViewById(R.id.tv_error_msg)
36 | imgError = view.findViewById(R.id.img_error)
37 | tvRetry = view.findViewById(R.id.tv_retry)
38 |
39 | setErrorMsg(MultiStatePage.config.errorMsg)
40 | setErrorIcon(MultiStatePage.config.errorIcon)
41 |
42 | tvRetry.setOnClickListener { retry?.retry() }
43 | }
44 |
45 | fun setErrorMsg(errorMsg: String) {
46 | tvErrorMsg.text = errorMsg
47 | }
48 |
49 | fun setErrorIcon(@DrawableRes errorIcon: Int) {
50 | imgError.setImageResource(errorIcon)
51 | }
52 |
53 | fun retry(retry: OnRetryClickListener) {
54 | this.retry = retry
55 | }
56 |
57 | fun interface OnRetryClickListener {
58 | fun retry()
59 | }
60 | override fun onHiddenChanged(hide: Boolean) {
61 | super.onHiddenChanged(hide)
62 | if (hide) {
63 | Log.e("TAG", "ErrorState: 隐藏了")
64 | } else {
65 | Log.e("TAG", "ErrorState: 显示了")
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/MultiStateConfig.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import androidx.annotation.DrawableRes
4 |
5 | /**
6 | * @author: yanz
7 | */
8 | data class MultiStateConfig(
9 | val errorMsg: String = "哎呀,出错了",
10 | @DrawableRes
11 | val errorIcon: Int = R.mipmap.state_error,
12 | val emptyMsg: String = "这里什么都没有",
13 | @DrawableRes
14 | val emptyIcon: Int = R.mipmap.state_empty,
15 | val loadingMsg: String = "loading...",
16 | var alphaDuration: Long = 500,
17 | val defaultState: MultiState? = null
18 | ) {
19 |
20 | class Builder {
21 | private var errorMsg: String = "哎呀,出错了"
22 |
23 | @DrawableRes
24 | private var errorIcon: Int = R.mipmap.state_error
25 | private var emptyMsg: String = "这里什么都没有"
26 |
27 | @DrawableRes
28 | private var emptyIcon: Int = R.mipmap.state_empty
29 | private var loadingMsg: String = "loading..."
30 | private var alphaDuration: Long = 500
31 |
32 | fun errorMsg(msg: String): Builder {
33 | this.errorMsg = msg
34 | return this
35 | }
36 |
37 | fun errorIcon(@DrawableRes icon: Int): Builder {
38 | this.errorIcon = icon
39 | return this
40 | }
41 |
42 | fun emptyMsg(msg: String): Builder {
43 | this.emptyMsg = msg
44 | return this
45 | }
46 |
47 | fun emptyIcon(@DrawableRes icon: Int): Builder {
48 | this.emptyIcon = icon
49 | return this
50 | }
51 |
52 | fun loadingMsg(msg: String): Builder {
53 | this.loadingMsg = msg
54 | return this
55 | }
56 |
57 | fun alphaDuration(duration: Long): Builder {
58 | this.alphaDuration = duration
59 | return this
60 | }
61 |
62 | fun build() = MultiStateConfig(
63 | errorMsg = errorMsg,
64 | errorIcon = errorIcon,
65 | emptyMsg = emptyMsg,
66 | emptyIcon = emptyIcon,
67 | loadingMsg = loadingMsg,
68 | alphaDuration = alphaDuration,
69 | )
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_smart_refresh_layout2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
41 |
42 |
47 |
48 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/SmartRefreshLayoutActivity2.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import androidx.lifecycle.lifecycleScope
4 | import androidx.recyclerview.widget.LinearLayoutManager
5 | import com.zy.demo.base.*
6 | import com.zy.demo.databinding.ActivitySmartRefreshLayout2Binding
7 | import com.zy.multistatepage.bindMultiState
8 | import kotlinx.coroutines.delay
9 |
10 | class SmartRefreshLayoutActivity2 : BaseActivity() {
11 | private val rlvAdapter = SmartRefreshLayoutActivity.RlvAdapter()
12 | private val container by lazy { viewBinding.recyclerView.bindMultiState() }
13 |
14 | override fun initPage() {
15 | viewBinding.recyclerView.layoutManager = LinearLayoutManager(this)
16 | viewBinding.recyclerView.adapter = rlvAdapter
17 | loadData()
18 |
19 |
20 | viewBinding.smartRefreshLayout.setEnableLoadMoreWhenContentNotFull(false)
21 |
22 | viewBinding.smartRefreshLayout.setOnRefreshListener {
23 | rlvAdapter.refreshData(getData(50))
24 | container.showSuccess()
25 | it.finishRefresh()
26 | }
27 | viewBinding.smartRefreshLayout.setOnLoadMoreListener {
28 | rlvAdapter.addData(getData(30))
29 | container.showSuccess()
30 | it.finishLoadMore()
31 | }
32 |
33 | viewBinding.btnContent.setOnClickListener {
34 | rlvAdapter.refreshData(getData(50))
35 | container.showSuccess()
36 | }
37 | viewBinding.btnError.setOnClickListener {
38 | rlvAdapter.clearData()
39 | container.showError() {
40 | it.retry { loadData() }
41 | }
42 | }
43 | viewBinding.btnEmpty.setOnClickListener {
44 | rlvAdapter.clearData()
45 | container.showEmpty()
46 | }
47 | }
48 |
49 | private fun loadData() {
50 | lifecycleScope.launchWhenResumed {
51 | container.showLoading()
52 | delay(3000)
53 | rlvAdapter.refreshData(getData(50))
54 | container.showSuccess()
55 | }
56 | }
57 |
58 | private fun getData(count: Int): MutableList {
59 | val data = mutableListOf()
60 | for (i in 0 until count) {
61 | data.add("data")
62 | }
63 | return data
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_smart_refresh_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
43 |
44 |
49 |
50 |
55 |
56 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.zy.demo'
8 | compileSdk 33
9 | defaultConfig {
10 | applicationId "com.zy.demo"
11 | minSdk 21
12 | targetSdk 33
13 | versionCode 11
14 | versionName "2.0.6"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | buildFeatures {
25 | viewBinding = true
26 | }
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 | kotlinOptions {
32 | jvmTarget = '1.8'
33 | }
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(dir: "libs", include: ["*.jar"])
38 | implementation 'androidx.core:core-ktx:1.10.1'
39 | implementation 'androidx.appcompat:appcompat:1.6.1'
40 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
41 | testImplementation 'junit:junit:4.13.2'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
44 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
45 | implementation 'androidx.recyclerview:recyclerview:1.3.1'
46 | implementation 'androidx.viewpager2:viewpager2:1.0.0'
47 | implementation 'com.google.android.material:material:1.9.0'
48 | implementation 'androidx.activity:activity-ktx:1.7.2'
49 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
50 | implementation 'androidx.fragment:fragment-ktx:1.6.1'
51 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
52 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
53 | implementation "com.airbnb.android:lottie:6.0.0"
54 | implementation "com.squareup.retrofit2:retrofit:2.9.0"
55 | implementation "com.squareup.retrofit2:converter-gson:2.9.0"
56 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
57 | implementation 'io.github.scwang90:refresh-layout-kernel:2.0.6'
58 | implementation 'io.github.scwang90:refresh-header-classics:2.0.6'
59 | implementation project(':multistatepage')
60 | }
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/MultiStatePage.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import android.app.Activity
4 | import android.view.View
5 | import android.view.ViewGroup
6 |
7 | /**
8 | * @author: yanz
9 | */
10 | object MultiStatePage {
11 |
12 | /**
13 | * 实现原理
14 | * 1.根据目标view在父view中的位置索引,移除原目标view,
15 | * 2.将MultiStateContainer添加到原view的索引处
16 | * 3.MultiStateContainer 的 layoutParams 是原目标View的 layoutParams
17 | */
18 | @JvmStatic
19 | fun bindMultiState(
20 | targetView: View,
21 | ): MultiStateContainer {
22 | val parent = targetView.parent as ViewGroup?
23 | var targetViewIndex = 0
24 | val multiStateContainer = MultiStateContainer(targetView.context, targetView)
25 | parent?.let { targetViewParent ->
26 | for (i in 0 until targetViewParent.childCount) {
27 | if (targetViewParent.getChildAt(i) == targetView) {
28 | targetViewIndex = i
29 | break
30 | }
31 | }
32 | targetViewParent.removeView(targetView)
33 | targetViewParent.addView(multiStateContainer, targetViewIndex, targetView.layoutParams)
34 | }
35 | multiStateContainer.initialization()
36 | return multiStateContainer
37 | }
38 |
39 | /**
40 | * 实现原理
41 | * 1. android.R.id.content 是Activity setContentView 内容的父view
42 | * 2. 在这个view中移除原本要添加的contentView
43 | * 3. 将MultiStateContainer设置为 content的子View MultiStateContainer中持有原有的Activity setContentView
44 | */
45 | @JvmStatic
46 | fun bindMultiState(
47 | activity: Activity,
48 | ): MultiStateContainer {
49 | val targetView = activity.findViewById(android.R.id.content)
50 | val targetViewIndex = 0
51 | val oldContent: View = targetView.getChildAt(targetViewIndex)
52 | targetView.removeView(oldContent)
53 | val oldLayoutParams = oldContent.layoutParams
54 | val multiStateContainer = MultiStateContainer(oldContent.context, oldContent)
55 | targetView.addView(multiStateContainer, targetViewIndex, oldLayoutParams)
56 | multiStateContainer.initialization()
57 | return multiStateContainer
58 | }
59 |
60 | var config: MultiStateConfig = MultiStateConfig()
61 |
62 | @JvmStatic
63 | fun config(config: MultiStateConfig): MultiStatePage {
64 | this.config = config
65 | return this
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
58 |
59 |
64 |
65 |
70 |
71 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/base/Fun.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo.base
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import com.zy.multistatepage.MultiStateContainer
6 | import com.zy.multistatepage.state.EmptyState
7 | import com.zy.multistatepage.state.ErrorState
8 | import com.zy.multistatepage.state.LoadingState
9 | import com.zy.multistatepage.state.SuccessState
10 | import kotlinx.coroutines.MainScope
11 | import kotlinx.coroutines.delay
12 | import kotlinx.coroutines.launch
13 |
14 | /**
15 | * @author: yanz
16 | */
17 | fun mockRandom(multiStateContainer: MultiStateContainer, block: () -> Unit) {
18 | MainScope().launch {
19 | multiStateContainer.show()
20 | val delayTime = (10..30).random() * 100.toLong()
21 | delay(delayTime)
22 | block.invoke()
23 | when ((1..3).random()) {
24 | 1 -> multiStateContainer.show()
25 | 2 -> multiStateContainer.show()
26 | 3 -> multiStateContainer.show()
27 | }
28 | }
29 | }
30 |
31 | fun mockError(multiStateContainer: MultiStateContainer) {
32 | MainScope().launch {
33 | multiStateContainer.show()
34 | val delayTime = (10..30).random() * 100.toLong()
35 | delay(delayTime)
36 | // val errorState = ErrorState()
37 | // errorState.retry { mockSuccess(multiStateContainer) }
38 | multiStateContainer.show {
39 | it.retry { mockSuccess(multiStateContainer) }
40 | }
41 | }
42 | }
43 |
44 | fun mockSuccess(multiStateContainer: MultiStateContainer) {
45 | MainScope().launch {
46 | multiStateContainer.show()
47 | val delayTime = (10..30).random() * 100.toLong()
48 | delay(delayTime)
49 | multiStateContainer.show()
50 | }
51 | }
52 |
53 | fun mockEmpty(multiStateContainer: MultiStateContainer) {
54 | MainScope().launch {
55 | multiStateContainer.show()
56 | val delayTime = (10..30).random() * 100.toLong()
57 | delay(delayTime)
58 | multiStateContainer.show()
59 | }
60 | }
61 |
62 | fun MultiStateContainer.showSuccess(callBack: () -> Unit = {}) {
63 | show {
64 | callBack.invoke()
65 | }
66 | }
67 |
68 | fun MultiStateContainer.showError(callBack: (ErrorState) -> Unit = {}) {
69 | show {
70 | callBack.invoke(it)
71 | }
72 | }
73 |
74 | fun MultiStateContainer.showEmpty(callBack: () -> Unit = {}) {
75 | show {
76 | callBack.invoke()
77 | }
78 | }
79 |
80 | fun MultiStateContainer.showLoading(callBack: () -> Unit = {}) {
81 | show {
82 | callBack.invoke()
83 | }
84 | }
85 |
86 | inline fun Activity.startActivity() {
87 | startActivity(Intent(this, T::class.java))
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
31 |
32 |
38 |
39 |
45 |
46 |
52 |
53 |
59 |
60 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zy/demo/SmartRefreshLayoutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zy.demo
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.lifecycle.lifecycleScope
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.zy.demo.base.*
10 | import com.zy.demo.databinding.ActivitySmartRefreshLayoutBinding
11 | import com.zy.demo.databinding.RlvItemBinding
12 | import kotlinx.coroutines.delay
13 | import kotlinx.coroutines.launch
14 |
15 | class SmartRefreshLayoutActivity : BaseActivity() {
16 |
17 | private val rlvAdapter = RlvAdapter()
18 |
19 | override fun initPage() {
20 | viewBinding.recyclerView.layoutManager = LinearLayoutManager(this)
21 | viewBinding.recyclerView.adapter = rlvAdapter
22 | loadData()
23 |
24 | viewBinding.smartRefreshLayout.setEnableLoadMoreWhenContentNotFull(false)
25 |
26 | viewBinding.smartRefreshLayout.setOnRefreshListener {
27 | rlvAdapter.refreshData(getData(50))
28 | viewBinding.container.showSuccess()
29 | it.finishRefresh()
30 | }
31 | viewBinding.smartRefreshLayout.setOnLoadMoreListener {
32 | rlvAdapter.addData(getData(30))
33 | viewBinding.container.showSuccess()
34 | it.finishLoadMore()
35 | }
36 |
37 | viewBinding.btnContent.setOnClickListener {
38 | rlvAdapter.refreshData(getData(50))
39 | viewBinding.container.showSuccess()
40 | }
41 | viewBinding.btnError.setOnClickListener {
42 | rlvAdapter.clearData()
43 | viewBinding.container.showError() {
44 | it.retry { loadData() }
45 | }
46 | }
47 | viewBinding.btnEmpty.setOnClickListener {
48 | rlvAdapter.clearData()
49 | viewBinding.container.showEmpty()
50 | }
51 | }
52 |
53 | private fun loadData() {
54 | lifecycleScope.launch {
55 | viewBinding.container.showLoading()
56 | delay(3000)
57 | rlvAdapter.refreshData(getData(50))
58 | viewBinding.container.showSuccess()
59 | }
60 | }
61 |
62 | private fun getData(count: Int): MutableList {
63 | val data = mutableListOf()
64 | for (i in 0 until count) {
65 | data.add("data")
66 | }
67 | return data
68 | }
69 |
70 | class RlvAdapter : RecyclerView.Adapter() {
71 |
72 | var data = mutableListOf()
73 |
74 | inner class Holder(val viewBinding: RlvItemBinding) : RecyclerView.ViewHolder(viewBinding.root)
75 |
76 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder =
77 | Holder(RlvItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
78 |
79 | @SuppressLint("SetTextI18n")
80 | override fun onBindViewHolder(holder: Holder, position: Int) {
81 | holder.viewBinding.root.text = "${data[position]}${position}"
82 | }
83 |
84 | override fun getItemCount(): Int = data.size
85 |
86 | fun addData(data: MutableList) {
87 | this.data.addAll(data)
88 | notifyDataSetChanged()
89 | }
90 |
91 | fun refreshData(data: MutableList) {
92 | this.data = data
93 | notifyDataSetChanged()
94 | }
95 |
96 | fun clearData() {
97 | this.data.clear()
98 | notifyDataSetChanged()
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_multi_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
20 |
21 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
66 |
67 |
68 |
69 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/multistatepage/src/main/java/com/zy/multistatepage/MultiStateContainer.kt:
--------------------------------------------------------------------------------
1 | package com.zy.multistatepage
2 |
3 | import android.animation.ValueAnimator
4 | import android.content.Context
5 | import android.util.AttributeSet
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.FrameLayout
10 | import com.zy.multistatepage.state.SuccessState
11 |
12 | /**
13 | * @author: yanz
14 | */
15 | @Suppress("UNCHECKED_CAST")
16 | open class MultiStateContainer : FrameLayout {
17 |
18 | private var originTargetView: View? = null
19 |
20 | private var lastState: MultiState? = null
21 |
22 | var currentState: MultiState? = null
23 |
24 | private var statePool: MutableMap, MultiState> = mutableMapOf()
25 |
26 | private var animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {
27 | duration = MultiStatePage.config.alphaDuration
28 | }
29 |
30 | constructor(
31 | context: Context,
32 | originTargetView: View,
33 | ) : this(context, null) {
34 | this.originTargetView = originTargetView
35 | }
36 |
37 | constructor(
38 | context: Context,
39 | attrs: AttributeSet?,
40 | ) : this(context, attrs, 0)
41 |
42 | constructor(
43 | context: Context,
44 | attrs: AttributeSet?,
45 | defStyleAttr: Int,
46 | ) : super(context, attrs, defStyleAttr)
47 |
48 | override fun onFinishInflate() {
49 | super.onFinishInflate()
50 | if (originTargetView == null && childCount == 1) {
51 | originTargetView = getChildAt(0)
52 | }
53 | }
54 |
55 | fun initialization() {
56 | val layoutParams = ViewGroup.LayoutParams(
57 | ViewGroup.LayoutParams.MATCH_PARENT,
58 | ViewGroup.LayoutParams.MATCH_PARENT
59 | )
60 | addView(originTargetView, 0, layoutParams)
61 | }
62 |
63 | inline fun show(enableAnimator: Boolean = true, noinline notify: (T) -> Unit = {}) {
64 | show(T::class.java, enableAnimator, notify)
65 | }
66 |
67 | @JvmOverloads
68 | fun show(
69 | multiState: T,
70 | enableAnimator: Boolean = true,
71 | onNotifyListener: OnNotifyListener? = null,
72 | ) {
73 | if (childCount == 0) {
74 | initialization()
75 | }
76 |
77 | if (multiState is SuccessState) {
78 | if (childCount > 1) {
79 | removeViewAt(1)
80 | }
81 | if (lastState !is SuccessState) {
82 | originTargetView?.visibility = View.VISIBLE
83 | lastState?.onHiddenChanged(true)
84 | if (enableAnimator) {
85 | originTargetView?.executeAnimator()
86 | }
87 | }
88 | } else {
89 | originTargetView?.visibility = View.INVISIBLE
90 | if (lastState != multiState) {
91 | if (childCount > 1) {
92 | removeViewAt(1)
93 | }
94 | val currentStateView = multiState.onCreateView(context, LayoutInflater.from(context), this)
95 | multiState.onViewCreated(currentStateView)
96 | addView(currentStateView)
97 | lastState?.onHiddenChanged(true)
98 | multiState.onHiddenChanged(false)
99 | if (enableAnimator) {
100 | currentStateView.executeAnimator()
101 | }
102 | }
103 | onNotifyListener?.onNotify(multiState)
104 | }
105 | currentState = multiState
106 | lastState = multiState
107 | }
108 |
109 | @JvmOverloads
110 | fun show(
111 | clazz: Class,
112 | enableAnimator: Boolean = true,
113 | onNotifyListener: OnNotifyListener? = null,
114 | ) {
115 | findState(clazz)?.let { multiState -> show(multiState as T, enableAnimator, onNotifyListener) }
116 | }
117 |
118 | private fun findState(clazz: Class): MultiState? {
119 | return if (statePool.containsKey(clazz)) {
120 | statePool[clazz]
121 | } else {
122 | val state = clazz.newInstance()
123 | statePool[clazz] = state
124 | state
125 | }
126 | }
127 |
128 | private fun View.executeAnimator() {
129 | this.clearAnimation()
130 | animator.addUpdateListener {
131 | this.alpha = it.animatedValue as Float
132 | }
133 | animator.start()
134 | }
135 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt 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 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MultiStatePage
2 |
3 | [](https://jitpack.io/#Zhao-Yan-Yan/MultiStatePage) [](https://github.com/Zhao-Yan-Yan/MultiStatePage/blob/master/LICENSE) 
4 |
5 | 
6 |
7 | | [Activity](app/src/main/java/com/zy/demo/MultiStateActivity.kt) | [Fragment](app/src/main/java/com/zy/demo/MultiFragmentActivity.kt) | [View](app/src/main/java/com/zy/demo/MultiViewActivity.kt) | [ViewPager2](app/src/main/java/com/zy/demo/ViewPager2Activity.kt) |
8 | |:---------------------------------------------------------------:|:------------------------------------------------------------------:|:----------------------------------------------------------:|:-----------------------------------------------------------------:|
9 | |  |  |  |  |
10 |
11 | | [Lottie拓展(自定义State)](app/src/main/java/com/zy/demo/LottieExtActivity.kt) | [State刷新](app/src/main/java/com/zy/demo/RefreshStateActivity.kt) | [网络请求](app/src/main/java/com/zy/demo/MockNetActivity.kt) | [sample](app/src/main/java/com/zy/demo/ApiActivity.kt) |
12 | |:------------------------------------------------------------------------:|:----------------------------------------------------------------:|:--------------------------------------------------------:|:------------------------------------------------------:|
13 | |  |  |  |  |
14 |
15 | ## MultiStatePage的功能及特点
16 |
17 | - 无需在布局添加视图代码
18 | - 可显示自定义状态视图,任意拓展
19 | - 可用于 Activity、Fragment、或指定的 View
20 | - 自定义重新请求监听
21 | - 支持xml直接嵌套且不限制要展示状态内容
22 | - 可动态更新视图样式
23 | - 可结合第三方控件使用
24 | - 支持状态回调监听
25 | - kotlin开发更易用的API
26 |
27 | ## 开始
28 |
29 | ### 添加依赖
30 |
31 | Step1. Add the JitPack repository to your build file
32 |
33 | ```
34 | allprojects {
35 | repositories {
36 | maven { url 'https://jitpack.io' }
37 | }
38 | }
39 | ```
40 |
41 | Step2. Add the dependency [](https://jitpack.io/#Zhao-Yan-Yan/MultiStatePage)
42 |
43 | ```
44 | dependencies {
45 | implementation 'com.github.Zhao-Yan-Yan:MultiStatePage:2.0.6'
46 | }
47 | ```
48 |
49 | ### 1.生成MultiStateContainer
50 |
51 | #### 在View上使用
52 |
53 | ```kotlin
54 | val multiStateContainer = MultiStatePage.bindMultiState(view)
55 | // 或
56 | val multiStateContainer = view.bindMultiState()
57 | ```
58 |
59 | #### 在Activity根View中使用
60 |
61 | ```kotlin
62 | val multiStateContainer = MultiStatePage.bindMultiState(this)
63 | // 或
64 | val multiStateContainer = bindMultiState()
65 | ```
66 |
67 | #### 在Fragment根View中使用
68 |
69 | ```kotlin
70 | class MultiStateFragment : Fragment {
71 |
72 | private lateinit var multiStateContainer: MultiStateContainer
73 |
74 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
75 | val root = inflater.inflate(R.layout.fragment, container, false)
76 | multiStateContainer = MultiStatePage.bindMultiState(root)
77 | // 或
78 | multiStateContainer = root.bindMultiState()
79 | return multiStateContainer
80 | }
81 | }
82 | ```
83 |
84 | #### xml中引用
85 |
86 | ```xml
87 |
88 |
92 |
93 |
97 |
98 |
99 | ```
100 |
101 | ### 2.切换状态
102 |
103 | ```kotlin
104 | multiStateContainer.show()
105 | // 或
106 | multiStateContainer.show(CustomState())
107 | ```
108 |
109 | #### 更新state信息
110 |
111 | ```kotlin
112 | multiStateContainer.show { errorState ->
113 | errorState.setErrorMsg("xxx出错了")
114 | }
115 | ```
116 |
117 | ### 如何添加重试事件(建议自定义State实现)参考 ErrorState
118 |
119 | ```kotlin
120 | class ErrorState : MultiState() {
121 |
122 | private lateinit var tvRetry: TextView
123 |
124 | private var retry: OnRetryClickListener? = null
125 |
126 | override fun onCreateView(
127 | context: Context, inflater: LayoutInflater, container: MultiStateContainer
128 | ): View {
129 | return inflater.inflate(R.layout.mult_state_error, container, false)
130 | }
131 |
132 | override fun onViewCreated(view: View) {
133 | tvRetry = view.findViewById(R.id.tv_retry)
134 | tvRetry.setOnClickListener { retry?.retry() }
135 | }
136 |
137 | fun retry(retry: OnRetryClickListener) {
138 | this.retry = retry
139 | }
140 |
141 | fun interface OnRetryClickListener {
142 | fun retry()
143 | }
144 | }
145 | ```
146 |
147 | ```kotlin
148 | multiStateContainer.show { state ->
149 | state.retry { do () }
150 | }
151 | // 或
152 | val state = ErrorState().apply {
153 | retry { do () }
154 | }
155 | multiStateContainer.show(state)
156 | ```
157 |
158 | ### 如何设置默认State
159 |
160 | 利用kotlin拓展函数可以很轻松的实现
161 |
162 | ```kotlin
163 | val multiStateActivityRoot = bindMultiState().apply { showEmpty() }
164 | ```
165 |
166 | ### 自定义State
167 |
168 | #### 继承`MultiState`
169 |
170 | ```kotlin
171 | class LottieWaitingState : MultiState() {
172 | override fun onCreateView(context: Context, inflater: LayoutInflater, container: MultiStateContainer): View {
173 | // your state view
174 | return inflater.inflate(R.layout.multi_lottie_waiting, container, false)
175 | }
176 |
177 | override fun onViewCreated(view: View) {
178 | //逻辑处理
179 | }
180 |
181 | override fun onHiddenChanged(hide: Boolean) {
182 | if (hide) {
183 | // State 隐藏
184 | } else {
185 | // State 显示
186 | }
187 | }
188 | }
189 | ```
190 |
191 | 结合`ViewBidng` 参考 `demo` [MultiStateBinding](app/src/main/java/com/zy/demo/base/MultiStateBinding.kt) 和 [WithBindingState](app/src/main/java/com/zy/demo/state/WithBindingState.kt)
192 |
193 | ### 使用内置状态配置
194 |
195 | **默认内置3种状态(强烈建议您自定义State)**
196 |
197 | ```kotlin
198 | val multiStateContainer = MultiStatePage.bindMultiState(view)
199 | //成功页
200 | multiStateContainer.show()
201 | //错误页
202 | multiStateContainer.show()
203 | //空页面
204 | multiStateContainer.show()
205 | //加载状态页
206 | multiStateContainer.show()
207 | ```
208 |
209 | **更换默认资源**
210 |
211 | ```kotlin
212 | class App : Application() {
213 | override fun onCreate() {
214 | super.onCreate()
215 | val config = MultiStateConfig.Builder()
216 | .alphaDuration(300)
217 | .errorIcon(R.mipmap.state_error)
218 | .emptyIcon(R.mipmap.state_empty)
219 | .emptyMsg("emptyMsg")
220 | .loadingMsg("loadingMsg")
221 | .errorMsg("errorMsg")
222 | .build()
223 | MultiStatePage.config(config)
224 | }
225 | }
226 | ```
227 |
228 | | Methods | Description |
229 | |:-------------:|:---------------:|
230 | | alphaDuration | alpha动画时长 |
231 | | errorIcon | 错误状态默认图标 |
232 | | emptyIcon | 空数据状态默认图标 |
233 | | emptyMsg | 空数据状态默认提示信息 |
234 | | errorMsg | 错误状态默认提示信息 |
235 | | loadingMsg | loading状态默认提示信息 |
236 |
237 | ### 小技巧
238 |
239 | 可以借助kotlin的拓展函数封装常用的状态
240 |
241 | ```kotlin
242 | fun MultiStateContainer.showSuccess(callBack: (SuccessState) -> Unit = {}) {
243 | show { callBack.invoke(it) }
244 | }
245 |
246 | fun MultiStateContainer.showError(callBack: (ErrorState) -> Unit = {}) {
247 | show { callBack.invoke(it) }
248 | }
249 |
250 | fun MultiStateContainer.showEmpty(callBack: (EmptyState) -> Unit = {}) {
251 | show { callBack.invoke(it) }
252 | }
253 |
254 | fun MultiStateContainer.showLoading(callBack: (LoadingState) -> Unit = {}) {
255 | show { callBack.invoke(it) }
256 | }
257 | ```
258 |
259 | ```kotlin
260 | val multiStateContainer = bindMultiState()
261 | multiStateContainer.showLoading()
262 | multiStateContainer.showSuccess()
263 | ```
264 |
265 | ## 下载Demo
266 |
267 | 点击或者扫描二维码下载
268 |
269 | [](https://www.pgyer.com/PVAi)
270 |
271 | ## Thanks
272 |
273 | - [DylanCaiCoding/LoadingHelper](https://github.com/DylanCaiCoding/LoadingHelper/)
274 | - [KingJA/LoadSir](https://github.com/KingJA/LoadSir)
275 | - [airbnb/lottie-android](https://github.com/airbnb/lottie-android)
276 | - [lottie动画资源社区](https://lottiefiles.com/featured)
277 | - [玩Android](https://www.wanandroid.com/)
278 |
279 | ## License
280 |
281 | ```
282 | Copyright (C) 2020. ZhaoYan
283 |
284 | Licensed under the Apache License, Version 2.0 (the "License");
285 | you may not use this file except in compliance with the License.
286 | You may obtain a copy of the License at
287 |
288 | http://www.apache.org/licenses/LICENSE-2.0
289 |
290 | Unless required by applicable law or agreed to in writing, software
291 | distributed under the License is distributed on an "AS IS" BASIS,
292 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
293 | See the License for the specific language governing permissions and
294 | limitations under the License.
295 | ```
296 |
297 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/app/src/main/assets/lottie_waiting.json:
--------------------------------------------------------------------------------
1 | {"v":"5.6.10","fr":25,"ip":0,"op":138,"w":1191,"h":842,"nm":"Live waiting Animation","ddd":0,"assets":[{"id":"image_0","w":579,"h":150,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_1","w":579,"h":150,"u":"","p":"data:image/png;base64,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","e":1}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"needle Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[644.329,392.068,0],"ix":2},"a":{"a":0,"k":[50.69,59.038,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-10.415],[-10.416,0],[0,10.416],[10.415,0]],"o":[[0,10.416],[10.415,0],[0,-10.415],[-10.416,0]],"v":[[-18.858,-0.001],[-0.001,18.858],[18.858,-0.001],[-0.001,-18.858]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.470999983245,0.313999998803,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[82.272,98.967],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.015],[0,0],[3.015,0],[0,0],[0,-3.017],[-3.015,0],[0,0]],"o":[[0,0],[0,-3.017],[0,0],[-3.015,0],[0,3.015],[0,0],[3.015,0]],"v":[[43.753,0.001],[43.753,0.001],[38.27,-5.482],[-38.27,-5.482],[-43.753,0.001],[-38.27,5.482],[38.27,5.482]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000003889,0.404000016755,0.961000031116,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[79.737,99.807],"ix":2},"a":{"a":0,"k":[40,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":138,"s":[359]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.015,0],[0,0],[0,3.016],[0,0],[3.017,0],[0,-3.014],[0,0]],"o":[[0,0],[3.017,0],[0,0],[0,-3.014],[-3.015,0],[0,0],[0,3.016]],"v":[[-0.001,52.099],[-0.001,52.099],[5.482,46.617],[5.482,-46.617],[-0.001,-52.099],[-5.482,-46.617],[-5.482,46.617]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000003889,0.404000016755,0.961000031116,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[82.273,94.914],"ix":2},"a":{"a":0,"k":[0,47],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":138,"s":[719]}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":225,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"clock Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[688.008,417.268,0],"ix":2},"a":{"a":0,"k":[211.224,213.856,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.214,1.278],[-1.279,-2.213],[0,0],[2.213,-1.277],[1.276,2.212],[0,0]],"o":[[2.214,-1.278],[0,0],[1.277,2.214],[-2.214,1.278],[0,0],[-1.28,-2.213]],"v":[[-70.078,-121.38],[-63.738,-119.681],[-59.694,-112.676],[-61.393,-106.337],[-67.736,-108.035],[-71.778,-115.039]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-2.214,1.279],[-1.277,-2.213],[0,0],[2.214,-1.278],[1.277,2.213],[0,0]],"o":[[2.211,-1.278],[0,0],[1.278,2.215],[-2.212,1.279],[0,0],[-1.28,-2.216]],"v":[[61.395,106.336],[67.735,108.037],[71.779,115.04],[70.078,121.379],[63.737,119.682],[59.693,112.678]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-1.279,2.215],[-2.212,-1.278],[0,0],[1.277,-2.214],[2.214,1.277],[0,0]],"o":[[1.278,-2.211],[0,0],[2.215,1.278],[-1.277,2.213],[0,0],[-2.216,-1.28]],"v":[[-121.38,-70.081],[-115.041,-71.778],[-108.036,-67.734],[-106.337,-61.391],[-112.677,-59.692],[-119.681,-63.736]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-1.277,2.214],[-2.212,-1.279],[0,0],[1.276,-2.213],[2.211,1.276],[0,0]],"o":[[1.279,-2.213],[0,0],[2.214,1.278],[-1.277,2.213],[0,0],[-2.214,-1.278]],"v":[[106.336,61.392],[112.677,59.694],[119.681,63.737],[121.381,70.079],[115.04,71.779],[108.035,67.735]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,2.56],[-2.559,0],[0,0],[0,-2.559],[2.559,0],[0,0]],"o":[[0,-2.557],[0,0],[2.562,0],[0,2.558],[0,0],[-2.561,0]],"v":[[-140.158,-0.002],[-135.515,-4.642],[-127.429,-4.642],[-122.788,0.001],[-127.429,4.643],[-135.515,4.643]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,2.56],[-2.556,0],[0,0],[0,-2.559],[2.556,0],[0,0]],"o":[[0,-2.557],[0,0],[2.559,0],[0,2.558],[0,0],[-2.559,0]],"v":[[122.785,-0.002],[127.428,-4.642],[135.517,-4.642],[140.158,0.001],[135.517,4.643],[127.428,4.643]],"c":true},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[1.278,2.213],[-2.213,1.278],[0,0],[-1.277,-2.216],[2.215,-1.277],[0,0]],"o":[[-1.279,-2.213],[0,0],[2.215,-1.279],[1.277,2.212],[0,0],[-2.214,1.276]],"v":[[-121.38,70.079],[-119.681,63.737],[-112.676,59.694],[-106.337,61.395],[-108.036,67.735],[-115.038,71.779]],"c":true},"ix":2},"nm":"Path 7","mn":"ADBE Vector Shape - Group","hd":false},{"ind":7,"ty":"sh","ix":8,"ks":{"a":0,"k":{"i":[[1.279,2.213],[-2.212,1.277],[0,0],[-1.279,-2.214],[2.214,-1.278],[0,0]],"o":[[-1.277,-2.212],[0,0],[2.214,-1.279],[1.276,2.212],[0,0],[-2.214,1.278]],"v":[[106.336,-61.394],[108.035,-67.734],[115.04,-71.778],[121.381,-70.078],[119.681,-63.736],[112.677,-59.692]],"c":true},"ix":2},"nm":"Path 8","mn":"ADBE Vector Shape - Group","hd":false},{"ind":8,"ty":"sh","ix":9,"ks":{"a":0,"k":{"i":[[2.214,1.28],[-1.28,2.211],[0,0],[-2.211,-1.278],[1.274,-2.213],[0,0]],"o":[[-2.211,-1.277],[0,0],[1.279,-2.216],[2.213,1.278],[0,0],[-1.281,2.215]],"v":[[-70.082,121.378],[-71.778,115.04],[-67.736,108.037],[-61.393,106.337],[-59.691,112.678],[-63.736,119.682]],"c":true},"ix":2},"nm":"Path 9","mn":"ADBE Vector Shape - Group","hd":false},{"ind":9,"ty":"sh","ix":10,"ks":{"a":0,"k":{"i":[[2.214,1.279],[-1.277,2.213],[0,0],[-2.216,-1.277],[1.278,-2.212],[0,0]],"o":[[-2.211,-1.276],[0,0],[1.28,-2.214],[2.212,1.277],[0,0],[-1.28,2.214]],"v":[[61.392,-106.338],[59.693,-112.677],[63.737,-119.682],[70.079,-121.38],[71.779,-115.04],[67.735,-108.035]],"c":true},"ix":2},"nm":"Path 10","mn":"ADBE Vector Shape - Group","hd":false},{"ind":10,"ty":"sh","ix":11,"ks":{"a":0,"k":{"i":[[2.559,0],[0,2.559],[0,0],[-2.557,0],[0,-2.559],[0,0]],"o":[[-2.559,0],[0,0],[0,-2.561],[2.559,0],[0,0],[0,2.56]],"v":[[0,140.158],[-4.642,135.516],[-4.642,127.429],[0,122.787],[4.644,127.429],[4.644,135.516]],"c":true},"ix":2},"nm":"Path 11","mn":"ADBE Vector Shape - Group","hd":false},{"ind":11,"ty":"sh","ix":12,"ks":{"a":0,"k":{"i":[[2.559,0],[0,2.557],[0,0],[-2.557,0],[0,-2.558],[0,0]],"o":[[-2.559,0],[0,0],[0,-2.56],[2.559,0],[0,0],[0,2.56]],"v":[[0,-122.787],[-4.642,-127.428],[-4.642,-135.516],[0,-140.158],[4.644,-135.516],[4.644,-127.428]],"c":true},"ix":2},"nm":"Path 12","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.592000026329,0.736999990426,0.984000052658,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[199.126,228.585],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":16,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-87.211,0],[0,87.211],[87.211,0],[0,-87.21]],"o":[[87.211,0],[0,-87.21],[-87.211,0],[0,87.211]],"v":[[0,158.342],[158.342,-0.001],[0,-158.341],[-158.342,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[199.126,228.585],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-95.233,0],[0,95.235],[95.235,0],[0,-95.235]],"o":[[95.235,0],[0,-95.235],[-95.233,0],[0,95.235]],"v":[[-0.001,172.909],[172.909,0.001],[-0.001,-172.91],[-172.909,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941000007181,0.961000031116,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[199.127,228.584],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-109.537,0],[0,109.539],[109.538,0],[0,-109.538]],"o":[[109.538,0],[0,-109.538],[-109.537,0],[0,109.539]],"v":[[0,198.877],[198.876,-0.001],[0,-198.877],[-198.876,-0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.067000003889,0.404000016755,0.961000031116,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[199.126,228.585],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,-109.836],[109.838,0],[3.926,0.235],[0,0],[0,0],[0,101.647],[-98.423,11.939],[0,0]],"o":[[0,0],[109.838,0],[0,109.838],[-3.985,0],[0,0],[0,0],[-98.423,-11.94],[0,-101.646],[0,0],[0,0]],"v":[[-0.001,-198.877],[-0.001,-198.877],[198.875,-0.002],[-0.001,198.876],[-11.866,198.514],[-24.197,198.514],[-24.197,197.408],[-198.876,-0.002],[-24.197,-197.409],[-24.197,-198.877]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.051000000449,0.313999998803,0.752999997606,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[223.323,228.585],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.096,0],[0,0],[0,-6.096],[0,0],[6.097,0],[0,0],[0,6.095],[0,0]],"o":[[0,0],[6.097,0],[0,0],[0,6.095],[0,0],[-6.096,0],[0,0],[0,-6.096]],"v":[[-61.753,-41.486],[61.752,-41.486],[72.838,-30.401],[72.838,30.402],[61.752,41.486],[-61.753,41.486],[-72.838,30.402],[-72.838,-30.401]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.783999992819,0.216000007181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[199.126,55.991],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.094,0],[0,0],[0,-6.096],[0,0],[6.097,0],[0,0],[0,6.095],[0,0]],"o":[[0,0],[6.097,0],[0,0],[0,6.095],[0,0],[-6.094,0],[0,0],[0,-6.096]],"v":[[-61.753,-41.486],[61.753,-41.486],[72.836,-30.401],[72.836,30.402],[61.753,41.486],[-61.753,41.486],[-72.837,30.402],[-72.837,-30.401]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.670999983245,0.125,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[220.296,55.991],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.607,0],[0,0],[0,-4.607],[0,0],[4.608,0],[0,0],[0,4.607],[0,0]],"o":[[0,0],[4.608,0],[0,0],[0,4.607],[0,0],[-4.607,0],[0,0],[0,-4.607]],"v":[[-46.674,-31.355],[46.675,-31.355],[55.051,-22.978],[55.051,22.979],[46.675,31.355],[-46.674,31.355],[-55.051,22.979],[-55.051,-22.978]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.470999983245,0.313999998803,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[199.126,31.605],"to":[0,1],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[199.126,37.605],"to":[0,0],"ti":[0,1]},{"t":10,"s":[199.126,31.605]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.607,0],[0,0],[0,-4.607],[0,0],[4.608,0],[0,0],[0,4.607],[0,0]],"o":[[0,0],[4.608,0],[0,0],[0,4.607],[0,0],[-4.607,0],[0,0],[0,-4.607]],"v":[[-46.674,-31.355],[46.675,-31.355],[55.051,-22.978],[55.051,22.979],[46.675,31.355],[-46.674,31.355],[-55.051,22.979],[-55.051,-22.978]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.948999980852,0.404000016755,0.243000000598,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[220.298,31.605],"to":[0,1],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":7,"s":[220.298,37.605],"to":[0,0],"ti":[0,1]},{"t":10,"s":[220.298,31.605]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":225,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"green book.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":120,"s":[100]},{"t":129,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[-7]},{"t":39,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":25,"s":[429.5,345,0],"to":[0,17.333,0],"ti":[0,-17.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":39,"s":[429.5,449,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83,"s":[429.5,449,0],"to":[0.167,11.667,0],"ti":[-0.167,-11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94,"s":[430.5,519,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114,"s":[430.5,519,0],"to":[-52.667,0,0],"ti":[52.667,0,0]},{"t":129,"s":[114.5,519,0]}],"ix":2},"a":{"a":0,"k":[289.5,75,0],"ix":1},"s":{"a":0,"k":[51.641,51.641,100],"ix":6}},"ao":0,"ip":0,"op":225,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"blue book.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"t":91,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[6]},{"t":32,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[398,470,0],"to":[0,8.5,0],"ti":[0,-8.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":32,"s":[398,521,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72,"s":[398,521,0],"to":[-49.5,0,0],"ti":[49.5,0,0]},{"t":91,"s":[101,521,0]}],"ix":2},"a":{"a":0,"k":[289.5,75,0],"ix":1},"s":{"a":0,"k":[51.206,51.206,100],"ix":6}},"ao":0,"ip":0,"op":225,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"yellow book Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[423.098,593.437,0],"ix":2},"a":{"a":0,"k":[144.689,37.688,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.608,0],[0,0],[0,0],[0,0],[-2.614,-9.637],[-0.163,-4.222],[1.461,5.385],[10.837,0],[0,0],[0,0],[0,0],[0,-3.365],[-0.31,-0.723]],"o":[[0,0],[0,0],[0,0],[10.837,0],[1.068,3.938],[0.207,-5.847],[-2.614,-9.637],[0,0],[0,0],[0,0],[-3.464,0],[0,0.83],[0.946,-2.202]],"v":[[-75.731,-11.943],[31.394,-11.943],[56.571,-11.943],[56.87,-11.943],[79.968,4.339],[81.796,16.632],[79.968,-0.351],[56.87,-16.632],[56.571,-16.632],[31.394,-16.632],[-75.731,-16.632],[-82.003,-10.536],[-81.521,-8.191]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.851000019148,0.458999992819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[86.379,21.26],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.048,6.284],[0,0],[0,0],[0,0],[0,0],[0,0],[2.256,1.327],[0.019,-0.045],[0,-1.444],[-0.527,-1.253],[-0.94,-0.949],[-1.244,-0.532],[-1.432,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.794,0],[-0.02,0.043],[-0.527,1.253],[0,1.443],[0.527,1.253],[0.942,0.949],[1.244,0.531],[0,0],[7.773,-1.584]],"v":[[83.415,-5.06],[82.429,-5.06],[61.34,-5.06],[59.996,-5.06],[35.511,-5.06],[-74.973,-5.06],[-82.516,-7.334],[-82.596,-7.217],[-83.415,-3.145],[-82.596,0.929],[-80.366,4.26],[-77.061,6.509],[-73.018,7.334],[64.858,7.334]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.783999992819,0.216000007181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[83.665,67.791],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[96.386,3.057],[0,0],[0,0],[7.772,-1.584],[0,0],[0,15.304],[0,0]],"o":[[0,0],[0,0],[-4.047,6.284],[0,0],[16.567,0],[0,0],[-5.755,9.003]],"v":[[-47.063,3.589],[-47.255,4.016],[-51.746,4.016],[-70.302,16.409],[40.257,16.409],[70.302,-11.346],[70.302,-16.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.987999949736,0.760999971278,0.195999998205,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[218.826,58.715],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.719,9.836],[3.007,11.074],[10.492,2.066],[0,0],[0.288,-0.065],[0.766,0],[0,0],[0,-5.775],[-5.732,0],[0,0],[-3.506,-3.756],[0.035,-3.821],[0,0],[10.005,0],[0,0],[0,-5.774],[-5.732,0],[0,0]],"o":[[3.514,-12.639],[-2.697,-9.899],[0,0],[-0.302,0],[-0.806,-0.066],[0,0],[-5.732,0],[0,5.777],[0,0],[5.474,0],[2.753,2.951],[0,0],[-0.11,8.836],[0,0],[-5.732,0],[0,5.778],[0,0],[10.408,-2.119]],"v":[[83.091,18.095],[83.859,-18.155],[62.112,-37.438],[59.37,-37.438],[58.482,-37.337],[56.133,-37.438],[-76.469,-37.438],[-86.866,-26.964],[-76.469,-16.487],[31.94,-16.487],[46.069,-10.578],[50.285,-0.075],[50.279,0.462],[31.933,16.488],[-76.469,16.488],[-86.866,26.958],[-76.469,37.438],[61.405,37.438]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.811999990426,0.317999985639,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[87.116,37.688],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.115,-15.828],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.249,-18.643],[-16.517,18.642],[16.516,18.642],[14.385,-17.537]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.941000007181,0.776000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[127.197,37.862],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.786,0],[0,0],[0,3.786],[0,0],[-3.786,0],[0,0],[0,-3.785],[0,0]],"o":[[0,0],[-3.786,0],[0,0],[0,-3.785],[0,0],[3.786,0],[0,0],[0,3.786]],"v":[[28.383,7.303],[-28.382,7.303],[-35.238,0.448],[-35.238,-0.449],[-28.382,-7.303],[28.383,-7.303],[35.238,-0.449],[35.238,0.448]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.980000035903,0.732999973671,0.172999991623,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[227.213,35.936],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[14.313,0],[0,0],[-1.137,-2.064],[0,0],[0,-12.909],[0,0]],"o":[[0,0],[1.648,1.832],[0,0],[14.313,0],[0,0],[0,-12.909]],"v":[[43.339,-14.617],[-69.257,-14.617],[-65.105,-8.755],[43.339,-8.755],[69.257,14.617],[69.257,8.755]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.811999990426,0.317999985639,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[215.744,19.245],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,5.778],[-5.733,0],[0,0],[-0.111,8.836],[0,0],[2.755,2.952],[5.474,0],[0,0],[0,5.776],[-5.733,0],[0,0],[-0.806,-0.068],[-0.302,0],[0,0],[0,-15.301],[0,0],[16.566,0]],"o":[[-5.733,0],[0,-5.774],[0,0],[10.005,0],[0,0],[0.035,-3.822],[-3.505,-3.756],[0,0],[-5.733,0],[0,-5.776],[0,0],[0.765,0],[0.289,-0.066],[0,0],[16.566,0],[0,0],[0,15.303],[0,0]],"v":[[-134.041,37.437],[-144.438,26.959],[-134.041,16.488],[-25.64,16.488],[-7.294,0.464],[-7.288,-0.074],[-11.505,-10.579],[-25.633,-16.488],[-134.041,-16.488],[-144.438,-26.963],[-134.041,-37.437],[-1.44,-37.437],[0.909,-37.335],[1.797,-37.437],[114.394,-37.437],[144.438,-9.687],[144.438,9.684],[114.394,37.437]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.783999992819,0.216000007181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[144.689,37.687],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":4,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-63.063,0.919],[63.063,0.919],[63.063,-0.919],[-63.063,-0.919]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.941000007181,0.776000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[84.007,45.877],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-63.063,0.921],[63.063,0.921],[63.063,-0.921],[-63.063,-0.921]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.941000007181,0.776000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[84.007,37.688],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-63.063,0.919],[63.063,0.919],[63.063,-0.919],[-63.063,-0.919]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.941000007181,0.776000019148,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[84.007,29.498],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[27.268,-20.865],[-68.281,-20.865],[-68.281,20.865],[40.363,20.865],[68.281,20.865],[68.281,-20.865]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.964999988032,0.862999949736,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.943,37.688],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":225,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"shadow Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[554.046,554.721,0],"ix":2},"a":{"a":0,"k":[287.074,83.507,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-4.062],[158.547,0],[0,4.062],[-158.547,0]],"o":[[0,4.062],[-158.547,0],[0,-4.062],[158.547,0]],"v":[[287.073,0],[0,7.354],[-287.073,0],[0,-7.354]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698000021542,0.698000021542,0.698000021542,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[287.074,159.661],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":225,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------