Compare commits
No commits in common. 'androidx' and 'main' have entirely different histories.
@ -0,0 +1,176 @@ |
|||||||
|
# ---> Android |
||||||
|
# Gradle files |
||||||
|
.gradle/ |
||||||
|
build/ |
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc) |
||||||
|
local.properties |
||||||
|
|
||||||
|
# Log/OS Files |
||||||
|
*.log |
||||||
|
|
||||||
|
# Android Studio generated files and folders |
||||||
|
captures/ |
||||||
|
.externalNativeBuild/ |
||||||
|
.cxx/ |
||||||
|
*.apk |
||||||
|
output.json |
||||||
|
|
||||||
|
# IntelliJ |
||||||
|
*.iml |
||||||
|
.idea/ |
||||||
|
misc.xml |
||||||
|
deploymentTargetDropDown.xml |
||||||
|
render.experimental.xml |
||||||
|
|
||||||
|
# Keystore files |
||||||
|
*.jks |
||||||
|
*.keystore |
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase) |
||||||
|
google-services.json |
||||||
|
|
||||||
|
# Android Profiling |
||||||
|
*.hprof |
||||||
|
|
||||||
|
# ---> CMake |
||||||
|
CMakeLists.txt.user |
||||||
|
CMakeCache.txt |
||||||
|
CMakeFiles |
||||||
|
CMakeScripts |
||||||
|
Testing |
||||||
|
Makefile |
||||||
|
cmake_install.cmake |
||||||
|
install_manifest.txt |
||||||
|
compile_commands.json |
||||||
|
CTestTestfile.cmake |
||||||
|
_deps |
||||||
|
|
||||||
|
# ---> Gradle |
||||||
|
.gradle |
||||||
|
**/build/ |
||||||
|
!src/**/build/ |
||||||
|
|
||||||
|
# Ignore Gradle GUI config |
||||||
|
gradle-app.setting |
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) |
||||||
|
!gradle-wrapper.jar |
||||||
|
|
||||||
|
# Avoid ignore Gradle wrappper properties |
||||||
|
!gradle-wrapper.properties |
||||||
|
|
||||||
|
# Cache of project |
||||||
|
.gradletasknamecache |
||||||
|
|
||||||
|
# Eclipse Gradle plugin generated files |
||||||
|
# Eclipse Core |
||||||
|
.project |
||||||
|
# JDT-specific (Eclipse Java Development Tools) |
||||||
|
.classpath |
||||||
|
|
||||||
|
# ---> Java |
||||||
|
# Compiled class file |
||||||
|
*.class |
||||||
|
|
||||||
|
# Log file |
||||||
|
*.log |
||||||
|
|
||||||
|
# BlueJ files |
||||||
|
*.ctxt |
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME) |
||||||
|
.mtj.tmp/ |
||||||
|
|
||||||
|
# Package Files # |
||||||
|
*.jar |
||||||
|
*.war |
||||||
|
*.nar |
||||||
|
*.ear |
||||||
|
*.zip |
||||||
|
*.tar.gz |
||||||
|
*.rar |
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml |
||||||
|
hs_err_pid* |
||||||
|
replay_pid* |
||||||
|
|
||||||
|
# ---> JetBrains |
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider |
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 |
||||||
|
|
||||||
|
# User-specific stuff |
||||||
|
.idea/**/workspace.xml |
||||||
|
.idea/**/tasks.xml |
||||||
|
.idea/**/usage.statistics.xml |
||||||
|
.idea/**/dictionaries |
||||||
|
.idea/**/shelf |
||||||
|
|
||||||
|
# AWS User-specific |
||||||
|
.idea/**/aws.xml |
||||||
|
|
||||||
|
# Generated files |
||||||
|
.idea/**/contentModel.xml |
||||||
|
|
||||||
|
# Sensitive or high-churn files |
||||||
|
.idea/**/dataSources/ |
||||||
|
.idea/**/dataSources.ids |
||||||
|
.idea/**/dataSources.local.xml |
||||||
|
.idea/**/sqlDataSources.xml |
||||||
|
.idea/**/dynamic.xml |
||||||
|
.idea/**/uiDesigner.xml |
||||||
|
.idea/**/dbnavigator.xml |
||||||
|
|
||||||
|
# Gradle |
||||||
|
.idea/**/gradle.xml |
||||||
|
.idea/**/libraries |
||||||
|
|
||||||
|
# Gradle and Maven with auto-import |
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files, |
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using |
||||||
|
# auto-import. |
||||||
|
# .idea/artifacts |
||||||
|
# .idea/compiler.xml |
||||||
|
# .idea/jarRepositories.xml |
||||||
|
# .idea/modules.xml |
||||||
|
# .idea/*.iml |
||||||
|
# .idea/modules |
||||||
|
# *.iml |
||||||
|
# *.ipr |
||||||
|
|
||||||
|
# CMake |
||||||
|
cmake-build-*/ |
||||||
|
|
||||||
|
# Mongo Explorer plugin |
||||||
|
.idea/**/mongoSettings.xml |
||||||
|
|
||||||
|
# File-based project format |
||||||
|
*.iws |
||||||
|
|
||||||
|
# IntelliJ |
||||||
|
out/ |
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin |
||||||
|
.idea_modules/ |
||||||
|
|
||||||
|
# JIRA plugin |
||||||
|
atlassian-ide-plugin.xml |
||||||
|
|
||||||
|
# Cursive Clojure plugin |
||||||
|
.idea/replstate.xml |
||||||
|
|
||||||
|
# SonarLint plugin |
||||||
|
.idea/sonarlint/ |
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ) |
||||||
|
com_crashlytics_export_strings.xml |
||||||
|
crashlytics.properties |
||||||
|
crashlytics-build.properties |
||||||
|
fabric.properties |
||||||
|
|
||||||
|
# Editor-based Rest Client |
||||||
|
.idea/httpRequests |
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file |
||||||
|
.idea/caches/build_file_checksums.ser |
||||||
|
|
@ -1,22 +0,0 @@ |
|||||||
*.iml |
|
||||||
.gradle |
|
||||||
/local.properties |
|
||||||
/.idea |
|
||||||
.DS_Store |
|
||||||
/build |
|
||||||
/captures |
|
||||||
.externalNativeBuild |
|
||||||
*.iml |
|
||||||
.idea/ |
|
||||||
.gradle |
|
||||||
/local.properties |
|
||||||
.DS_Store |
|
||||||
/build |
|
||||||
/captures |
|
||||||
*.apk |
|
||||||
*.ap_ |
|
||||||
*.dex |
|
||||||
*.class |
|
||||||
bin/ |
|
||||||
gen/ |
|
||||||
local.properties |
|
@ -1,28 +0,0 @@ |
|||||||
# Android Development Base Library |
|
||||||
|
|
||||||
## 1 Third part Libraries |
|
||||||
|
|
||||||
- [AndroidX](https://developer.android.com/jetpack/androidx) |
|
||||||
- [RxJava(2)](https://github.com/ReactiveX/RxJava) |
|
||||||
- [RxAndroid(2)](https://github.com/ReactiveX/RxAndroid) |
|
||||||
- [AutoDispose](https://github.com/uber/AutoDispose) |
|
||||||
- [Dagger2](https://github.com/google/dagger) |
|
||||||
- [Glide](https://github.com/bumptech/glide) |
|
||||||
- [OkHttp](https://github.com/square/okhttp) |
|
||||||
- [Timber](https://github.com/JakeWharton/timber) |
|
||||||
- [WrapperAdapter](https://github.com/Ztiany/WrapperAdapter) |
|
||||||
- [MultiTypeAdapter](https://github.com/drakeet/MultiType) |
|
||||||
- [AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) |
|
||||||
|
|
||||||
## 2 Environment |
|
||||||
|
|
||||||
- AndroidStudio 3+ |
|
||||||
- Java8 with desugar |
|
||||||
|
|
||||||
## 3 How do we make Dagger2 working with SavedStateViewModel? |
|
||||||
|
|
||||||
refer |
|
||||||
|
|
||||||
- [saving-ui-state-with-viewmodel-savedstate-and-dagger](https://proandroiddev.com/saving-ui-state-with-viewmodel-savedstate-and-dagger-f77bcaeb8b08#7f89) |
|
||||||
- [AssistedInject](https://github.com/square/AssistedInject/issues/81) |
|
||||||
- [github-commit-browser](https://github.com/Nimrodda/github-commit-browser) |
|
@ -1,130 +0,0 @@ |
|||||||
apply plugin: 'com.android.library' |
|
||||||
apply plugin: 'kotlin-android' |
|
||||||
apply plugin: 'kotlin-android-extensions' |
|
||||||
apply plugin: 'kotlin-kapt' |
|
||||||
|
|
||||||
androidExtensions { |
|
||||||
experimental = true |
|
||||||
} |
|
||||||
|
|
||||||
android { |
|
||||||
compileSdkVersion rootProject.compileSdkVersion |
|
||||||
buildToolsVersion rootProject.buildToolsVersion |
|
||||||
|
|
||||||
defaultConfig { |
|
||||||
|
|
||||||
minSdkVersion rootProject.minSdkVersion |
|
||||||
targetSdkVersion rootProject.targetSdkVersion |
|
||||||
versionCode 1 |
|
||||||
versionName "1.0" |
|
||||||
|
|
||||||
javaCompileOptions { |
|
||||||
annotationProcessorOptions { |
|
||||||
includeCompileClasspath false |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
buildTypes { |
|
||||||
release { |
|
||||||
minifyEnabled false |
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
lintOptions { |
|
||||||
abortOnError false |
|
||||||
} |
|
||||||
|
|
||||||
compileOptions { |
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8 |
|
||||||
targetCompatibility JavaVersion.VERSION_1_8 |
|
||||||
} |
|
||||||
|
|
||||||
kotlinOptions { |
|
||||||
jvmTarget = "1.8" |
|
||||||
} |
|
||||||
|
|
||||||
sourceSets { |
|
||||||
main { |
|
||||||
java.srcDirs += "src/github/java" |
|
||||||
res.srcDirs += "src/github/res" |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
dependencies { |
|
||||||
api fileTree(dir: 'libs', include: ['*.jar']) |
|
||||||
|
|
||||||
//测试 |
|
||||||
testImplementation testLibraries.junit |
|
||||||
|
|
||||||
//AndroidSupport |
|
||||||
api androidLibraries.supportV4 |
|
||||||
api androidLibraries.appcompat |
|
||||||
api androidLibraries.recyclerView |
|
||||||
api androidLibraries.material |
|
||||||
api androidLibraries.percentLayout |
|
||||||
api androidLibraries.constraintLayout |
|
||||||
api androidLibraries.viewpager2 |
|
||||||
api androidLibraries.annotation |
|
||||||
|
|
||||||
//AAC |
|
||||||
api androidLibraries.archRuntime |
|
||||||
api androidLibraries.archCommon |
|
||||||
api androidLibraries.fragmentKtx |
|
||||||
api androidLibraries.lifecycleCommon |
|
||||||
api androidLibraries.lifecycleCommonJava8 |
|
||||||
api androidLibraries.lifecycleRuntimeKtx |
|
||||||
api androidLibraries.lifecycleLiveDataCore |
|
||||||
api androidLibraries.lifecycleLiveData |
|
||||||
api androidLibraries.lifecycleLiveKtx |
|
||||||
api androidLibraries.lifecycleViewModel |
|
||||||
api androidLibraries.lifecycleViewModelKtx |
|
||||||
api androidLibraries.lifecycleExtensions |
|
||||||
api androidLibraries.lifecycleReactiveStreams |
|
||||||
|
|
||||||
//Kotlin |
|
||||||
api kotlinLibraries.kotlinStdlib |
|
||||||
api kotlinLibraries.kotlinReflect |
|
||||||
api kotlinLibraries.kotlinCoroutines |
|
||||||
api kotlinLibraries.kotlinAndroidCoroutines |
|
||||||
api kotlinLibraries.kotlinxCoroutinesRx2 |
|
||||||
|
|
||||||
//RxJava |
|
||||||
api thirdLibraries.rxJava |
|
||||||
api thirdLibraries.rxAndroid |
|
||||||
api thirdLibraries.rxBinding |
|
||||||
api thirdLibraries.autoDispose |
|
||||||
api thirdLibraries.autoDisposeAndroid |
|
||||||
api thirdLibraries.autoDisposeLifecycle |
|
||||||
api thirdLibraries.autoDisposeLifecycleArchcomponents |
|
||||||
|
|
||||||
/*Dagger2*/ |
|
||||||
api thirdLibraries.dagger2 |
|
||||||
api thirdLibraries.jsr305 |
|
||||||
api thirdLibraries.dagger2Android |
|
||||||
api thirdLibraries.dagger2AndroidSupport |
|
||||||
kapt thirdLibraries.dagger2Apt |
|
||||||
kapt thirdLibraries.dagger2AndroidApt |
|
||||||
|
|
||||||
//LoadMore |
|
||||||
api uiLibraries.wrapperAdapter |
|
||||||
|
|
||||||
//Adapter |
|
||||||
api uiLibraries.multiType |
|
||||||
|
|
||||||
//Log |
|
||||||
api thirdLibraries.timber |
|
||||||
|
|
||||||
//ImageLoader |
|
||||||
api thirdLibraries.glide |
|
||||||
api thirdLibraries.glideOkHttp |
|
||||||
api thirdLibraries.okHttp |
|
||||||
|
|
||||||
//Utils |
|
||||||
api thirdLibraries.utilcode |
|
||||||
api thirdLibraries.jOOR |
|
||||||
api thirdLibraries.supportOptional |
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
# Add project specific ProGuard rules here. |
|
||||||
# By default, the flags in this file are appended to flags specified |
|
||||||
# in E:\DeveloperTools\sdk/tools/proguard/proguard-android.txt |
|
||||||
# You can edit the include path and order by changing the proguardFiles |
|
||||||
# directive in build.gradle. |
|
||||||
# |
|
||||||
# For more details, see |
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html |
|
||||||
|
|
||||||
# Add any project specific keep options here: |
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following |
|
||||||
# and specify the fully qualified class name to the JavaScript interface |
|
||||||
# class: |
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
|
||||||
# public *; |
|
||||||
#} |
|
@ -1,583 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (C) 2017 Jared Rummler |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.jaredrummler.android.util; |
|
||||||
|
|
||||||
import android.os.Build; |
|
||||||
import android.text.Html; |
|
||||||
import android.text.Spanned; |
|
||||||
import android.widget.TextView; |
|
||||||
|
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.LinkedList; |
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p>Build a valid HTML string for a {@link TextView}.</p> |
|
||||||
* |
|
||||||
* <p>Example usage:</p> |
|
||||||
* |
|
||||||
* <pre> |
|
||||||
* <code> |
|
||||||
* HtmlBuilder html = new HtmlBuilder() |
|
||||||
* .p() |
|
||||||
* .b() |
|
||||||
* .font().color("red").face("sans-serif-condensed").text("Hello").close() |
|
||||||
* .close() |
|
||||||
* .close(); |
|
||||||
* |
|
||||||
* // html.toString():
|
|
||||||
* // <p><b><font color="red" face="sans-serif-condensed">Hello</font></b></p>
|
|
||||||
* |
|
||||||
* yourEditText.setText(html.toSpan()); |
|
||||||
* </code> |
|
||||||
* </pre> |
|
||||||
* |
|
||||||
* <p>HTML Tags Supported by {@link TextView}:</p> |
|
||||||
* |
|
||||||
* <ul> |
|
||||||
* <li><code><a href="..."></code></li> |
|
||||||
* <li><code><b></code></li> |
|
||||||
* <li><code><big></code></li> |
|
||||||
* <li><code><blockquote></code></li> |
|
||||||
* <li><code><br></code></li> |
|
||||||
* <li><code><cite></code></li> |
|
||||||
* <li><code><dfn></code></li> |
|
||||||
* <li><code><div align="..."></code></li> |
|
||||||
* <li><code><em></code></li> |
|
||||||
* <li><code><font color="..." face="..."></code></li> |
|
||||||
* <li><code><h1></code></li> |
|
||||||
* <li><code><h2></code></li> |
|
||||||
* <li><code><h3></code></li> |
|
||||||
* <li><code><h4></code></li> |
|
||||||
* <li><code><h5></code></li> |
|
||||||
* <li><code><h6></code></li> |
|
||||||
* <li><code><i></code></li> |
|
||||||
* <li><code><img src="..."></code></li> |
|
||||||
* <li><code><p></code></li> |
|
||||||
* <li><code><small></code></li> |
|
||||||
* <li><code><strike></code></li> |
|
||||||
* <li><code><strong></code></li> |
|
||||||
* <li><code><sub></code></li> |
|
||||||
* <li><code><sup></code></li> |
|
||||||
* <li><code><tt></code></li> |
|
||||||
* <li><code><u></code></li> |
|
||||||
* <li><code><ul></code> (Android 7.0+)</li> |
|
||||||
* <li><code><li></code> (Android 7.0+)</li> |
|
||||||
* </ul> |
|
||||||
* |
|
||||||
* @see <a href='https://github.com/jaredrummler/HtmlBuilder'>HtmlBuilder</a>
|
|
||||||
*/ |
|
||||||
public class HtmlBuilder { |
|
||||||
|
|
||||||
private final StringBuilder html = new StringBuilder(); |
|
||||||
|
|
||||||
private final LinkedList<String> tags = new LinkedList<>(); |
|
||||||
|
|
||||||
public HtmlBuilder open(String element, String data) { |
|
||||||
tags.add(element); |
|
||||||
html.append('<'); |
|
||||||
html.append(element); |
|
||||||
if (data != null) { |
|
||||||
html.append(' ').append(data); |
|
||||||
} |
|
||||||
html.append('>'); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder open(String element) { |
|
||||||
return open(element, null); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder close(String element) { |
|
||||||
html.append("</").append(element).append('>'); |
|
||||||
for (Iterator<String> iterator = tags.iterator(); iterator.hasNext(); ) { |
|
||||||
if (iterator.next().equals(element)) { |
|
||||||
iterator.remove(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder close() { |
|
||||||
if (tags.isEmpty()) { |
|
||||||
return this; |
|
||||||
} |
|
||||||
html.append("</").append(tags.removeLast()).append('>'); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder close(char element) { |
|
||||||
return close(String.valueOf(element)); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(boolean b) { |
|
||||||
html.append(b); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(char c) { |
|
||||||
html.append(c); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(int i) { |
|
||||||
html.append(i); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(long l) { |
|
||||||
html.append(l); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(float f) { |
|
||||||
html.append(f); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(double d) { |
|
||||||
html.append(d); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(Object obj) { |
|
||||||
html.append(obj); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(String str) { |
|
||||||
html.append(str); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(StringBuffer sb) { |
|
||||||
html.append(sb); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(char[] chars) { |
|
||||||
html.append(chars); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(char[] str, int offset, int len) { |
|
||||||
html.append(str, offset, len); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(CharSequence csq) { |
|
||||||
html.append(csq); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(CharSequence csq, int start, int end) { |
|
||||||
html.append(csq, start, end); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder append(Tag tag) { |
|
||||||
html.append(tag.toString()); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder a(String href, String text) { |
|
||||||
return append(String.format("<a href=\"%s\">%s</a>", href, text)); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder b() { |
|
||||||
return open("b"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder b(String text) { |
|
||||||
html.append("<b>").append(text).append("</b>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder big() { |
|
||||||
return open("big"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder big(String text) { |
|
||||||
html.append("<big>").append(text).append("</big>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder blockquote() { |
|
||||||
return open("blockquote"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder blockquote(String text) { |
|
||||||
html.append("<blockquote>").append(text).append("</blockquote>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder br() { |
|
||||||
html.append("<br>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder cite() { |
|
||||||
return open("cite"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder cite(String text) { |
|
||||||
html.append("<cite>").append(text).append("</cite>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder dfn() { |
|
||||||
return open("dfn"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder dfn(String text) { |
|
||||||
html.append("<dfn>").append(text).append("</dfn>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder div() { |
|
||||||
return open("div"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder div(String align) { |
|
||||||
html.append(String.format("<div align=\"%s\">", align)); |
|
||||||
tags.add("div"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder em() { |
|
||||||
return open("em"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder em(String text) { |
|
||||||
html.append("<em>").append(text).append("</em>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Font font() { |
|
||||||
return new Font(this); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder font(int color, String text) { |
|
||||||
return font().color(color).text(text).close(); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder font(String face, String text) { |
|
||||||
return font().face(face).text(text).close(); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h1() { |
|
||||||
return open("h1"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h1(String text) { |
|
||||||
html.append("<h1>").append(text).append("</h1>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h2() { |
|
||||||
return open("h2"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h2(String text) { |
|
||||||
html.append("<h2>").append(text).append("</h2>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h3() { |
|
||||||
return open("h3"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h3(String text) { |
|
||||||
html.append("<h3>").append(text).append("</h3>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h4() { |
|
||||||
return open("h4"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h4(String text) { |
|
||||||
html.append("<h4>").append(text).append("</h4>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h5() { |
|
||||||
return open("h5"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h5(String text) { |
|
||||||
html.append("<h5>").append(text).append("</h5>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h6() { |
|
||||||
return open("h6"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder h6(String text) { |
|
||||||
html.append("<h6>").append(text).append("</h6>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder i() { |
|
||||||
return open("i"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder i(String text) { |
|
||||||
html.append("<i>").append(text).append("</i>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img img() { |
|
||||||
return new Img(this); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder img(String src) { |
|
||||||
return img().src(src).close(); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder p() { |
|
||||||
return open("p"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder p(String text) { |
|
||||||
html.append("<p>").append(text).append("</p>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder small() { |
|
||||||
return open("small"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder small(String text) { |
|
||||||
html.append("<small>").append(text).append("</small>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder strike() { |
|
||||||
return open("strike"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder strike(String text) { |
|
||||||
html.append("<strike>").append(text).append("</strike>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder strong() { |
|
||||||
return open("strong"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder strong(String text) { |
|
||||||
html.append("<strong>").append(text).append("</strong>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder sub() { |
|
||||||
return open("sub"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder sub(String text) { |
|
||||||
html.append("<sub>").append(text).append("</sub>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder sup() { |
|
||||||
return open("sup"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder sup(String text) { |
|
||||||
html.append("<sup>").append(text).append("</sup>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder tt() { |
|
||||||
return open("tt"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder tt(String text) { |
|
||||||
html.append("<tt>").append(text).append("</tt>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder u() { |
|
||||||
return open("u"); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder u(String text) { |
|
||||||
html.append("<u>").append(text).append("</u>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N) |
|
||||||
public HtmlBuilder ul() { |
|
||||||
return open("ul"); |
|
||||||
} |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N) |
|
||||||
public HtmlBuilder li() { |
|
||||||
return open("li"); |
|
||||||
} |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N) |
|
||||||
public HtmlBuilder li(String text) { |
|
||||||
html.append("<li>").append(text).append("</li>"); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N) |
|
||||||
public Spanned build(int flags) { |
|
||||||
return Html.fromHtml(html.toString(), flags); |
|
||||||
} |
|
||||||
|
|
||||||
public Spanned build() { |
|
||||||
//noinspection deprecation
|
|
||||||
return Html.fromHtml(html.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return html.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
public static class Tag { |
|
||||||
|
|
||||||
final HtmlBuilder builder; |
|
||||||
final String element; |
|
||||||
String separator = ""; |
|
||||||
|
|
||||||
public Tag(HtmlBuilder builder, String element) { |
|
||||||
this.builder = builder; |
|
||||||
this.element = element; |
|
||||||
open(); |
|
||||||
} |
|
||||||
|
|
||||||
protected void open() { |
|
||||||
builder.append('<').append(element).append(' '); |
|
||||||
} |
|
||||||
|
|
||||||
public HtmlBuilder close() { |
|
||||||
return builder.append("</").append(element).append('>'); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return builder.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public static class Font extends Tag { |
|
||||||
|
|
||||||
public Font() { |
|
||||||
this(new HtmlBuilder()); |
|
||||||
} |
|
||||||
|
|
||||||
public Font(HtmlBuilder builder) { |
|
||||||
super(builder, "font"); |
|
||||||
} |
|
||||||
|
|
||||||
public Font size(int size) { |
|
||||||
builder.append(separator).append("size=\"").append(size).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Font size(String size) { |
|
||||||
builder.append(separator).append("size=\"").append(size).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Font color(int color) { |
|
||||||
return color(String.format("#%06X", (0xFFFFFF & color))); |
|
||||||
} |
|
||||||
|
|
||||||
public Font color(String color) { |
|
||||||
builder.append(separator).append("color=\"").append(color).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Font face(String face) { |
|
||||||
builder.append(separator).append("face=\"").append(face).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Font text(String text) { |
|
||||||
builder.append('>').append(text); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public static class Img extends Tag { |
|
||||||
|
|
||||||
public Img() { |
|
||||||
this(new HtmlBuilder()); |
|
||||||
} |
|
||||||
|
|
||||||
public Img(HtmlBuilder builder) { |
|
||||||
super(builder, "img"); |
|
||||||
} |
|
||||||
|
|
||||||
public Img src(String src) { |
|
||||||
builder.append(separator).append("src=\"").append(src).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img alt(String alt) { |
|
||||||
builder.append(separator).append("alt=\"").append(alt).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img height(String height) { |
|
||||||
builder.append(separator).append("height=\"").append(height).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img height(int height) { |
|
||||||
builder.append(separator).append("height=\"").append(height).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img width(String width) { |
|
||||||
builder.append(separator).append("width=\"").append(width).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Img width(int width) { |
|
||||||
builder.append(separator).append("width=\"").append(width).append('\"'); |
|
||||||
separator = " "; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public HtmlBuilder close() { |
|
||||||
return builder.append('>'); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
<manifest package="com.android.base"> |
|
||||||
|
|
||||||
<application> |
|
||||||
|
|
||||||
</application> |
|
||||||
|
|
||||||
</manifest> |
|
@ -1,79 +0,0 @@ |
|||||||
package com.android.base.adapter; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
/** |
|
||||||
* <pre> |
|
||||||
* 注意数据源引用的替换,只有setDataSource方法会把elements替换掉之前的数据源引用,其他方法都是基于现有数据集合做删除与添加操作。 |
|
||||||
* </pre> |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Date : 2016-09-12 11:33 |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
public interface DataManager<T> { |
|
||||||
|
|
||||||
void add(T element); |
|
||||||
|
|
||||||
void addAt(int location, T element); |
|
||||||
|
|
||||||
void addItems(List<T> elements); |
|
||||||
|
|
||||||
/** |
|
||||||
* 添加元素前会使用equals方法进行比较。 |
|
||||||
* |
|
||||||
* @param elements 元素 |
|
||||||
*/ |
|
||||||
void addItemsChecked(List<T> elements); |
|
||||||
|
|
||||||
void addItemsAt(int location, List<T> elements); |
|
||||||
|
|
||||||
void replace(T oldElement, T newElement); |
|
||||||
|
|
||||||
void replaceAt(int index, T element); |
|
||||||
|
|
||||||
/** |
|
||||||
* 清除之前集合中的数据,然后把elements添加到之前的集合中,不会使用elements作为数据源 |
|
||||||
* |
|
||||||
* @param elements 元素 |
|
||||||
*/ |
|
||||||
void replaceAll(List<T> elements); |
|
||||||
|
|
||||||
/** |
|
||||||
* 此方法会使用 newDataSource 替换掉之前的数据源,而不对之前的数据源做任何操作。 |
|
||||||
* |
|
||||||
* @param newDataSource 新的数据集 |
|
||||||
* @param notifyDataSetChanged 是否调用adapter的notifyDataSetChanged方法 |
|
||||||
*/ |
|
||||||
void setDataSource(List<T> newDataSource, boolean notifyDataSetChanged); |
|
||||||
|
|
||||||
void remove(T element); |
|
||||||
|
|
||||||
void removeAt(int index); |
|
||||||
|
|
||||||
void removeItems(List<T> elements); |
|
||||||
|
|
||||||
void removeItems(List<T> elements, boolean isSuccessive); |
|
||||||
|
|
||||||
@Nullable |
|
||||||
T getItem(int position); |
|
||||||
|
|
||||||
List<T> getItems(); |
|
||||||
|
|
||||||
int getDataSize(); |
|
||||||
|
|
||||||
boolean contains(T element); |
|
||||||
|
|
||||||
boolean isEmpty(); |
|
||||||
|
|
||||||
void clear(); |
|
||||||
|
|
||||||
/** |
|
||||||
* @param t element |
|
||||||
* @return -1 if not contains this element |
|
||||||
*/ |
|
||||||
int indexItem(T t); |
|
||||||
|
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
package com.android.base.adapter; |
|
||||||
|
|
||||||
import android.util.SparseArray; |
|
||||||
import android.view.View; |
|
||||||
import android.widget.TextView; |
|
||||||
|
|
||||||
import androidx.annotation.IdRes; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.StringRes; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email :1169654504@qq.com |
|
||||||
* Date :015-12-29 20:47 |
|
||||||
*/ |
|
||||||
public class ItemHelper { |
|
||||||
|
|
||||||
private View mItemView; |
|
||||||
private SparseArray<View> views; |
|
||||||
|
|
||||||
public ItemHelper(View itemView) { |
|
||||||
mItemView = itemView; |
|
||||||
views = new SparseArray<>(); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked,WeakerAccess") |
|
||||||
public <T extends View> T getView(int viewId) { |
|
||||||
View view = views.get(viewId); |
|
||||||
if (view == null) { |
|
||||||
view = mItemView.findViewById(viewId); |
|
||||||
views.put(viewId, view); |
|
||||||
} |
|
||||||
return (T) view; |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper setText(CharSequence str, @IdRes int viewId) { |
|
||||||
((TextView) getView(viewId)).setText(str == null ? "" : str); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper setText(@StringRes int strId, @IdRes int viewId) { |
|
||||||
((TextView) getView(viewId)).setText(strId); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper setTag(@NonNull Object object, @IdRes int tagId, @IdRes int viewID) { |
|
||||||
View view = getView(viewID); |
|
||||||
view.setTag(tagId, object); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper setTag(@NonNull Object object, @IdRes int viewID) { |
|
||||||
View view = getView(viewID); |
|
||||||
view.setTag(object); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public <T> T getTag(@IdRes int tagId, @IdRes int viewID) { |
|
||||||
View view = getView(viewID); |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
T tag = (T) view.getTag(tagId); |
|
||||||
return tag; |
|
||||||
} |
|
||||||
|
|
||||||
public <T> T getTag(@IdRes int viewID) { |
|
||||||
View view = getView(viewID); |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
T tag = (T) view.getTag(); |
|
||||||
return tag; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,185 +0,0 @@ |
|||||||
package com.android.base.adapter.list; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.LayoutInflater; |
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewGroup; |
|
||||||
import android.widget.BaseAdapter; |
|
||||||
|
|
||||||
import com.android.base.R; |
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
/** |
|
||||||
* absListView通用的Adapter,注意:只有setDataSource才能替换原有数据源的引用。 |
|
||||||
* |
|
||||||
* @param <T> 数据模型 |
|
||||||
* @author Ztiany |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public abstract class BaseListAdapter<T, VH extends ViewHolder> extends BaseAdapter implements DataManager<T> { |
|
||||||
|
|
||||||
private final Context mContext; |
|
||||||
private final static int ITEM_ID = R.id.base_item_tag_view_id; |
|
||||||
private DataManager<T> mDataManager; |
|
||||||
private final LayoutInflater mLayoutInflater; |
|
||||||
|
|
||||||
public BaseListAdapter(@NonNull Context context) { |
|
||||||
this(context, null); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("all") |
|
||||||
public BaseListAdapter(Context context, List<T> data) { |
|
||||||
this.mContext = context; |
|
||||||
mLayoutInflater = LayoutInflater.from(context); |
|
||||||
mDataManager = new ListDataManagerImpl<>(data, this); |
|
||||||
} |
|
||||||
|
|
||||||
public Context getContext() { |
|
||||||
return mContext; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getCount() { |
|
||||||
return getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public long getItemId(int position) { |
|
||||||
return position; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public View getView(int position, View convertView, ViewGroup parent) { |
|
||||||
VH viewHolder; |
|
||||||
int type = getItemViewType(position); |
|
||||||
if (convertView == null) { |
|
||||||
viewHolder = onCreateViewHolder(mLayoutInflater, parent, type); |
|
||||||
viewHolder.mItemView.setTag(ITEM_ID, viewHolder); |
|
||||||
} else { |
|
||||||
viewHolder = (VH) convertView.getTag(ITEM_ID); |
|
||||||
} |
|
||||||
viewHolder.setPosition(position); |
|
||||||
viewHolder.setType(type); |
|
||||||
T item = getItem(position); |
|
||||||
onBindData(viewHolder, item); |
|
||||||
return viewHolder.mItemView; |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract void onBindData(@NonNull VH viewHolder, T item); |
|
||||||
|
|
||||||
@NonNull |
|
||||||
protected abstract VH onCreateViewHolder(@NonNull LayoutInflater layoutInflater, @NonNull ViewGroup parent, int type); |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemViewType(int position) { |
|
||||||
return super.getItemViewType(position); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getViewTypeCount() { |
|
||||||
return super.getViewTypeCount(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(T elem) { |
|
||||||
mDataManager.add(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, T elem) { |
|
||||||
mDataManager.addAt(location, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<T> elements) { |
|
||||||
mDataManager.addItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<T> elements) { |
|
||||||
mDataManager.addItemsChecked(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<T> elements) { |
|
||||||
mDataManager.addItemsAt(location, elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(T oldElem, T newElem) { |
|
||||||
mDataManager.replace(oldElem, newElem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, T elem) { |
|
||||||
mDataManager.replaceAt(index, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<T> elements) { |
|
||||||
mDataManager.replaceAll(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(T elem) { |
|
||||||
mDataManager.remove(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements) { |
|
||||||
mDataManager.removeItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements, boolean isSuccessive) { |
|
||||||
mDataManager.removeItems(elements, isSuccessive); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
mDataManager.removeAt(index); |
|
||||||
} |
|
||||||
|
|
||||||
@Nullable |
|
||||||
@Override |
|
||||||
public T getItem(int position) { |
|
||||||
return mDataManager.getItem(position); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getDataSize() { |
|
||||||
return mDataManager.getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(T elem) { |
|
||||||
return mDataManager.contains(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(List<T> elements, boolean notifyDataSetChanged) { |
|
||||||
mDataManager.setDataSource(elements, notifyDataSetChanged); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(T t) { |
|
||||||
return mDataManager.indexItem(t); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
mDataManager.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<T> getItems() { |
|
||||||
return mDataManager.getItems(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,191 +0,0 @@ |
|||||||
package com.android.base.adapter.list; |
|
||||||
|
|
||||||
import android.widget.BaseAdapter; |
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
import com.android.base.utils.common.Checker; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
|
|
||||||
final class ListDataManagerImpl<T> implements DataManager<T> { |
|
||||||
|
|
||||||
private List<T> mData; |
|
||||||
private BaseAdapter mBaseAdapter; |
|
||||||
|
|
||||||
ListDataManagerImpl(List<T> tList, BaseAdapter adapter) { |
|
||||||
mData = tList; |
|
||||||
mBaseAdapter = adapter; |
|
||||||
} |
|
||||||
|
|
||||||
private void checkData() { |
|
||||||
if (mData == null) { |
|
||||||
mData = new ArrayList<>(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(T elem) { |
|
||||||
checkData(); |
|
||||||
mData.add(elem); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, T elem) { |
|
||||||
checkData(); |
|
||||||
mData.add(location, elem); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<T> elements) { |
|
||||||
checkData(); |
|
||||||
mData.addAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (mData == null) { |
|
||||||
addItems(elements); |
|
||||||
return; |
|
||||||
} |
|
||||||
for (T element : elements) { |
|
||||||
if (element == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
mData.remove(element); |
|
||||||
} |
|
||||||
mData.addAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<T> elements) { |
|
||||||
checkData(); |
|
||||||
mData.addAll(location, elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(T oldElem, T newElem) { |
|
||||||
if (mData != null && mData.contains(oldElem)) { |
|
||||||
replaceAt(mData.indexOf(oldElem), newElem); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, T elem) { |
|
||||||
if (mData != null && mData.size() > index) { |
|
||||||
mData.set(index, elem); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<T> elements) { |
|
||||||
if (mData == null) { |
|
||||||
mData = new ArrayList<>(); |
|
||||||
} |
|
||||||
mData.clear(); |
|
||||||
if (elements != null) { |
|
||||||
mData.addAll(elements); |
|
||||||
} |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(List<T> newDataSource, boolean notifyDataSetChanged) { |
|
||||||
mData = newDataSource; |
|
||||||
if (notifyDataSetChanged) { |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(T elem) { |
|
||||||
if (mData != null && mData.contains(elem)) { |
|
||||||
mData.remove(elem); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements) { |
|
||||||
if (mData != null && mData.containsAll(elements)) { |
|
||||||
mData.removeAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements, boolean isSuccessive) { |
|
||||||
removeItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
if (mData != null && mData.size() > index) { |
|
||||||
mData.remove(index); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@Nullable |
|
||||||
public T getItem(int position) { |
|
||||||
if (mData != null && mData.size() > position) { |
|
||||||
return mData.get(position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getDataSize() { |
|
||||||
return mData == null ? 0 : mData.size(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(T elem) { |
|
||||||
return mData != null && mData.contains(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isEmpty() { |
|
||||||
return mData == null || mData.size() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
if (mData != null && !mData.isEmpty()) { |
|
||||||
mData.clear(); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(T t) { |
|
||||||
List<T> items = getItems(); |
|
||||||
if (items == null) { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
return items.indexOf(t); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<T> getItems() { |
|
||||||
return mData; |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyDataSetChanged() { |
|
||||||
mBaseAdapter.notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package com.android.base.adapter.list; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import com.android.base.adapter.ItemHelper; |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public class SmartViewHolder extends ViewHolder { |
|
||||||
|
|
||||||
private final ItemHelper mHelper; |
|
||||||
|
|
||||||
public SmartViewHolder(View itemView) { |
|
||||||
super(itemView); |
|
||||||
mHelper = new ItemHelper(itemView); |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper helper() { |
|
||||||
return mHelper; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,35 +0,0 @@ |
|||||||
package com.android.base.adapter.list; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
public class ViewHolder { |
|
||||||
|
|
||||||
protected final View mItemView; |
|
||||||
private int mPosition; |
|
||||||
private int mType; |
|
||||||
|
|
||||||
public ViewHolder(View itemView) { |
|
||||||
mItemView = itemView; |
|
||||||
} |
|
||||||
|
|
||||||
public int getPosition() { |
|
||||||
return mPosition; |
|
||||||
} |
|
||||||
|
|
||||||
void setPosition(int position) { |
|
||||||
mPosition = position; |
|
||||||
} |
|
||||||
|
|
||||||
public int getType() { |
|
||||||
return mType; |
|
||||||
} |
|
||||||
|
|
||||||
void setType(int type) { |
|
||||||
mType = type; |
|
||||||
} |
|
||||||
|
|
||||||
public View getItemView() { |
|
||||||
return mItemView; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,154 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.os.Build; |
|
||||||
import android.util.SparseArray; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
/** |
|
||||||
* The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of |
|
||||||
* storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the |
|
||||||
* start of a layout. By construction, they are displaying current information. At the end of |
|
||||||
* layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that |
|
||||||
* could potentially be used by the adapter to avoid allocating views unnecessarily. |
|
||||||
* <p> |
|
||||||
* This class was taken from Android's implementation of {@link android.widget.AbsListView} which |
|
||||||
* is copyrighted 2006 The Android Open Source Project. |
|
||||||
*/ |
|
||||||
public class RecycleBin { |
|
||||||
|
|
||||||
/** |
|
||||||
* Views that were on screen at the start of layout. This array is populated at the start of |
|
||||||
* layout, and at the end of layout all view in activeViews are moved to scrapViews. |
|
||||||
* Views in activeViews represent a contiguous range of Views, with position of the first |
|
||||||
* view store in mFirstActivePosition. |
|
||||||
*/ |
|
||||||
private View[] activeViews = new View[0]; |
|
||||||
private int[] activeViewTypes = new int[0]; |
|
||||||
|
|
||||||
/** Unsorted views that can be used by the adapter as a convert view. */ |
|
||||||
private SparseArray<View>[] scrapViews; |
|
||||||
|
|
||||||
private int viewTypeCount; |
|
||||||
|
|
||||||
private SparseArray<View> currentScrapViews; |
|
||||||
|
|
||||||
public void setViewTypeCount(int viewTypeCount) { |
|
||||||
if (viewTypeCount < 1) { |
|
||||||
throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); |
|
||||||
} |
|
||||||
//noinspection unchecked
|
|
||||||
SparseArray<View>[] scrapViews = new SparseArray[viewTypeCount]; |
|
||||||
for (int i = 0; i < viewTypeCount; i++) { |
|
||||||
scrapViews[i] = new SparseArray<View>(); |
|
||||||
} |
|
||||||
this.viewTypeCount = viewTypeCount; |
|
||||||
currentScrapViews = scrapViews[0]; |
|
||||||
this.scrapViews = scrapViews; |
|
||||||
} |
|
||||||
|
|
||||||
protected boolean shouldRecycleViewType(int viewType) { |
|
||||||
return viewType >= 0; |
|
||||||
} |
|
||||||
|
|
||||||
/** @return A view from the ScrapViews collection. These are unordered. */ |
|
||||||
View getScrapView(int position, int viewType) { |
|
||||||
if (viewTypeCount == 1) { |
|
||||||
return retrieveFromScrap(currentScrapViews, position); |
|
||||||
} else if (viewType >= 0 && viewType < scrapViews.length) { |
|
||||||
return retrieveFromScrap(scrapViews[viewType], position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Put a view into the ScrapViews list. These views are unordered. |
|
||||||
* |
|
||||||
* @param scrap The view to add |
|
||||||
*/ |
|
||||||
void addScrapView(View scrap, int position, int viewType) { |
|
||||||
if (viewTypeCount == 1) { |
|
||||||
currentScrapViews.put(position, scrap); |
|
||||||
} else { |
|
||||||
scrapViews[viewType].put(position, scrap); |
|
||||||
} |
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
||||||
scrap.setAccessibilityDelegate(null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** Move all views remaining in activeViews to scrapViews. */ |
|
||||||
void scrapActiveViews() { |
|
||||||
final View[] activeViews = this.activeViews; |
|
||||||
final int[] activeViewTypes = this.activeViewTypes; |
|
||||||
final boolean multipleScraps = viewTypeCount > 1; |
|
||||||
|
|
||||||
SparseArray<View> scrapViews = currentScrapViews; |
|
||||||
final int count = activeViews.length; |
|
||||||
for (int i = count - 1; i >= 0; i--) { |
|
||||||
final View victim = activeViews[i]; |
|
||||||
if (victim != null) { |
|
||||||
int whichScrap = activeViewTypes[i]; |
|
||||||
|
|
||||||
activeViews[i] = null; |
|
||||||
activeViewTypes[i] = -1; |
|
||||||
|
|
||||||
if (!shouldRecycleViewType(whichScrap)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (multipleScraps) { |
|
||||||
scrapViews = this.scrapViews[whichScrap]; |
|
||||||
} |
|
||||||
scrapViews.put(i, victim); |
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
||||||
victim.setAccessibilityDelegate(null); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pruneScrapViews(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Makes sure that the size of scrapViews does not exceed the size of activeViews. |
|
||||||
* (This can happen if an adapter does not recycle its views). |
|
||||||
*/ |
|
||||||
private void pruneScrapViews() { |
|
||||||
final int maxViews = activeViews.length; |
|
||||||
final int viewTypeCount = this.viewTypeCount; |
|
||||||
final SparseArray<View>[] scrapViews = this.scrapViews; |
|
||||||
for (int i = 0; i < viewTypeCount; ++i) { |
|
||||||
final SparseArray<View> scrapPile = scrapViews[i]; |
|
||||||
int size = scrapPile.size(); |
|
||||||
final int extras = size - maxViews; |
|
||||||
size--; |
|
||||||
for (int j = 0; j < extras; j++) { |
|
||||||
scrapPile.remove(scrapPile.keyAt(size--)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static View retrieveFromScrap(SparseArray<View> scrapViews, int position) { |
|
||||||
int size = scrapViews.size(); |
|
||||||
if (size > 0) { |
|
||||||
// See if we still have a view for this position.
|
|
||||||
for (int i = 0; i < size; i++) { |
|
||||||
int fromPosition = scrapViews.keyAt(i); |
|
||||||
View view = scrapViews.get(fromPosition); |
|
||||||
if (fromPosition == position) { |
|
||||||
scrapViews.remove(fromPosition); |
|
||||||
return view; |
|
||||||
} |
|
||||||
} |
|
||||||
int index = size - 1; |
|
||||||
View r = scrapViews.valueAt(index); |
|
||||||
scrapViews.remove(scrapViews.keyAt(index)); |
|
||||||
return r; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,118 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewGroup; |
|
||||||
import android.widget.AdapterView; |
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull; |
|
||||||
|
|
||||||
import androidx.viewpager.widget.PagerAdapter; |
|
||||||
|
|
||||||
/** |
|
||||||
* A {@link PagerAdapter} which behaves like an {@link android.widget.Adapter} with view types and view recycling. |
|
||||||
* |
|
||||||
* @see <a href='https://github.com/JakeWharton/salvage'>JakeWharton/salvage</a>
|
|
||||||
*/ |
|
||||||
public abstract class RecyclingPagerAdapter extends PagerAdapter { |
|
||||||
|
|
||||||
static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; |
|
||||||
|
|
||||||
private final RecycleBin recycleBin; |
|
||||||
|
|
||||||
public RecyclingPagerAdapter() { |
|
||||||
this(new RecycleBin()); |
|
||||||
} |
|
||||||
|
|
||||||
RecyclingPagerAdapter(RecycleBin recycleBin) { |
|
||||||
this.recycleBin = recycleBin; |
|
||||||
recycleBin.setViewTypeCount(getViewTypeCount()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void notifyDataSetChanged() { |
|
||||||
recycleBin.scrapActiveViews(); |
|
||||||
super.notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final Object instantiateItem(@NotNull ViewGroup container, int position) { |
|
||||||
int viewType = getItemViewType(position); |
|
||||||
View view = null; |
|
||||||
if (viewType != IGNORE_ITEM_VIEW_TYPE) { |
|
||||||
view = recycleBin.getScrapView(position, viewType); |
|
||||||
} |
|
||||||
view = getView(position, view, container); |
|
||||||
container.addView(view); |
|
||||||
return view; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final void destroyItem(ViewGroup container, int position, @NotNull Object object) { |
|
||||||
View view = (View) object; |
|
||||||
container.removeView(view); |
|
||||||
int viewType = getItemViewType(position); |
|
||||||
if (viewType != IGNORE_ITEM_VIEW_TYPE) { |
|
||||||
recycleBin.addScrapView(view, position, viewType); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final boolean isViewFromObject(@NotNull View view, @NotNull Object object) { |
|
||||||
return view == object; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* Returns the number of types of Views that will be created by |
|
||||||
* {@link #getView}. Each type represents a set of views that can be |
|
||||||
* converted in {@link #getView}. If the adapter always returns the same |
|
||||||
* type of View for all items, this method should return 1. |
|
||||||
* </p> |
|
||||||
* <p> |
|
||||||
* This method will only be called when when the adapter is set on the |
|
||||||
* the {@link AdapterView}. |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @return The number of types of Views that will be created by this adapter |
|
||||||
*/ |
|
||||||
public int getViewTypeCount() { |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get the type of View that will be created by {@link #getView} for the specified item. |
|
||||||
* |
|
||||||
* @param position The position of the item within the adapter's data set whose view type we |
|
||||||
* want. |
|
||||||
* @return An integer representing the type of View. Two views should share the same type if one |
|
||||||
* can be converted to the other in {@link #getView}. Note: Integers must be in the |
|
||||||
* range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can |
|
||||||
* also be returned. |
|
||||||
* @see #IGNORE_ITEM_VIEW_TYPE |
|
||||||
*/ |
|
||||||
@SuppressWarnings("UnusedParameters") // Argument potentially used by subclasses.
|
|
||||||
public int getItemViewType(int position) { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Get a View that displays the data at the specified position in the data set. You can either |
|
||||||
* create a View manually or inflate it from an XML layout file. When the View is inflated, the |
|
||||||
* parent View (GridView, ListView...) will apply default layout parameters unless you use |
|
||||||
* {@link android.view.LayoutInflater#inflate(int, ViewGroup, boolean)} |
|
||||||
* to specify a root view and to prevent attachment to the root. |
|
||||||
* |
|
||||||
* @param position The position of the item within the adapter's data set of the item whose view |
|
||||||
* we want. |
|
||||||
* @param convertView The old view to reuse, if possible. Note: You should check that this view |
|
||||||
* is non-null and of an appropriate type before using. If it is not possible to convert |
|
||||||
* this view to display the correct data, this method can create a new view. |
|
||||||
* Heterogeneous lists can specify their number of view types, so that this View is |
|
||||||
* always of the right type (see {@link #getViewTypeCount()} and |
|
||||||
* {@link #getItemViewType(int)}). |
|
||||||
* @param container The parent that this view will eventually be attached to |
|
||||||
* @return A View corresponding to the data at the specified position. |
|
||||||
*/ |
|
||||||
public abstract View getView(int position, View convertView, ViewGroup container); |
|
||||||
|
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
package com.android.base.adapter.pager |
|
||||||
|
|
||||||
import android.view.LayoutInflater |
|
||||||
import android.view.View |
|
||||||
import android.view.ViewGroup |
|
||||||
import kotlinx.android.extensions.LayoutContainer |
|
||||||
|
|
||||||
/** |
|
||||||
* 如果使用可缩放的 View 作为 pager,可能不适合使用此Adapter |
|
||||||
* |
|
||||||
* @param <T> 数据 |
|
||||||
* @param <VH> View Holder类型 |
|
||||||
</VH></T> */ |
|
||||||
abstract class SimpleViewPagerAdapter<T>(data: List<T>) : ViewPagerAdapter<T, KtViewHolder>(data) { |
|
||||||
|
|
||||||
override fun createViewHolder(container: ViewGroup): KtViewHolder { |
|
||||||
val layout = provideLayout(container) |
|
||||||
val itemView = if (layout is Int) { |
|
||||||
LayoutInflater.from(container.context).inflate(layout, container, false) |
|
||||||
} else { |
|
||||||
layout as View |
|
||||||
} |
|
||||||
return KtViewHolder(itemView) |
|
||||||
} |
|
||||||
|
|
||||||
/**provide a layout id or a View*/ |
|
||||||
abstract fun provideLayout(parent: ViewGroup): Any |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
class KtViewHolder(itemView: View) : ViewPagerAdapter.ViewHolder(itemView), LayoutContainer { |
|
||||||
override val containerView: View = itemView |
|
||||||
} |
|
@ -1,69 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewGroup; |
|
||||||
|
|
||||||
import com.android.base.R; |
|
||||||
import com.android.base.utils.common.Checker; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
/** |
|
||||||
* 如果使用可缩放的 View 作为 pager,可能不适合使用此 Adapter |
|
||||||
* |
|
||||||
* @param <T> 数据 |
|
||||||
* @param <VH> View Holder类型 |
|
||||||
*/ |
|
||||||
public abstract class ViewPagerAdapter<T, VH extends ViewPagerAdapter.ViewHolder> extends RecyclingPagerAdapter { |
|
||||||
|
|
||||||
private List<T> mData; |
|
||||||
|
|
||||||
public ViewPagerAdapter(@Nullable List<T> data) { |
|
||||||
mData = data; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public View getView(int position, View convertView, ViewGroup container) { |
|
||||||
VH viewHolder; |
|
||||||
if (convertView == null) { |
|
||||||
viewHolder = createViewHolder(container); |
|
||||||
} else { |
|
||||||
viewHolder = (VH) convertView.getTag(R.id.base_item_tag_view_id); |
|
||||||
} |
|
||||||
T item = getItem(position); |
|
||||||
onBindData(viewHolder, item); |
|
||||||
return viewHolder.itemView; |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract VH createViewHolder(@NonNull ViewGroup container); |
|
||||||
|
|
||||||
protected abstract void onBindData(@NonNull VH viewHolder, @NonNull T item); |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getCount() { |
|
||||||
return Checker.isEmpty(mData) ? 0 : mData.size(); |
|
||||||
} |
|
||||||
|
|
||||||
public T getItem(int position) { |
|
||||||
if (position < 0 || position >= mData.size()) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return mData.get(position); |
|
||||||
} |
|
||||||
|
|
||||||
public static class ViewHolder { |
|
||||||
|
|
||||||
public View itemView; |
|
||||||
|
|
||||||
public ViewHolder(@NonNull View itemView) { |
|
||||||
this.itemView = itemView; |
|
||||||
itemView.setTag(R.id.base_item_tag_view_id, this); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,48 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
import androidx.fragment.app.FragmentManager; |
|
||||||
import androidx.fragment.app.FragmentPagerAdapter; |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public class ViewPagerFragmentAdapter extends FragmentPagerAdapter { |
|
||||||
|
|
||||||
private final List<ViewPagerInfo> mTabs; |
|
||||||
private Context mContext; |
|
||||||
|
|
||||||
public ViewPagerFragmentAdapter(FragmentManager fragmentManager, Context context) { |
|
||||||
super(fragmentManager); |
|
||||||
mContext = context; |
|
||||||
mTabs = new ArrayList<>(); |
|
||||||
} |
|
||||||
|
|
||||||
public void setDataSource(List<ViewPagerInfo> viewPagerInfoList) { |
|
||||||
mTabs.clear(); |
|
||||||
mTabs.addAll(viewPagerInfoList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getCount() { |
|
||||||
return mTabs.size(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Fragment getItem(int position) { |
|
||||||
ViewPagerInfo viewPagerInfo = mTabs.get(position); |
|
||||||
return Fragment.instantiate(mContext, viewPagerInfo.clazz.getName(), viewPagerInfo.args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public CharSequence getPageTitle(int position) { |
|
||||||
return mTabs.get(position).title; |
|
||||||
} |
|
||||||
|
|
||||||
public List<ViewPagerInfo> getTabs() { |
|
||||||
return mTabs; |
|
||||||
} |
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.os.Bundle; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
|
|
||||||
@SuppressWarnings("all") |
|
||||||
public class ViewPagerInfo { |
|
||||||
|
|
||||||
public final Class<? extends Fragment> clazz; |
|
||||||
public final Bundle args; |
|
||||||
public final String title; |
|
||||||
|
|
||||||
public ViewPagerInfo(String title, Class<? extends Fragment> clazz, Bundle args) { |
|
||||||
this.title = title; |
|
||||||
this.clazz = clazz; |
|
||||||
this.args = args; |
|
||||||
} |
|
||||||
} |
|
@ -1,51 +0,0 @@ |
|||||||
package com.android.base.adapter.pager; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
import androidx.fragment.app.FragmentManager; |
|
||||||
import androidx.fragment.app.FragmentStatePagerAdapter; |
|
||||||
|
|
||||||
public class ViewPagerStateFragmentAdapter extends FragmentStatePagerAdapter { |
|
||||||
|
|
||||||
private final List<ViewPagerInfo> mTabs; |
|
||||||
private Context mContext; |
|
||||||
|
|
||||||
public ViewPagerStateFragmentAdapter(FragmentManager fragmentManager, Context context) { |
|
||||||
super(fragmentManager); |
|
||||||
mContext = context; |
|
||||||
mTabs = new ArrayList<>(); |
|
||||||
} |
|
||||||
|
|
||||||
public void setDataSource(List<ViewPagerInfo> viewPagerInfoList) { |
|
||||||
mTabs.clear(); |
|
||||||
mTabs.addAll(viewPagerInfoList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getCount() { |
|
||||||
return mTabs.size(); |
|
||||||
} |
|
||||||
|
|
||||||
@NotNull |
|
||||||
@Override |
|
||||||
public Fragment getItem(int position) { |
|
||||||
ViewPagerInfo viewPagerInfo = mTabs.get(position); |
|
||||||
return Fragment.instantiate(mContext, viewPagerInfo.clazz.getName(), viewPagerInfo.args); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public CharSequence getPageTitle(int position) { |
|
||||||
return mTabs.get(position).title; |
|
||||||
} |
|
||||||
|
|
||||||
protected List<ViewPagerInfo> getTabs() { |
|
||||||
return mTabs; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.recyclerview.widget.RecyclerView; |
|
||||||
|
|
||||||
/** |
|
||||||
* @see <a href='http://www.cezcb.com/2018/08/24/PagingWithHeader/'>PagingWithHeader</a>
|
|
||||||
*/ |
|
||||||
class AdapterDataObserverProxy extends RecyclerView.AdapterDataObserver { |
|
||||||
|
|
||||||
private RecyclerView.AdapterDataObserver adapterDataObserver; |
|
||||||
private int headerCount; |
|
||||||
|
|
||||||
AdapterDataObserverProxy(RecyclerView.AdapterDataObserver adapterDataObserver, int headerCount) { |
|
||||||
this.adapterDataObserver = adapterDataObserver; |
|
||||||
this.headerCount = headerCount; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onChanged() { |
|
||||||
adapterDataObserver.onChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onItemRangeChanged(int positionStart, int itemCount) { |
|
||||||
adapterDataObserver.onItemRangeChanged(positionStart + headerCount, itemCount); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) { |
|
||||||
adapterDataObserver.onItemRangeChanged(positionStart + headerCount, itemCount, payload); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onItemRangeInserted(int positionStart, int itemCount) { |
|
||||||
adapterDataObserver.onItemRangeInserted(positionStart + headerCount, itemCount); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onItemRangeRemoved(int positionStart, int itemCount) { |
|
||||||
adapterDataObserver.onItemRangeRemoved(positionStart + headerCount, itemCount); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { |
|
||||||
super.onItemRangeMoved(fromPosition + headerCount, toPosition + headerCount, itemCount); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,266 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.ViewGroup; |
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
import com.android.base.utils.common.Checker; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.concurrent.Executor; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.recyclerview.widget.AdapterListUpdateCallback; |
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig; |
|
||||||
import androidx.recyclerview.widget.AsyncListDiffer; |
|
||||||
import androidx.recyclerview.widget.DiffUtil; |
|
||||||
import androidx.recyclerview.widget.RecyclerView; |
|
||||||
|
|
||||||
/** |
|
||||||
* RecyclerView 的适配器,注意: 只有{@link #setDataSource(List, boolean)}才能替换原有数据源的引用。 |
|
||||||
* |
|
||||||
* @param <T> 当前列表使用的数据类型 |
|
||||||
* @author Ztiany |
|
||||||
* date : 2015-05-11 22:38 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public abstract class DiffRecyclerAdapter<T, VH extends ViewHolder> extends RecyclerView.Adapter<VH> implements DataManager<T> { |
|
||||||
|
|
||||||
@NonNull |
|
||||||
private Context mContext; |
|
||||||
|
|
||||||
private AsyncListDiffer<T> mAsyncListDiffer; |
|
||||||
|
|
||||||
private final int mHeaderCount; |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public DiffRecyclerAdapter(@NonNull Context context, @NonNull DiffUtil.ItemCallback<T> itemCallback, @Nullable Executor executor, int headerCount) { |
|
||||||
mContext = context; |
|
||||||
mHeaderCount = headerCount; |
|
||||||
|
|
||||||
AsyncDifferConfig.Builder<T> tBuilder = new AsyncDifferConfig.Builder<>(itemCallback); |
|
||||||
if (executor != null) { |
|
||||||
tBuilder.setBackgroundThreadExecutor(executor); |
|
||||||
} |
|
||||||
AsyncDifferConfig<T> differConfig = tBuilder.build(); |
|
||||||
|
|
||||||
mAsyncListDiffer = new AsyncListDiffer<>(new AdapterListUpdateCallback(this), differConfig); |
|
||||||
} |
|
||||||
|
|
||||||
public DiffRecyclerAdapter(@NonNull Context context, @NonNull DiffUtil.ItemCallback<T> itemCallback, int headerCount) { |
|
||||||
this(context, itemCallback, null, headerCount); |
|
||||||
} |
|
||||||
|
|
||||||
public DiffRecyclerAdapter(@NonNull Context context, @NonNull DiffUtil.ItemCallback<T> itemCallback) { |
|
||||||
this(context, itemCallback, null, 0); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void registerAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) { |
|
||||||
if (mHeaderCount != 0) { |
|
||||||
super.registerAdapterDataObserver(new AdapterDataObserverProxy(observer, mHeaderCount)); |
|
||||||
} else { |
|
||||||
super.registerAdapterDataObserver(observer); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
public Context getContext() { |
|
||||||
return mContext; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemCount() { |
|
||||||
return getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
@Override |
|
||||||
public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType); |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) { |
|
||||||
super.onBindViewHolder(holder, position, payloads); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onBindViewHolder(@NonNull VH viewHolder, int position); |
|
||||||
|
|
||||||
public void notifyEntryChanged(T t) { |
|
||||||
int itemPosition = indexItem(t); |
|
||||||
if (itemPosition != -1) { |
|
||||||
notifyItemChanged(itemPosition); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(T element) { |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.add(element); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, T element) { |
|
||||||
if (location > getDataSize()) { |
|
||||||
location = getDataSize(); |
|
||||||
} |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.add(location, element); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.addAll(elements); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
List<T> newList = newList(); |
|
||||||
|
|
||||||
for (T element : elements) { |
|
||||||
if (element == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
newList.remove(element); |
|
||||||
} |
|
||||||
|
|
||||||
newList.addAll(elements); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
List<T> newList = newList(); |
|
||||||
|
|
||||||
if (location > newList.size()) { |
|
||||||
location = newList.size(); |
|
||||||
} |
|
||||||
|
|
||||||
newList.addAll(location, elements); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(T oldElement, T newElement) { |
|
||||||
if (!contains(oldElement)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.set(newList.indexOf(oldElement), newElement); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, T element) { |
|
||||||
if (getDataSize() > index) { |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.set(index, element); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<T> elements) { |
|
||||||
List<T> newList = new ArrayList<>(elements); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(T element) { |
|
||||||
if (contains(element)) { |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.remove(element); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements) || isEmpty() || !getItems().containsAll(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.removeAll(elements); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements, boolean isSuccessive) { |
|
||||||
removeItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
if (getDataSize() > index) { |
|
||||||
List<T> newList = newList(); |
|
||||||
newList.remove(index); |
|
||||||
mAsyncListDiffer.submitList(newList); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public T getItem(int position) { |
|
||||||
return getDataSize() > position ? getItems().get(position) : null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getDataSize() { |
|
||||||
return getItems() == null ? 0 : getItems().size(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(T element) { |
|
||||||
return !isEmpty() && getItems().contains(element); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
mAsyncListDiffer.submitList(null); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(List<T> elements, boolean notifyDataSetChanged) { |
|
||||||
mAsyncListDiffer.submitList(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<T> getItems() { |
|
||||||
return mAsyncListDiffer.getCurrentList(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isEmpty() { |
|
||||||
return getDataSize() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(T t) { |
|
||||||
return isEmpty() ? -1 : getItems().indexOf(t); |
|
||||||
} |
|
||||||
|
|
||||||
private List<T> newList() { |
|
||||||
if (getItems() == null) { |
|
||||||
return new ArrayList<>(); |
|
||||||
} else { |
|
||||||
return new ArrayList<>(getItems()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,5 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
public interface HeaderSize { |
|
||||||
int getHeaderSize(); |
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler |
|
||||||
|
|
||||||
import android.view.LayoutInflater |
|
||||||
import android.view.View |
|
||||||
import android.view.ViewGroup |
|
||||||
import androidx.recyclerview.widget.RecyclerView |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2017-09-13 15:33 |
|
||||||
*/ |
|
||||||
abstract class ItemViewBinder<T, VH : RecyclerView.ViewHolder> : com.drakeet.multitype.ItemViewBinder<T, VH>() { |
|
||||||
|
|
||||||
protected val dataManager: MultiTypeAdapter |
|
||||||
get() = adapter as MultiTypeAdapter |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
abstract class SimpleItemViewBinder<T> : ItemViewBinder<T, KtViewHolder>() { |
|
||||||
|
|
||||||
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): KtViewHolder { |
|
||||||
val layout = provideLayout(inflater, parent) |
|
||||||
val itemView = if (layout is Int) { |
|
||||||
inflater.inflate(layout, parent, false) |
|
||||||
} else |
|
||||||
layout as View |
|
||||||
return KtViewHolder(itemView).apply { |
|
||||||
onViewHolderCreated(this) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onViewHolderCreated(viewHolder: KtViewHolder) = Unit |
|
||||||
|
|
||||||
/**provide a layout id or a View*/ |
|
||||||
abstract fun provideLayout(inflater: LayoutInflater, parent: ViewGroup): Any |
|
||||||
|
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler |
|
||||||
|
|
||||||
import android.view.View |
|
||||||
import kotlinx.android.extensions.CacheImplementation |
|
||||||
import kotlinx.android.extensions.ContainerOptions |
|
||||||
import kotlinx.android.extensions.LayoutContainer |
|
||||||
|
|
||||||
/** |
|
||||||
*@author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-11-12 17:07 |
|
||||||
*/ |
|
||||||
@ContainerOptions(cache = CacheImplementation.SPARSE_ARRAY) |
|
||||||
open class KtViewHolder(override val containerView: View) : ViewHolder(containerView), LayoutContainer |
|
@ -1,169 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @see <a href='https://github.com/drakeet/MultiType'>drakeet/MultiTypeAdapter</a>
|
|
||||||
*/ |
|
||||||
public class MultiTypeAdapter extends com.drakeet.multitype.MultiTypeAdapter implements DataManager<Object> { |
|
||||||
|
|
||||||
private final Context mContext; |
|
||||||
|
|
||||||
private RecyclerDataManagerImpl<Object> mRecyclerDataManager; |
|
||||||
|
|
||||||
public MultiTypeAdapter(Context context) { |
|
||||||
super(); |
|
||||||
mContext = context; |
|
||||||
ArrayList<Object> objects = new ArrayList<>(); |
|
||||||
mRecyclerDataManager = new RecyclerDataManagerImpl<>(objects, this); |
|
||||||
super.setItems(objects); |
|
||||||
} |
|
||||||
|
|
||||||
public MultiTypeAdapter(Context context, @NonNull List<?> items) { |
|
||||||
super(); |
|
||||||
mContext = context; |
|
||||||
ArrayList<Object> objects = new ArrayList<>(items); |
|
||||||
mRecyclerDataManager = new RecyclerDataManagerImpl<>(objects, this); |
|
||||||
super.setItems(objects); |
|
||||||
} |
|
||||||
|
|
||||||
public MultiTypeAdapter(Context context, @NonNull List<?> items, int initialCapacity) { |
|
||||||
super(items, initialCapacity); |
|
||||||
mContext = context; |
|
||||||
ArrayList<Object> objects = new ArrayList<>(items); |
|
||||||
mRecyclerDataManager = new RecyclerDataManagerImpl<>(objects, this); |
|
||||||
super.setItems(objects); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public void notifyEntryChanged(Object entry) { |
|
||||||
int itemPosition = indexItem(entry); |
|
||||||
if (itemPosition != -1) { |
|
||||||
notifyItemChanged(itemPosition); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(Object elem) { |
|
||||||
mRecyclerDataManager.add(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, Object elem) { |
|
||||||
mRecyclerDataManager.addAt(location, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<Object> elements) { |
|
||||||
mRecyclerDataManager.addItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<Object> elements) { |
|
||||||
mRecyclerDataManager.addItemsChecked(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<Object> elements) { |
|
||||||
mRecyclerDataManager.addItemsAt(location, elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(Object oldElem, Object newElem) { |
|
||||||
mRecyclerDataManager.replace(oldElem, newElem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, Object elem) { |
|
||||||
mRecyclerDataManager.replaceAt(index, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<Object> elements) { |
|
||||||
mRecyclerDataManager.replaceAll(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(@NonNull List<Object> newDataSource, boolean notifyDataSetChanged) { |
|
||||||
super.setItems(newDataSource); |
|
||||||
mRecyclerDataManager.setDataSource(newDataSource, notifyDataSetChanged); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(Object elem) { |
|
||||||
mRecyclerDataManager.remove(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
mRecyclerDataManager.removeAt(index); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<Object> elements) { |
|
||||||
mRecyclerDataManager.removeItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<Object> elements, boolean isSuccessive) { |
|
||||||
mRecyclerDataManager.removeItems(elements, isSuccessive); |
|
||||||
} |
|
||||||
|
|
||||||
@Nullable |
|
||||||
@Override |
|
||||||
public Object getItem(int position) { |
|
||||||
return mRecyclerDataManager.getItem(position); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getDataSize() { |
|
||||||
return mRecyclerDataManager.getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(Object elem) { |
|
||||||
return mRecyclerDataManager.contains(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isEmpty() { |
|
||||||
return mRecyclerDataManager.isEmpty(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
mRecyclerDataManager.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
@Override |
|
||||||
public List<Object> getItems() { |
|
||||||
return mRecyclerDataManager.getItems(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(Object o) { |
|
||||||
return mRecyclerDataManager.indexItem(o); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setItems(@NonNull List<?> items) { |
|
||||||
ArrayList<Object> objects = new ArrayList<>(items); |
|
||||||
super.setItems(objects); |
|
||||||
mRecyclerDataManager.setDataSource(objects, true); |
|
||||||
} |
|
||||||
|
|
||||||
public Context getContext() { |
|
||||||
return mContext; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,177 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.ViewGroup; |
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.recyclerview.widget.RecyclerView; |
|
||||||
|
|
||||||
/** |
|
||||||
* RecyclerView 的适配器 |
|
||||||
* 注意: 只有setDataSource才能替换原有数据源的引用。 |
|
||||||
* |
|
||||||
* @param <T> 当前列表使用的数据类型 |
|
||||||
* @author Ztiany |
|
||||||
* date : 2015-05-11 22:38 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
public abstract class RecyclerAdapter<T, VH extends ViewHolder> extends RecyclerView.Adapter<VH> implements DataManager<T> { |
|
||||||
|
|
||||||
private RecyclerDataManagerImpl<T> mDataManager; |
|
||||||
|
|
||||||
@NonNull |
|
||||||
private final Context mContext; |
|
||||||
|
|
||||||
public RecyclerAdapter(@NonNull Context context, List<T> data) { |
|
||||||
mDataManager = new RecyclerDataManagerImpl<>(data, this); |
|
||||||
this.mContext = context; |
|
||||||
} |
|
||||||
|
|
||||||
public RecyclerAdapter(@NonNull Context context) { |
|
||||||
this(context, null); |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
public Context getContext() { |
|
||||||
return mContext; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemCount() { |
|
||||||
return getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
@Override |
|
||||||
public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType); |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) { |
|
||||||
super.onBindViewHolder(holder, position, payloads); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onBindViewHolder(@NonNull VH viewHolder, int position); |
|
||||||
|
|
||||||
public void notifyEntryChanged(T t) { |
|
||||||
int itemPosition = indexItem(t); |
|
||||||
if (itemPosition != -1) { |
|
||||||
notifyItemChanged(itemPosition); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// DataManager
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(T elem) { |
|
||||||
mDataManager.add(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, T elem) { |
|
||||||
mDataManager.addAt(location, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<T> elements) { |
|
||||||
mDataManager.addItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<T> elements) { |
|
||||||
mDataManager.addItemsChecked(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<T> elements) { |
|
||||||
mDataManager.addItemsAt(location, elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(T oldElem, T newElem) { |
|
||||||
mDataManager.replace(oldElem, newElem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, T elem) { |
|
||||||
mDataManager.replaceAt(index, elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<T> elements) { |
|
||||||
mDataManager.replaceAll(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(T elem) { |
|
||||||
mDataManager.remove(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements) { |
|
||||||
mDataManager.removeItems(elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements, boolean isSuccessive) { |
|
||||||
mDataManager.removeItems(elements, isSuccessive); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
mDataManager.removeAt(index); |
|
||||||
} |
|
||||||
|
|
||||||
@Nullable |
|
||||||
@Override |
|
||||||
public T getItem(int position) { |
|
||||||
return mDataManager.getItem(position); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getDataSize() { |
|
||||||
return mDataManager.getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(T elem) { |
|
||||||
return mDataManager.contains(elem); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
mDataManager.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(List<T> elements, boolean notifyDataSetChanged) { |
|
||||||
mDataManager.setDataSource(elements, notifyDataSetChanged); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<T> getItems() { |
|
||||||
return mDataManager.getItems(); |
|
||||||
} |
|
||||||
|
|
||||||
protected final void setHeaderSize(HeaderSize headerSize) { |
|
||||||
mDataManager.setHeaderSize(headerSize); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isEmpty() { |
|
||||||
return mDataManager.isEmpty(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(T t) { |
|
||||||
return mDataManager.indexItem(t); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,272 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
import com.android.base.utils.common.Checker; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView; |
|
||||||
|
|
||||||
|
|
||||||
final class RecyclerDataManagerImpl<T> implements DataManager<T> { |
|
||||||
|
|
||||||
private List<T> mData; |
|
||||||
private RecyclerView.Adapter mAdapter; |
|
||||||
private HeaderSize mHeaderSize; |
|
||||||
|
|
||||||
RecyclerDataManagerImpl(List<T> tList, RecyclerView.Adapter adapter) { |
|
||||||
mData = tList; |
|
||||||
mAdapter = adapter; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isEmpty() { |
|
||||||
return getDataSize() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void add(T element) { |
|
||||||
addAt(getDataSize(), element); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addAt(int location, T element) { |
|
||||||
if (mData != null) { |
|
||||||
if (mData.isEmpty()) { |
|
||||||
mData.add(element); |
|
||||||
notifyItemInserted(getHeaderSize()); |
|
||||||
} else { |
|
||||||
int size = mData.size(); |
|
||||||
int lastIndex = (location >= size ? size : location) + getHeaderSize(); |
|
||||||
mData.add(location, element); |
|
||||||
notifyItemInserted(lastIndex); |
|
||||||
} |
|
||||||
} else { |
|
||||||
mData = new ArrayList<>(); |
|
||||||
mData.add(element); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItems(List<T> elements) { |
|
||||||
addItemsAt(getDataSize(), elements); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsChecked(List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (mData == null) { |
|
||||||
addItems(elements); |
|
||||||
return; |
|
||||||
} |
|
||||||
boolean hasRemovedElements = false; |
|
||||||
for (T element : elements) { |
|
||||||
if (element == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (mData.contains(element)) { |
|
||||||
mData.remove(element); |
|
||||||
if (!hasRemovedElements) { |
|
||||||
hasRemovedElements = true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if (hasRemovedElements) { |
|
||||||
mData.addAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} else { |
|
||||||
addItems(elements); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addItemsAt(int location, List<T> elements) { |
|
||||||
if (Checker.isEmpty(elements)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (this.mData != null) { |
|
||||||
|
|
||||||
if (mData.isEmpty()) { |
|
||||||
mData.addAll(elements); |
|
||||||
notifyItemRangeInserted(getHeaderSize(), elements.size()); |
|
||||||
} else { |
|
||||||
int size = mData.size(); |
|
||||||
int lastIndex = (location >= size ? size : location) + getHeaderSize(); |
|
||||||
this.mData.addAll(location, elements); |
|
||||||
notifyItemRangeInserted(lastIndex, elements.size()); |
|
||||||
} |
|
||||||
|
|
||||||
} else { |
|
||||||
this.mData = new ArrayList<>(elements.size()); |
|
||||||
mData.addAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replace(T oldElem, T newElem) { |
|
||||||
if (mData != null && mData.contains(oldElem)) { |
|
||||||
replaceAt(mData.indexOf(oldElem), newElem); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAt(int index, T element) { |
|
||||||
if (getDataSize() > index) { |
|
||||||
mData.set(index, element); |
|
||||||
notifyItemChanged(index + getHeaderSize()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void replaceAll(List<T> elements) { |
|
||||||
if (mData == null) { |
|
||||||
mData = new ArrayList<>(); |
|
||||||
} |
|
||||||
mData.clear(); |
|
||||||
if (elements != null) { |
|
||||||
mData.addAll(elements); |
|
||||||
} |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setDataSource(List<T> newDataSource, boolean notifyDataSetChanged) { |
|
||||||
mData = newDataSource; |
|
||||||
if (notifyDataSetChanged) { |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void remove(T element) { |
|
||||||
if (mData == null || mData.isEmpty()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (mData.contains(element)) { |
|
||||||
int index = mData.indexOf(element) + getHeaderSize(); |
|
||||||
mData.remove(element); |
|
||||||
notifyItemRemoved(index); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeAt(int index) { |
|
||||||
if (getDataSize() > index) { |
|
||||||
mData.remove(index); |
|
||||||
notifyItemRemoved(index + getHeaderSize()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements) { |
|
||||||
if (!Checker.isEmpty(elements) && mData != null && mData.containsAll(elements)) { |
|
||||||
mData.removeAll(elements); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void removeItems(List<T> elements, boolean isSuccessive) { |
|
||||||
if (Checker.isEmpty(elements) || Checker.isEmpty(mData)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (!isSuccessive) { |
|
||||||
removeItems(elements); |
|
||||||
return; |
|
||||||
} |
|
||||||
T data = elements.get(0); |
|
||||||
int index = mData.indexOf(data); |
|
||||||
if (index == -1) { |
|
||||||
removeItems(elements); |
|
||||||
} else { |
|
||||||
mData.removeAll(elements); |
|
||||||
notifyItemRangeRemoved(index, elements.size()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public T getItem(int position) { |
|
||||||
position = position - getHeaderSize(); |
|
||||||
if (position >= 0 && getDataSize() > position) { |
|
||||||
return mData.get(position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getDataSize() { |
|
||||||
return mData == null ? 0 : mData.size(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean contains(T element) { |
|
||||||
return mData != null && mData.contains(element); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void clear() { |
|
||||||
if (mData != null) { |
|
||||||
mData.clear(); |
|
||||||
notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int indexItem(T t) { |
|
||||||
List<T> items = getItems(); |
|
||||||
if (items == null) { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
return items.indexOf(t); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<T> getItems() { |
|
||||||
return mData; |
|
||||||
} |
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Size
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
private int getHeaderSize() { |
|
||||||
return mHeaderSize == null ? 0 : mHeaderSize.getHeaderSize(); |
|
||||||
} |
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Adapter Call
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
private void notifyItemChanged(int position) { |
|
||||||
mAdapter.notifyItemChanged(position); |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyDataSetChanged() { |
|
||||||
mAdapter.notifyDataSetChanged(); |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyItemInserted(int position) { |
|
||||||
mAdapter.notifyItemInserted(position); |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyItemRangeInserted(int position, int size) { |
|
||||||
mAdapter.notifyItemRangeInserted(position, size); |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyItemRemoved(int index) { |
|
||||||
mAdapter.notifyItemRemoved(index); |
|
||||||
} |
|
||||||
|
|
||||||
private void notifyItemRangeRemoved(int index, int size) { |
|
||||||
mAdapter.notifyItemRangeRemoved(index, size); |
|
||||||
} |
|
||||||
|
|
||||||
void setHeaderSize(HeaderSize headerSize) { |
|
||||||
mHeaderSize = headerSize; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,41 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.view.LayoutInflater |
|
||||||
import android.view.View |
|
||||||
import android.view.ViewGroup |
|
||||||
|
|
||||||
/** |
|
||||||
* A simple way to build a simple list. If you want to build a multi type list, perhaps you need to use [MultiTypeAdapter]. |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-01-15 11:41 |
|
||||||
*/ |
|
||||||
abstract class SimpleRecyclerAdapter<T>(context: Context, data: List<T>? = null) : RecyclerAdapter<T, KtViewHolder>(context, data) { |
|
||||||
|
|
||||||
private var layoutInflater: LayoutInflater = LayoutInflater.from(context) |
|
||||||
|
|
||||||
final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KtViewHolder { |
|
||||||
val layout = provideLayout(parent, viewType) |
|
||||||
val itemView = if (layout is Int) { |
|
||||||
layoutInflater.inflate(layout, parent, false) |
|
||||||
} else |
|
||||||
layout as View |
|
||||||
return KtViewHolder(itemView).apply { |
|
||||||
onViewHolderCreated(this) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onViewHolderCreated(viewHolder: KtViewHolder) = Unit |
|
||||||
|
|
||||||
/**provide a layout id or a View*/ |
|
||||||
abstract fun provideLayout(parent: ViewGroup, viewType: Int): Any |
|
||||||
|
|
||||||
override fun onBindViewHolder(viewHolder: KtViewHolder, position: Int) { |
|
||||||
bind(viewHolder, getItem(position) ?: throw NullPointerException("SimpleRecyclerAdapter onBindViewHolder getItem return null")) |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract fun bind(viewHolder: KtViewHolder, item: T) |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import com.android.base.adapter.ItemHelper; |
|
||||||
|
|
||||||
|
|
||||||
public class SmartViewHolder extends ViewHolder { |
|
||||||
|
|
||||||
private final ItemHelper mHelper; |
|
||||||
|
|
||||||
public SmartViewHolder(View itemView) { |
|
||||||
super(itemView); |
|
||||||
mHelper = new ItemHelper(itemView); |
|
||||||
} |
|
||||||
|
|
||||||
public ItemHelper helper() { |
|
||||||
return mHelper; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
package com.android.base.adapter.recycler; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import androidx.annotation.IdRes; |
|
||||||
import androidx.recyclerview.widget.RecyclerView; |
|
||||||
|
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder { |
|
||||||
|
|
||||||
public ViewHolder(View itemView) { |
|
||||||
super(itemView); |
|
||||||
} |
|
||||||
|
|
||||||
protected Context getContext() { |
|
||||||
return itemView.getContext(); |
|
||||||
} |
|
||||||
|
|
||||||
public <V extends View> V findView(@IdRes int viewId) { |
|
||||||
return itemView.findViewById(viewId); |
|
||||||
} |
|
||||||
|
|
||||||
public ViewHolder setItemClickListener(View.OnClickListener onClickListener) { |
|
||||||
itemView.setOnClickListener(onClickListener); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
package com.android.base.app |
|
||||||
|
|
||||||
import android.app.Activity |
|
||||||
import android.content.Context |
|
||||||
import android.os.Bundle |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import androidx.fragment.app.FragmentActivity |
|
||||||
import androidx.fragment.app.FragmentManager |
|
||||||
import com.android.base.app.activity.ActivityDelegateOwner |
|
||||||
import com.android.base.app.dagger.Injectable |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
import com.android.base.interfaces.ActivityLifecycleCallbacksAdapter |
|
||||||
import dagger.android.AndroidInjection |
|
||||||
import dagger.android.support.AndroidSupportInjection |
|
||||||
|
|
||||||
internal class AndroidComponentLifecycleInjector : ActivityLifecycleCallbacksAdapter { |
|
||||||
|
|
||||||
private var isAutoInjectEnable = false |
|
||||||
|
|
||||||
var delegateInjector: DelegateInjector? = null |
|
||||||
|
|
||||||
fun enableAutoInject() { |
|
||||||
isAutoInjectEnable = true |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) { |
|
||||||
handleAutoInjectActivity(activity) |
|
||||||
handleAutoInstallActivityDelegate(activity) |
|
||||||
if (activity is FragmentActivity) { |
|
||||||
injectFragmentLifecycle(activity) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private fun injectFragmentLifecycle(activity: FragmentActivity) { |
|
||||||
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() { |
|
||||||
override fun onFragmentAttached(fm: FragmentManager, fragment: Fragment, context: Context) { |
|
||||||
handleAutoInjectFragment(fragment) |
|
||||||
handleAutoInstallFragmentDelegate(fragment) |
|
||||||
} |
|
||||||
}, true) |
|
||||||
} |
|
||||||
|
|
||||||
private fun handleAutoInstallFragmentDelegate(fragment: Fragment) { |
|
||||||
if (fragment is FragmentDelegateOwner) { |
|
||||||
delegateInjector?.injectFragmentDelegate(fragment) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private fun handleAutoInstallActivityDelegate(activity: Activity?) { |
|
||||||
if (activity is ActivityDelegateOwner) { |
|
||||||
delegateInjector?.injectActivityDelegate(activity) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private fun handleAutoInjectActivity(activity: Activity?) { |
|
||||||
if (isAutoInjectEnable && activity is Injectable) { |
|
||||||
AndroidInjection.inject(activity) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private fun handleAutoInjectFragment(fragment: Fragment) { |
|
||||||
if (isAutoInjectEnable && fragment is Injectable) { |
|
||||||
AndroidSupportInjection.inject(fragment) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,80 +0,0 @@ |
|||||||
package com.android.base.app |
|
||||||
|
|
||||||
import android.app.Activity |
|
||||||
import android.app.Application |
|
||||||
import android.content.Context |
|
||||||
import android.content.IntentFilter |
|
||||||
import android.content.res.Configuration |
|
||||||
import android.net.ConnectivityManager |
|
||||||
import com.android.base.app.utils.CrashHandler |
|
||||||
import com.android.base.receiver.NetStateReceiver |
|
||||||
import com.android.base.utils.BaseUtils |
|
||||||
import com.blankj.utilcode.util.AppUtils |
|
||||||
import com.blankj.utilcode.util.Utils.OnAppStatusChangedListener |
|
||||||
import io.reactivex.processors.BehaviorProcessor |
|
||||||
import timber.log.Timber |
|
||||||
import java.util.concurrent.atomic.AtomicBoolean |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-10-12 18:19 |
|
||||||
*/ |
|
||||||
internal class ApplicationDelegate internal constructor(private val androidComponentLifecycleInjector: AndroidComponentLifecycleInjector) { |
|
||||||
|
|
||||||
lateinit var application: Application |
|
||||||
|
|
||||||
private lateinit var crashHandler: CrashHandler |
|
||||||
|
|
||||||
/** 获取可观察的 app 生命周期 */ |
|
||||||
val appStatus: BehaviorProcessor<Boolean> = BehaviorProcessor.create() |
|
||||||
|
|
||||||
private val onCreateCalled = AtomicBoolean(false) |
|
||||||
private val onAttachBaseCalled = AtomicBoolean(false) |
|
||||||
|
|
||||||
fun attachBaseContext(base: Context) { |
|
||||||
check(onAttachBaseCalled.compareAndSet(false, true)) { "Can only be called once" } |
|
||||||
} |
|
||||||
|
|
||||||
fun onCreate(application: Application) { |
|
||||||
check(onCreateCalled.compareAndSet(false, true)) { "Can only be called once" } |
|
||||||
this.application = application |
|
||||||
//工具类初始化 |
|
||||||
BaseUtils.init(application) |
|
||||||
//异常日志记录 |
|
||||||
crashHandler = CrashHandler.register(application) |
|
||||||
//网络状态 |
|
||||||
application.registerReceiver(NetStateReceiver(), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) |
|
||||||
//App前台后台 |
|
||||||
listenActivityLifecycleCallbacks() |
|
||||||
//声明周期回调 |
|
||||||
application.registerActivityLifecycleCallbacks(androidComponentLifecycleInjector) |
|
||||||
} |
|
||||||
|
|
||||||
fun onTerminate() {} |
|
||||||
|
|
||||||
fun onConfigurationChanged(newConfig: Configuration) {} |
|
||||||
|
|
||||||
fun onTrimMemory(level: Int) {} |
|
||||||
|
|
||||||
fun onLowMemory() {} |
|
||||||
|
|
||||||
private fun listenActivityLifecycleCallbacks() { |
|
||||||
AppUtils.registerAppStatusChangedListener(object : OnAppStatusChangedListener { |
|
||||||
override fun onBackground(activity: Activity?) { |
|
||||||
Timber.d("app进入后台") |
|
||||||
appStatus.onNext(false) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onForeground(activity: Activity?) { |
|
||||||
Timber.d("app进入前台") |
|
||||||
appStatus.onNext(true) |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
internal fun setCrashProcessor(crashProcessor: CrashProcessor) { |
|
||||||
crashHandler.setCrashProcessor(crashProcessor) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,55 +0,0 @@ |
|||||||
package com.android.base.app |
|
||||||
|
|
||||||
import android.app.Application |
|
||||||
import android.content.Context |
|
||||||
import android.content.res.Configuration |
|
||||||
import dagger.android.DispatchingAndroidInjector |
|
||||||
import dagger.android.HasAndroidInjector |
|
||||||
import javax.inject.Inject |
|
||||||
|
|
||||||
open class BaseAppContext : Application() { |
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context) { |
|
||||||
super.attachBaseContext(base) |
|
||||||
Sword.applicationDelegate.attachBaseContext(base) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreate() { |
|
||||||
super.onCreate() |
|
||||||
Sword.applicationDelegate.onCreate(this) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onLowMemory() { |
|
||||||
super.onLowMemory() |
|
||||||
Sword.applicationDelegate.onLowMemory() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onTrimMemory(level: Int) { |
|
||||||
super.onTrimMemory(level) |
|
||||||
Sword.applicationDelegate.onTrimMemory(level) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) { |
|
||||||
super.onConfigurationChanged(newConfig) |
|
||||||
Sword.applicationDelegate.onConfigurationChanged(newConfig) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onTerminate() { |
|
||||||
super.onTerminate() |
|
||||||
Sword.applicationDelegate.onTerminate() |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
*@author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-10-12 10:59 |
|
||||||
*/ |
|
||||||
open class InjectorBaseAppContext : BaseAppContext(), HasAndroidInjector { |
|
||||||
|
|
||||||
@Inject lateinit var androidInjector: DispatchingAndroidInjector<Any> |
|
||||||
|
|
||||||
override fun androidInjector() = androidInjector |
|
||||||
|
|
||||||
} |
|
@ -1,133 +0,0 @@ |
|||||||
package com.android.base.app |
|
||||||
|
|
||||||
import android.app.Activity |
|
||||||
import android.content.Context |
|
||||||
import com.android.base.app.activity.ActivityDelegateOwner |
|
||||||
import com.android.base.app.fragment.animator.FragmentAnimator |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
import com.android.base.app.fragment.tools.FragmentConfig |
|
||||||
import com.android.base.app.ui.LoadingView |
|
||||||
import com.android.base.app.ui.PageNumber |
|
||||||
import com.android.base.app.ui.RefreshLoadViewFactory |
|
||||||
import com.android.base.app.ui.RefreshLoadViewFactory.Factory |
|
||||||
import com.android.base.app.ui.RefreshViewFactory |
|
||||||
import com.android.base.receiver.NetworkState |
|
||||||
import com.blankj.utilcode.util.ActivityUtils |
|
||||||
import com.blankj.utilcode.util.AppUtils |
|
||||||
import io.reactivex.Flowable |
|
||||||
import io.reactivex.plugins.RxJavaPlugins |
|
||||||
import timber.log.Timber |
|
||||||
|
|
||||||
/** |
|
||||||
* useful tools for android development, just like a sword. |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-04-16 17:12 |
|
||||||
*/ |
|
||||||
object Sword { |
|
||||||
|
|
||||||
private val androidComponentLifecycleInjector = AndroidComponentLifecycleInjector() |
|
||||||
|
|
||||||
/** Application lifecycle delegate */ |
|
||||||
internal val applicationDelegate = ApplicationDelegate(androidComponentLifecycleInjector) |
|
||||||
|
|
||||||
/** 错误类型分类器 */ |
|
||||||
var errorClassifier: ErrorClassifier? = null |
|
||||||
|
|
||||||
/** dialog 最小展示时间 */ |
|
||||||
var minimumShowingDialogMills: Long = 0 |
|
||||||
|
|
||||||
/** 用于创建 LoadingView*/ |
|
||||||
var loadingViewFactory: ((Context) -> LoadingView)? = null |
|
||||||
|
|
||||||
/**网络状态监听器*/ |
|
||||||
fun networkState(): Flowable<NetworkState> = NetworkState.observableState() |
|
||||||
|
|
||||||
fun setCrashProcessor(crashProcessor: CrashProcessor): Sword { |
|
||||||
applicationDelegate.setCrashProcessor(crashProcessor) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun setDefaultPageStart(pageStart: Int): Sword { |
|
||||||
PageNumber.setDefaultPageStart(pageStart) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun setDefaultPageSize(defaultPageSize: Int): Sword { |
|
||||||
PageNumber.setDefaultPageSize(defaultPageSize) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
/** 设置一个默认的布局 id,在使用 Fragments 中相关方法时,如果没有传入特定的容器 id 时,则使用设置的默认布局 id。 */ |
|
||||||
fun setDefaultFragmentContainerId(defaultContainerId: Int): Sword { |
|
||||||
FragmentConfig.setDefaultContainerId(defaultContainerId) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
/**设置默认的 Fragment 转场动画*/ |
|
||||||
fun setDefaultFragmentAnimator(animator: FragmentAnimator?): Sword { |
|
||||||
FragmentConfig.setDefaultFragmentAnimator(animator) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
/** RxJava2的一个重要的设计理念是:不吃掉任何一个异常。产生的问题是,当RxJava2“downStream”取消订阅后,“upStream”仍有可能抛出异常,这时由于已经取消订阅, |
|
||||||
* “downStream”无法处理异常,此时的异常无人处理,便会导致程序崩溃,解决方案:在Application设置RxJavaPlugin的ErrorHandler。 |
|
||||||
* refer: [RxJava2使用过程中遇到的坑](https://github.com/qqiabc521/blog/issues/3) */ |
|
||||||
fun setupRxJavaErrorHandler(): Sword { |
|
||||||
RxJavaPlugins.setErrorHandler { |
|
||||||
Timber.d("RxJavaPlugins error handler receives error: $it") |
|
||||||
} |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun enableAutoInject(): Sword { |
|
||||||
androidComponentLifecycleInjector.enableAutoInject() |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun setDelegateInjector(delegateInjector: DelegateInjector): Sword { |
|
||||||
androidComponentLifecycleInjector.delegateInjector = delegateInjector |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
/** 获取可观察的 app 生命周期,发射 tue 表示 app 切换到前台,发射 false 表示 app 切换到后台 */ |
|
||||||
val appState: Flowable<Boolean> |
|
||||||
get() = applicationDelegate.appStatus |
|
||||||
|
|
||||||
/** 获取当前 resume 的 Activity */ |
|
||||||
val topActivity: Activity? |
|
||||||
get() = ActivityUtils.getTopActivity() |
|
||||||
|
|
||||||
/** App是否在前台运行 */ |
|
||||||
val isForeground: Boolean |
|
||||||
get() = AppUtils.isAppForeground() |
|
||||||
|
|
||||||
fun registerRefreshLoadViewFactory(factory: Factory): Sword { |
|
||||||
RefreshLoadViewFactory.registerFactory(factory) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun registerRefreshViewFactory(factory: RefreshViewFactory.Factory): Sword { |
|
||||||
RefreshViewFactory.registerFactory(factory) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
interface CrashProcessor { |
|
||||||
fun uncaughtException(thread: Thread, ex: Throwable) |
|
||||||
} |
|
||||||
|
|
||||||
interface ErrorClassifier { |
|
||||||
fun isNetworkError(throwable: Throwable): Boolean |
|
||||||
fun isServerError(throwable: Throwable): Boolean |
|
||||||
} |
|
||||||
|
|
||||||
interface DelegateInjector { |
|
||||||
|
|
||||||
fun injectFragmentDelegate(fragment: FragmentDelegateOwner) |
|
||||||
|
|
||||||
fun injectActivityDelegate(activity: ActivityDelegateOwner) |
|
||||||
|
|
||||||
} |
|
@ -1,79 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (C) 2018 The Android Open Source Project |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0 |
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package com.android.base.app.aac |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import androidx.fragment.app.FragmentActivity |
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver |
|
||||||
import androidx.lifecycle.Lifecycle |
|
||||||
import androidx.lifecycle.LifecycleOwner |
|
||||||
import kotlin.properties.ReadWriteProperty |
|
||||||
import kotlin.reflect.KProperty |
|
||||||
|
|
||||||
class AutoClearedValue<T : Any>( |
|
||||||
lifecycle: Lifecycle, |
|
||||||
private val _event: Lifecycle.Event, |
|
||||||
private val onCleared: (() -> Unit)? |
|
||||||
) : ReadWriteProperty<Fragment, T> { |
|
||||||
|
|
||||||
private var _value: T? = null |
|
||||||
|
|
||||||
init { |
|
||||||
lifecycle.addObserver(object : DefaultLifecycleObserver { |
|
||||||
|
|
||||||
override fun onPause(owner: LifecycleOwner) { |
|
||||||
clearValue(Lifecycle.Event.ON_PAUSE) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStop(owner: LifecycleOwner) { |
|
||||||
clearValue(Lifecycle.Event.ON_STOP) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroy(owner: LifecycleOwner) { |
|
||||||
clearValue(Lifecycle.Event.ON_DESTROY) |
|
||||||
} |
|
||||||
|
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
override fun getValue(thisRef: Fragment, property: KProperty<*>): T { |
|
||||||
return _value |
|
||||||
?: throw IllegalStateException("should never call auto-cleared-value get when it might not be available") |
|
||||||
} |
|
||||||
|
|
||||||
override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) { |
|
||||||
_value = value |
|
||||||
} |
|
||||||
|
|
||||||
private fun clearValue(event: Lifecycle.Event) { |
|
||||||
if (_event == event) { |
|
||||||
_value = null |
|
||||||
onCleared?.invoke() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
fun <T : Any> Fragment.autoCleared( |
|
||||||
event: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, |
|
||||||
onCleared: (() -> Unit)? = null |
|
||||||
) = AutoClearedValue<T>(this.lifecycle, event, onCleared) |
|
||||||
|
|
||||||
fun <T : Any> FragmentActivity.autoCleared( |
|
||||||
event: Lifecycle.Event = Lifecycle.Event.ON_DESTROY, |
|
||||||
onCleared: (() -> Unit)? = null |
|
||||||
) = AutoClearedValue<T>(this.lifecycle, event, onCleared) |
|
@ -1,23 +0,0 @@ |
|||||||
package com.android.base.app.aac |
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData |
|
||||||
|
|
||||||
fun <T> MutableLiveData<T>.init(t: T): MutableLiveData<T> { |
|
||||||
this.postValue(t) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
fun <T> MutableLiveData<T>.touchOff() { |
|
||||||
this.postValue(this.value) |
|
||||||
} |
|
||||||
|
|
||||||
fun <T> MutableLiveData<List<T>>.append(list: List<T>) { |
|
||||||
val value = this.value |
|
||||||
if (value == null) { |
|
||||||
this.postValue(list) |
|
||||||
} else { |
|
||||||
val mutableList = value.toMutableList() |
|
||||||
mutableList.addAll(list) |
|
||||||
this.postValue(mutableList) |
|
||||||
} |
|
||||||
} |
|
@ -1,116 +0,0 @@ |
|||||||
package com.android.base.app.aac; |
|
||||||
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.ListIterator; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.lifecycle.LifecycleOwner; |
|
||||||
import androidx.lifecycle.MediatorLiveData; |
|
||||||
import androidx.lifecycle.Observer; |
|
||||||
import timber.log.Timber; |
|
||||||
|
|
||||||
public class SingleLiveData<T> extends MediatorLiveData<T> { |
|
||||||
|
|
||||||
private int mVersion = 0; |
|
||||||
|
|
||||||
private final List<WeakReference<ObserverWrapper<? super T>>> mWrapperObserverList = new ArrayList<>(); |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setValue(T value) { |
|
||||||
mVersion++; |
|
||||||
super.setValue(value); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { |
|
||||||
super.observe(owner, getOrNewObserver(observer, mVersion)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void observeForever(@NonNull Observer<? super T> observer) { |
|
||||||
super.observeForever(getOrNewObserver(observer, mVersion)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public void removeObserver(@NonNull Observer<? super T> observer) { |
|
||||||
if (observer instanceof ObserverWrapper) { |
|
||||||
super.removeObserver(observer); |
|
||||||
removeWrapper((ObserverWrapper) observer); |
|
||||||
Timber.d("removeObserver() called with: observer = wrapper = [" + observer + "]"); |
|
||||||
} else { |
|
||||||
ObserverWrapper<? super T> wrapper = findWrapper(observer); |
|
||||||
Timber.d("removeObserver() called with: observer = [" + observer + "], wrapper = [" + wrapper + "]"); |
|
||||||
super.removeObserver(wrapper); |
|
||||||
removeWrapper(wrapper); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void removeWrapper(ObserverWrapper observer) { |
|
||||||
ListIterator<WeakReference<ObserverWrapper<? super T>>> iterator = mWrapperObserverList.listIterator(); |
|
||||||
while (iterator.hasNext()) { |
|
||||||
WeakReference<ObserverWrapper<? super T>> next = iterator.next(); |
|
||||||
ObserverWrapper<? super T> item = next.get(); |
|
||||||
if (item == observer) { |
|
||||||
iterator.remove(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private ObserverWrapper<? super T> findWrapper(Observer<? super T> observer) { |
|
||||||
ListIterator<WeakReference<ObserverWrapper<? super T>>> iterator = mWrapperObserverList.listIterator(); |
|
||||||
|
|
||||||
ObserverWrapper<? super T> target = null; |
|
||||||
|
|
||||||
while (iterator.hasNext()) { |
|
||||||
WeakReference<ObserverWrapper<? super T>> next = iterator.next(); |
|
||||||
ObserverWrapper<? super T> item = next.get(); |
|
||||||
if (item == null) { |
|
||||||
iterator.remove(); |
|
||||||
} else if (item.mOrigin == observer) { |
|
||||||
target = item; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return target; |
|
||||||
} |
|
||||||
|
|
||||||
private Observer<? super T> getOrNewObserver(@NonNull Observer<? super T> observer, int observerVersion) { |
|
||||||
ObserverWrapper<? super T> wrapper = findWrapper(observer); |
|
||||||
|
|
||||||
if (wrapper == null) { |
|
||||||
wrapper = new ObserverWrapper<>(observerVersion, observer); |
|
||||||
mWrapperObserverList.add(new WeakReference<>(wrapper)); |
|
||||||
} |
|
||||||
|
|
||||||
Timber.d("getOrNewObserver() called with: observer = [" + observer + "], observerVersion = [" + observerVersion + "], wrapper = [" + wrapper + "]"); |
|
||||||
|
|
||||||
return wrapper; |
|
||||||
} |
|
||||||
|
|
||||||
private class ObserverWrapper<E> implements Observer<E> { |
|
||||||
|
|
||||||
private final int mObserverVersion; |
|
||||||
|
|
||||||
private final Observer<E> mOrigin; |
|
||||||
|
|
||||||
private ObserverWrapper(int observerVersion, Observer<E> origin) { |
|
||||||
mObserverVersion = observerVersion; |
|
||||||
mOrigin = origin; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onChanged(@Nullable E t) { |
|
||||||
if (mObserverVersion < mVersion && mOrigin != null) { |
|
||||||
mOrigin.onChanged(t); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,62 +0,0 @@ |
|||||||
package com.android.base.app.aac; |
|
||||||
|
|
||||||
import android.util.Log; |
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean; |
|
||||||
|
|
||||||
import androidx.annotation.MainThread; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.lifecycle.LifecycleOwner; |
|
||||||
import androidx.lifecycle.MutableLiveData; |
|
||||||
import androidx.lifecycle.Observer; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* A lifecycle-aware observable that sends only new updates after subscription, used for events like |
|
||||||
* navigation and Snackbar messages. |
|
||||||
* <p> |
|
||||||
* This avoids a common problem with events: on configuration change (like rotation) an update |
|
||||||
* can be emitted if the observer is active. This LiveData only calls the observable if there's an |
|
||||||
* explicit call to setValue() or call(). |
|
||||||
* <p> |
|
||||||
* Note that only one observer is going to be notified of changes. |
|
||||||
* |
|
||||||
* @see <a href='https://github.com/googlesamples/android-architecture/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java'>SingleLiveEvent</a>
|
|
||||||
*/ |
|
||||||
public class SingleLiveEvent<T> extends MutableLiveData<T> { |
|
||||||
|
|
||||||
private static final String TAG = "SingleLiveEvent"; |
|
||||||
|
|
||||||
private final AtomicBoolean mPending = new AtomicBoolean(false); |
|
||||||
|
|
||||||
@MainThread |
|
||||||
public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) { |
|
||||||
|
|
||||||
if (hasActiveObservers()) { |
|
||||||
Log.w(TAG, "Multiple observers registered but only one will be notified of changes."); |
|
||||||
} |
|
||||||
|
|
||||||
// Observe the internal MutableLiveData
|
|
||||||
super.observe(owner, t -> { |
|
||||||
if (mPending.compareAndSet(true, false)) { |
|
||||||
observer.onChanged(t); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
@MainThread |
|
||||||
public void setValue(@Nullable T t) { |
|
||||||
mPending.set(true); |
|
||||||
super.setValue(t); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Used for cases where T is Void, to make calls cleaner. |
|
||||||
*/ |
|
||||||
@MainThread |
|
||||||
public void call() { |
|
||||||
setValue(null); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,69 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
import android.app.Activity; |
|
||||||
import android.content.Intent; |
|
||||||
import android.os.Bundle; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Activity生命周期代理 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Date : 2016-05-06 15:04 |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public interface ActivityDelegate<T extends Activity> { |
|
||||||
|
|
||||||
default void onAttachedToActivity(@NonNull T activity) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onDetachedFromActivity() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onCreateBeforeSetContentView(@Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onCreateAfterSetContentView(@Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onSaveInstanceState(Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onStart() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onResume() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onPause() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onStop() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onDestroy() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onActivityResult(int requestCode, int resultCode, Intent data) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onRestoreInstanceState(Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onRestart() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onPostCreate(@Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onResumeFragments() { |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
|
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate; |
|
||||||
|
|
||||||
import androidx.annotation.UiThread; |
|
||||||
|
|
||||||
@UiThread |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public interface ActivityDelegateOwner { |
|
||||||
|
|
||||||
void addDelegate(ActivityDelegate fragmentDelegate); |
|
||||||
|
|
||||||
boolean removeDelegate(ActivityDelegate fragmentDelegate); |
|
||||||
|
|
||||||
ActivityDelegate findDelegate(Predicate<ActivityDelegate> predicate); |
|
||||||
|
|
||||||
ActivityState getStatus(); |
|
||||||
|
|
||||||
} |
|
@ -1,138 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
import android.content.Intent; |
|
||||||
import android.os.Bundle; |
|
||||||
|
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.annotation.UiThread; |
|
||||||
import androidx.appcompat.app.AppCompatActivity; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2016-12-20 11:43 |
|
||||||
*/ |
|
||||||
@UiThread |
|
||||||
final class ActivityDelegates { |
|
||||||
|
|
||||||
private final List<ActivityDelegate> mDelegates; |
|
||||||
private AppCompatActivity mBaseActivity; |
|
||||||
|
|
||||||
ActivityDelegates(AppCompatActivity baseActivity) { |
|
||||||
mDelegates = new ArrayList<>(4); |
|
||||||
mBaseActivity = baseActivity; |
|
||||||
} |
|
||||||
|
|
||||||
void callOnCreateBeforeSetContentView(@Nullable Bundle savedInstanceState) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onCreateBeforeSetContentView(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnCreateAfterSetContentView(@Nullable Bundle savedInstanceState) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onCreateAfterSetContentView(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnRestoreInstanceState(Bundle savedInstanceState) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onRestoreInstanceState(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnPostCreate(@Nullable Bundle savedInstanceState) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onPostCreate(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnSaveInstanceState(Bundle outState) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onSaveInstanceState(outState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnDestroy() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onDestroy(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnStop() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onStop(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnPause() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onPause(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnResume() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onResume(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnStart() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onStart(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnRestart() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onRestart(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnActivityResult(int requestCode, int resultCode, Intent data) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onActivityResult(requestCode, resultCode, data); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void callOnResumeFragments() { |
|
||||||
for (ActivityDelegate activityDelegate : mDelegates) { |
|
||||||
activityDelegate.onResumeFragments(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
void addActivityDelegate(ActivityDelegate activityDelegate) { |
|
||||||
mDelegates.add(activityDelegate); |
|
||||||
activityDelegate.onAttachedToActivity(mBaseActivity); |
|
||||||
} |
|
||||||
|
|
||||||
boolean removeActivityDelegate(ActivityDelegate activityDelegate) { |
|
||||||
boolean remove = mDelegates.remove(activityDelegate); |
|
||||||
if (remove) { |
|
||||||
activityDelegate.onDetachedFromActivity(); |
|
||||||
} |
|
||||||
return remove; |
|
||||||
} |
|
||||||
|
|
||||||
ActivityDelegate findDelegate(Predicate<ActivityDelegate> predicate) { |
|
||||||
for (ActivityDelegate delegate : mDelegates) { |
|
||||||
if (predicate.test(delegate)) { |
|
||||||
return delegate; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,11 +0,0 @@ |
|||||||
package com.android.base.app.activity |
|
||||||
|
|
||||||
enum class ActivityState { |
|
||||||
INITIALIZED, |
|
||||||
CREATE, |
|
||||||
START, |
|
||||||
RESUME, |
|
||||||
PAUSE, |
|
||||||
STOP, |
|
||||||
DESTROY |
|
||||||
} |
|
@ -1,72 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
import androidx.fragment.app.FragmentActivity; |
|
||||||
import androidx.fragment.app.FragmentManager; |
|
||||||
|
|
||||||
/** |
|
||||||
* <pre> |
|
||||||
* 1.Fragment需要自己处理BackPress事件,如果不处理,就交给子Fragment处理。都不处理则由Activity处理 |
|
||||||
* 2.BackPress的传递由低层往深层传递,同一层级的中外层中的 Fragment优先处理。 |
|
||||||
* 3.在Fragment中嵌套使用Fragment时,请使用getSupportChildFragmentManager |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public class BackHandlerHelper { |
|
||||||
|
|
||||||
/** |
|
||||||
* 将back事件分发给 FragmentManager 中管理的子Fragment,如果该 FragmentManager 中的所有Fragment都 |
|
||||||
* 没有处理back事件,则尝试 FragmentManager.popBackStack() |
|
||||||
* |
|
||||||
* @return 如果处理了back键则返回 <b>true</b> |
|
||||||
* @see #handleBackPress(Fragment) |
|
||||||
* @see #handleBackPress(FragmentActivity) |
|
||||||
*/ |
|
||||||
public static boolean handleBackPress(FragmentManager fragmentManager) { |
|
||||||
List<Fragment> fragments = fragmentManager.getFragments(); |
|
||||||
for (int i = fragments.size() - 1; i >= 0; i--) { |
|
||||||
Fragment child = fragments.get(i); |
|
||||||
if (isFragmentBackHandled(child)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 将back事件分发给Fragment中的子Fragment, |
|
||||||
* 该方法调用了 {@link #handleBackPress(FragmentManager)} |
|
||||||
* |
|
||||||
* @return 如果处理了back键则返回 <b>true</b> |
|
||||||
*/ |
|
||||||
public static boolean handleBackPress(Fragment fragment) { |
|
||||||
return handleBackPress(fragment.getChildFragmentManager()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 将back事件分发给Activity中的子Fragment, |
|
||||||
* 该方法调用了 {@link #handleBackPress(FragmentManager)} |
|
||||||
* |
|
||||||
* @return 如果处理了back键则返回 <b>true</b> |
|
||||||
*/ |
|
||||||
public static boolean handleBackPress(FragmentActivity fragmentActivity) { |
|
||||||
return handleBackPress(fragmentActivity.getSupportFragmentManager()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断Fragment是否处理了Back键 |
|
||||||
* |
|
||||||
* @return 如果处理了back键则返回 <b>true</b> |
|
||||||
*/ |
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public static boolean isFragmentBackHandled(Fragment fragment) { |
|
||||||
return fragment != null |
|
||||||
&& fragment.isVisible() |
|
||||||
&& fragment.getUserVisibleHint() //getUserVisibleHint默认情况下为true,在ViewPager中会被使用到。
|
|
||||||
&& fragment instanceof OnBackPressListener |
|
||||||
&& ((OnBackPressListener) fragment).onBackPressed(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,191 +0,0 @@ |
|||||||
package com.android.base.app.activity |
|
||||||
|
|
||||||
import android.content.Intent |
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import androidx.annotation.UiThread |
|
||||||
import androidx.appcompat.app.AppCompatActivity |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import com.android.base.rx.autodispose.AutoDisposeLifecycleOwnerEx |
|
||||||
import com.android.base.utils.android.compat.AndroidVersion |
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate |
|
||||||
import timber.log.Timber |
|
||||||
|
|
||||||
/** |
|
||||||
* 基础 BaseActivity 封装: |
|
||||||
* |
|
||||||
* 1. 封装通用流程。 |
|
||||||
* 2. [onBackPressed] 事件分发,优先交给 [Fragment] 处理。 |
|
||||||
* 3. 提供 RxJava 的生命周期绑定。 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Date : 2016-05-04 15:40 |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
abstract class BaseActivity : AppCompatActivity(), ActivityDelegateOwner, AutoDisposeLifecycleOwnerEx { |
|
||||||
|
|
||||||
@Suppress("LeakingThis") |
|
||||||
private val activityDelegates = ActivityDelegates(this) |
|
||||||
|
|
||||||
private var activityState = ActivityState.INITIALIZED |
|
||||||
|
|
||||||
private fun tag() = this.javaClass.simpleName |
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) { |
|
||||||
Timber.tag(tag()).d("---->onCreate before call super") |
|
||||||
initialize(savedInstanceState) |
|
||||||
activityDelegates.callOnCreateBeforeSetContentView(savedInstanceState) |
|
||||||
super.onCreate(savedInstanceState) |
|
||||||
Timber.tag(tag()).d("---->onCreate after call super bundle = $savedInstanceState") |
|
||||||
|
|
||||||
when (val layout = layout()) { |
|
||||||
is View -> setContentView(layout) |
|
||||||
is Int -> setContentView(layout) |
|
||||||
null -> Timber.d("layout() return null layout") |
|
||||||
else -> throw IllegalArgumentException("layout() return type no support, layout = $layout") |
|
||||||
} |
|
||||||
|
|
||||||
activityState = ActivityState.CREATE |
|
||||||
activityDelegates.callOnCreateAfterSetContentView(savedInstanceState) |
|
||||||
setupView(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRestart() { |
|
||||||
Timber.tag(tag()).d("---->onRestart before call super") |
|
||||||
super.onRestart() |
|
||||||
Timber.tag(tag()).d("---->onRestart after call super ") |
|
||||||
activityDelegates.callOnRestart() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStart() { |
|
||||||
Timber.tag(tag()).d("---->onStart before call super") |
|
||||||
super.onStart() |
|
||||||
Timber.tag(tag()).d("---->onStart after call super") |
|
||||||
activityState = ActivityState.START |
|
||||||
activityDelegates.callOnStart() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
Timber.tag(tag()).d("---->onResume before call super") |
|
||||||
super.onResume() |
|
||||||
Timber.tag(tag()).d("---->onResume after call super") |
|
||||||
activityState = ActivityState.RESUME |
|
||||||
activityDelegates.callOnResume() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPause() { |
|
||||||
Timber.tag(tag()).d("---->onPause before call super") |
|
||||||
activityState = ActivityState.PAUSE |
|
||||||
activityDelegates.callOnPause() |
|
||||||
super.onPause() |
|
||||||
Timber.tag(tag()).d("---->onPause after call super ") |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStop() { |
|
||||||
Timber.tag(tag()).d("---->onStop before call super") |
|
||||||
activityState = ActivityState.STOP |
|
||||||
activityDelegates.callOnStop() |
|
||||||
super.onStop() |
|
||||||
Timber.tag(tag()).d("---->onStop after call super") |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroy() { |
|
||||||
Timber.tag(tag()).d("---->onDestroy before call super") |
|
||||||
activityState = ActivityState.DESTROY |
|
||||||
activityDelegates.callOnDestroy() |
|
||||||
super.onDestroy() |
|
||||||
Timber.tag(tag()).d("---->onDestroy after call super") |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPostCreate(savedInstanceState: Bundle?) { |
|
||||||
super.onPostCreate(savedInstanceState) |
|
||||||
activityDelegates.callOnPostCreate(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) { |
|
||||||
super.onSaveInstanceState(outState) |
|
||||||
activityDelegates.callOnSaveInstanceState(outState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) { |
|
||||||
super.onRestoreInstanceState(savedInstanceState) |
|
||||||
activityDelegates.callOnRestoreInstanceState(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
|
||||||
super.onActivityResult(requestCode, resultCode, data) |
|
||||||
activityDelegates.callOnActivityResult(requestCode, resultCode, data) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { |
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
activityDelegates.callOnRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResumeFragments() { |
|
||||||
super.onResumeFragments() |
|
||||||
activityDelegates.callOnResumeFragments() |
|
||||||
} |
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////// |
|
||||||
// interface impl |
|
||||||
/////////////////////////////////////////////////////////////////////////// |
|
||||||
@UiThread |
|
||||||
final override fun addDelegate(activityDelegate: ActivityDelegate<*>) { |
|
||||||
activityDelegates.addActivityDelegate(activityDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
final override fun removeDelegate(activityDelegate: ActivityDelegate<*>): Boolean { |
|
||||||
return activityDelegates.removeActivityDelegate(activityDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
final override fun findDelegate(predicate: Predicate<ActivityDelegate<*>?>?): ActivityDelegate<*>? { |
|
||||||
return activityDelegates.findDelegate(predicate) |
|
||||||
} |
|
||||||
|
|
||||||
override fun getStatus(): ActivityState { |
|
||||||
return activityState |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Before call super.onCreate and setContentView |
|
||||||
* |
|
||||||
* @param savedInstanceState state |
|
||||||
*/ |
|
||||||
protected open fun initialize(savedInstanceState: Bundle?) {} |
|
||||||
|
|
||||||
/** |
|
||||||
* provide a layoutId (int) or layout (View) |
|
||||||
* |
|
||||||
* @return layoutId |
|
||||||
*/ |
|
||||||
protected abstract fun layout(): Any? |
|
||||||
|
|
||||||
/** |
|
||||||
* after setContentView |
|
||||||
*/ |
|
||||||
protected abstract fun setupView(savedInstanceState: Bundle?) |
|
||||||
|
|
||||||
override fun onBackPressed() { |
|
||||||
if (BackHandlerHelper.handleBackPress(this)) { |
|
||||||
Timber.d("onBackPressed() called but child fragment handle it") |
|
||||||
} else { |
|
||||||
superOnBackPressed() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun superOnBackPressed() { |
|
||||||
super.onBackPressed() |
|
||||||
} |
|
||||||
|
|
||||||
override fun isDestroyed(): Boolean { |
|
||||||
return if (AndroidVersion.atLeast(17)) { |
|
||||||
super.isDestroyed() |
|
||||||
} else { |
|
||||||
status === ActivityState.DESTROY |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
import com.android.base.app.dagger.Injectable; |
|
||||||
|
|
||||||
import javax.inject.Inject; |
|
||||||
|
|
||||||
import dagger.android.AndroidInjector; |
|
||||||
import dagger.android.DispatchingAndroidInjector; |
|
||||||
import dagger.android.HasAndroidInjector; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2018-11-01 |
|
||||||
*/ |
|
||||||
public abstract class InjectorBaseActivity extends BaseActivity implements Injectable, HasAndroidInjector { |
|
||||||
|
|
||||||
@Inject |
|
||||||
DispatchingAndroidInjector<Object> androidInjector; |
|
||||||
|
|
||||||
@Override |
|
||||||
public AndroidInjector<Object> androidInjector() { |
|
||||||
return androidInjector; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,13 +0,0 @@ |
|||||||
package com.android.base.app.activity; |
|
||||||
|
|
||||||
/** |
|
||||||
* Activity的返回键监听 |
|
||||||
*/ |
|
||||||
public interface OnBackPressListener { |
|
||||||
|
|
||||||
/** |
|
||||||
* @return true 表示Fragment处理back press,false表示由Activity处理 |
|
||||||
*/ |
|
||||||
boolean onBackPressed(); |
|
||||||
|
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import java.lang.annotation.Documented; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
|
|
||||||
import javax.inject.Scope; |
|
||||||
|
|
||||||
|
|
||||||
@Scope |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Documented |
|
||||||
public @interface ActivityScope { |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import java.lang.annotation.Documented; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
|
|
||||||
import javax.inject.Qualifier; |
|
||||||
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME; |
|
||||||
|
|
||||||
|
|
||||||
@Qualifier |
|
||||||
@Documented |
|
||||||
@Retention(RUNTIME) |
|
||||||
public @interface ContextType { |
|
||||||
|
|
||||||
String ACTIVITY = "Activity"; |
|
||||||
String CONTEXT = "Context"; |
|
||||||
String APPLICATION = "Application"; |
|
||||||
|
|
||||||
String value() default APPLICATION; |
|
||||||
|
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import java.lang.annotation.Documented; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
|
|
||||||
import javax.inject.Scope; |
|
||||||
|
|
||||||
|
|
||||||
@Scope |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
@Documented |
|
||||||
public @interface FragmentScope { |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import javax.inject.Provider; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2017-06-21 14:58 |
|
||||||
*/ |
|
||||||
public interface HasViewInjector { |
|
||||||
|
|
||||||
Map<Class<? extends View>, Provider<ViewComponentBuilder>> viewInjectors(); |
|
||||||
|
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
/** |
|
||||||
* 当 Activity 实现此接口时,如果需要为内部的 Fragment 提供注入容器,需要实现 HasSupportFragmentInjector,具体如下面代码: |
|
||||||
* |
|
||||||
* <pre>{@code |
|
||||||
* |
|
||||||
* class InjectableActivity implements Injectable, HasSupportFragmentInjector{ |
|
||||||
* @Inject |
|
||||||
* DispatchingAndroidInjector<Fragment> fragmentInjector; |
|
||||||
* |
|
||||||
* public AndroidInjector<Fragment> supportFragmentInjector() { |
|
||||||
* return fragmentInjector; |
|
||||||
* } |
|
||||||
* } |
|
||||||
* } |
|
||||||
* |
|
||||||
* 标记接口,用于标记此类需要被注入依赖。 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-12-11 12:38 |
|
||||||
*/ |
|
||||||
public interface Injectable { |
|
||||||
|
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import dagger.MembersInjector; |
|
||||||
|
|
||||||
/** |
|
||||||
* how to use it? refer https://github.com/Ztiany/notes/blob/master/Android/00-Code/Dagger2AndroidInjection-v2.24/README.md.
|
|
||||||
* |
|
||||||
* @param <A> |
|
||||||
*/ |
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public interface ViewComponent<A extends View> extends MembersInjector<A> { |
|
||||||
} |
|
@ -1,15 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import dagger.BindsInstance; |
|
||||||
|
|
||||||
|
|
||||||
public interface ViewComponentBuilder<T extends View, C extends ViewComponent<T>> { |
|
||||||
|
|
||||||
@BindsInstance |
|
||||||
ViewComponentBuilder bindInstance(T t); |
|
||||||
|
|
||||||
C build(); |
|
||||||
|
|
||||||
} |
|
@ -1,60 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import android.app.Application; |
|
||||||
import android.content.Context; |
|
||||||
import android.util.Log; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import javax.inject.Provider; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2017-06-21 14:55 |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public class ViewInjection { |
|
||||||
|
|
||||||
private static final String TAG = ViewInjection.class.getSimpleName(); |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public static void inject(View view) { |
|
||||||
|
|
||||||
if (null == view) { |
|
||||||
throw new NullPointerException(); |
|
||||||
} |
|
||||||
|
|
||||||
HasViewInjector hasViewInjector = findHasViewInjectors(view); |
|
||||||
|
|
||||||
Log.d(TAG, String.format("An injector for %s was found in %s", view.getClass().getCanonicalName(), hasViewInjector.getClass().getCanonicalName())); |
|
||||||
|
|
||||||
Map<Class<? extends View>, Provider<ViewComponentBuilder>> viewInjectors = hasViewInjector.viewInjectors(); |
|
||||||
Provider<ViewComponentBuilder> provider = viewInjectors.get(view.getClass()); |
|
||||||
|
|
||||||
if (provider != null) { |
|
||||||
ViewComponentBuilder viewComponentBuilder = provider.get(); |
|
||||||
viewComponentBuilder |
|
||||||
.bindInstance(view) |
|
||||||
.build() |
|
||||||
.injectMembers(view); |
|
||||||
} else { |
|
||||||
throw new NullPointerException("ViewInjection fail "); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private static HasViewInjector findHasViewInjectors(View view) { |
|
||||||
Context context = view.getContext(); |
|
||||||
if (context instanceof HasViewInjector) { |
|
||||||
return (HasViewInjector) context; |
|
||||||
} |
|
||||||
Application application = (Application) context.getApplicationContext(); |
|
||||||
if (application instanceof HasViewInjector) { |
|
||||||
return (HasViewInjector) application; |
|
||||||
} |
|
||||||
throw new IllegalArgumentException(String.format("No injector was found for %s", view.getClass().getCanonicalName())); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
import dagger.MapKey; |
|
||||||
import dagger.internal.Beta; |
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.METHOD; |
|
||||||
|
|
||||||
@Beta |
|
||||||
@MapKey |
|
||||||
@Target(METHOD) |
|
||||||
@SuppressWarnings("unused") |
|
||||||
public @interface ViewKey { |
|
||||||
Class<? extends View> value(); |
|
||||||
} |
|
@ -1,48 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
|
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import javax.inject.Inject; |
|
||||||
import javax.inject.Provider; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.lifecycle.ViewModel; |
|
||||||
import androidx.lifecycle.ViewModelProvider; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link androidx.lifecycle.AbstractSavedStateViewModelFactory} is not supported. |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-11-05 14:31 |
|
||||||
*/ |
|
||||||
public class ViewModelFactory implements ViewModelProvider.Factory { |
|
||||||
|
|
||||||
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> mCreatorMap; |
|
||||||
|
|
||||||
@Inject |
|
||||||
ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> classProviderMap) { |
|
||||||
mCreatorMap = classProviderMap; |
|
||||||
} |
|
||||||
|
|
||||||
@NonNull |
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { |
|
||||||
Provider<ViewModel> viewModelProvider = mCreatorMap.get(modelClass); |
|
||||||
if (viewModelProvider == null) { |
|
||||||
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : mCreatorMap.entrySet()) { |
|
||||||
if (modelClass.isAssignableFrom(entry.getKey())) { |
|
||||||
viewModelProvider = entry.getValue(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if (viewModelProvider != null) { |
|
||||||
return (T) viewModelProvider.get(); |
|
||||||
} |
|
||||||
throw new NullPointerException("can not find provider for " + modelClass); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel; |
|
||||||
import dagger.MapKey; |
|
||||||
import kotlin.annotation.AnnotationTarget; |
|
||||||
import kotlin.annotation.MustBeDocumented; |
|
||||||
import kotlin.annotation.Retention; |
|
||||||
import kotlin.annotation.Target; |
|
||||||
|
|
||||||
@MustBeDocumented |
|
||||||
@Target(allowedTargets = AnnotationTarget.FUNCTION) |
|
||||||
@Retention() |
|
||||||
@MapKey |
|
||||||
public @interface ViewModelKey { |
|
||||||
|
|
||||||
Class<? extends ViewModel> value(); |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModelProvider; |
|
||||||
import dagger.Binds; |
|
||||||
import dagger.Module; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link androidx.lifecycle.AbstractSavedStateViewModelFactory} is not supported. |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-11-05 16:20 |
|
||||||
*/ |
|
||||||
@Module |
|
||||||
public abstract class ViewModelModule { |
|
||||||
|
|
||||||
@Binds |
|
||||||
@ActivityScope |
|
||||||
abstract ViewModelProvider.Factory provideViewModelFactory(ViewModelFactory viewModelFactory); |
|
||||||
|
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
package com.android.base.app.dagger; |
|
||||||
|
|
||||||
import java.lang.annotation.Documented; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
|
|
||||||
import javax.inject.Scope; |
|
||||||
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2017-05-23 09:59 |
|
||||||
*/ |
|
||||||
@Scope |
|
||||||
@Documented |
|
||||||
@Retention(RUNTIME) |
|
||||||
public @interface ViewScope { |
|
||||||
} |
|
@ -1,277 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.content.Intent |
|
||||||
import android.os.Bundle |
|
||||||
import android.view.LayoutInflater |
|
||||||
import android.view.View |
|
||||||
import android.view.ViewGroup |
|
||||||
import androidx.annotation.StringRes |
|
||||||
import androidx.annotation.UiThread |
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment |
|
||||||
import com.android.base.app.Sword |
|
||||||
import com.android.base.app.activity.BackHandlerHelper |
|
||||||
import com.android.base.app.activity.OnBackPressListener |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegate |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
import com.android.base.app.ui.LoadingView |
|
||||||
import com.android.base.rx.autodispose.AutoDisposeLifecycleOwnerEx |
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate |
|
||||||
import timber.log.Timber |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
* @see [BaseFragment] |
|
||||||
*/ |
|
||||||
open class BaseDialogFragment : AppCompatDialogFragment(), LoadingView, OnBackPressListener, FragmentDelegateOwner, AutoDisposeLifecycleOwnerEx { |
|
||||||
|
|
||||||
private var loadingView: LoadingView? = null |
|
||||||
|
|
||||||
private var layoutView: View? = null |
|
||||||
|
|
||||||
/** just for cache*/ |
|
||||||
private var cachedView: View? = null |
|
||||||
|
|
||||||
@Suppress("LeakingThis") |
|
||||||
private val fragmentDelegates = FragmentDelegates(this) |
|
||||||
|
|
||||||
private var recentShowingDialogTime: Long = 0 |
|
||||||
|
|
||||||
private var _state: Bundle? = null |
|
||||||
|
|
||||||
protected val state: Bundle |
|
||||||
get() { |
|
||||||
var state = _state |
|
||||||
if (state == null) { |
|
||||||
state = Bundle() |
|
||||||
_state = state |
|
||||||
} |
|
||||||
return state |
|
||||||
} |
|
||||||
|
|
||||||
private fun tag() = this.javaClass.simpleName |
|
||||||
|
|
||||||
override fun onAttach(context: Context) { |
|
||||||
super.onAttach(context) |
|
||||||
Timber.tag(tag()).d("onAttach() called with: context = [$context]") |
|
||||||
fragmentDelegates.onAttach(context) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) { |
|
||||||
super.onCreate(savedInstanceState) |
|
||||||
_state = getInstanceState(savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onCreate savedInstanceState = $savedInstanceState") |
|
||||||
fragmentDelegates.onCreate(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
|
||||||
if (cachedView == null) { |
|
||||||
val layout = provideLayout() ?: return null |
|
||||||
if (layout is Int) { |
|
||||||
return inflater.inflate(layout, container, false).also { cachedView = it } |
|
||||||
} |
|
||||||
if (layout is View) { |
|
||||||
cachedView = layout |
|
||||||
return layout |
|
||||||
} |
|
||||||
throw IllegalArgumentException("Here you should provide a layout id or a View") |
|
||||||
} |
|
||||||
|
|
||||||
Timber.tag(tag()).d("mCachedView.parent: " + cachedView?.parent) |
|
||||||
|
|
||||||
cachedView?.run { |
|
||||||
val viewParent = parent |
|
||||||
if (viewParent != null && viewParent is ViewGroup) { |
|
||||||
viewParent.removeView(this) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return cachedView |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 使用此方法提供的布局,将只会被缓存起来,即此方法将只会被调用一次。 |
|
||||||
* |
|
||||||
* @return provide a layout id or a View |
|
||||||
*/ |
|
||||||
protected open fun provideLayout(): Any? = null |
|
||||||
|
|
||||||
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
|
||||||
super.onViewCreated(view, savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState) |
|
||||||
if (layoutView !== view) { |
|
||||||
layoutView = view |
|
||||||
internalOnViewPrepared(view, savedInstanceState) |
|
||||||
onViewPrepared(view, savedInstanceState) |
|
||||||
} |
|
||||||
fragmentDelegates.onViewCreated(view, savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
internal open fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) {} |
|
||||||
|
|
||||||
/** |
|
||||||
* View is prepared, If [androidx.fragment.app.Fragment.onCreateView] return same layout, it will be called once |
|
||||||
* |
|
||||||
* @param view view of fragment |
|
||||||
*/ |
|
||||||
protected open fun onViewPrepared(view: View, savedInstanceState: Bundle?) {} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onActivityCreated savedInstanceState = $savedInstanceState") |
|
||||||
fragmentDelegates.onActivityCreated(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStart() { |
|
||||||
super.onStart() |
|
||||||
Timber.tag(tag()).d("-->onStart") |
|
||||||
fragmentDelegates.onStart() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
super.onResume() |
|
||||||
Timber.tag(tag()).d("-->onResume") |
|
||||||
fragmentDelegates.onResume() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPause() { |
|
||||||
Timber.tag(tag()).d("-->onPause") |
|
||||||
fragmentDelegates.onPause() |
|
||||||
super.onPause() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStop() { |
|
||||||
Timber.tag(tag()).d("-->onStop") |
|
||||||
fragmentDelegates.onStop() |
|
||||||
super.onStop() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
Timber.tag(tag()).d("-->onDestroyView") |
|
||||||
fragmentDelegates.onDestroyView() |
|
||||||
super.onDestroyView() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroy() { |
|
||||||
Timber.tag(tag()).d("-->onDestroy") |
|
||||||
fragmentDelegates.onDestroy() |
|
||||||
super.onDestroy() |
|
||||||
dismissLoadingDialog() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDetach() { |
|
||||||
Timber.tag(tag()).d("-->onDetach") |
|
||||||
fragmentDelegates.onDetach() |
|
||||||
super.onDetach() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) { |
|
||||||
fragmentDelegates.onSaveInstanceState(outState) |
|
||||||
saveInstanceState(outState, _state) |
|
||||||
super.onSaveInstanceState(outState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setUserVisibleHint(isVisibleToUser: Boolean) { |
|
||||||
super.setUserVisibleHint(isVisibleToUser) |
|
||||||
Timber.tag(tag()).d("-->setUserVisibleHint ==$isVisibleToUser") |
|
||||||
fragmentDelegates.setUserVisibleHint(isVisibleToUser) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onHiddenChanged(hidden: Boolean) { |
|
||||||
super.onHiddenChanged(hidden) |
|
||||||
Timber.tag(tag()).d("-->onHiddenChanged = $hidden") |
|
||||||
fragmentDelegates.onHiddenChanged(hidden) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { |
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
fragmentDelegates.onRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
|
||||||
super.onActivityResult(requestCode, resultCode, data) |
|
||||||
fragmentDelegates.onActivityResult(requestCode, resultCode, data) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
override fun addDelegate(fragmentDelegate: FragmentDelegate<*>?) { |
|
||||||
fragmentDelegates.addDelegate(fragmentDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
override fun removeDelegate(fragmentDelegate: FragmentDelegate<*>?): Boolean { |
|
||||||
return fragmentDelegates.removeDelegate(fragmentDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
override fun findDelegate(predicate: Predicate<FragmentDelegate<*>?>?): FragmentDelegate<*>? { |
|
||||||
return fragmentDelegates.findDelegate(predicate) |
|
||||||
} |
|
||||||
|
|
||||||
final override fun onBackPressed(): Boolean { |
|
||||||
return handleBackPress() || BackHandlerHelper.handleBackPress(this) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Fragment需要自己处理BackPress事件,如果不处理,就交给子Fragment处理。都不处理则由Activity处理 |
|
||||||
*/ |
|
||||||
protected open fun handleBackPress(): Boolean { |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
private fun loadingView(): LoadingView { |
|
||||||
val loadingViewImpl = loadingView |
|
||||||
return if (loadingViewImpl != null) { |
|
||||||
loadingViewImpl |
|
||||||
} else { |
|
||||||
loadingView = onCreateLoadingView() ?: Sword.loadingViewFactory?.invoke(requireContext()) |
|
||||||
loadingView ?: throw NullPointerException("you need to config LoadingViewFactory in Sword or implement onCreateLoadingView.") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onCreateLoadingView(): LoadingView? { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog() { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(true) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(message: CharSequence, cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(message, cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(@StringRes messageId: Int, cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(messageId, cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun dismissLoadingDialog() { |
|
||||||
loadingView().dismissLoadingDialog() |
|
||||||
} |
|
||||||
|
|
||||||
override fun dismissLoadingDialog(minimumMills: Long, onDismiss: () -> Unit) { |
|
||||||
dismissDialog(recentShowingDialogTime, minimumMills, onDismiss) |
|
||||||
} |
|
||||||
|
|
||||||
override fun isLoadingDialogShowing(): Boolean { |
|
||||||
return loadingView().isLoadingDialogShowing() |
|
||||||
} |
|
||||||
|
|
||||||
override fun showMessage(message: CharSequence) { |
|
||||||
loadingView().showMessage(message) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showMessage(@StringRes messageId: Int) { |
|
||||||
loadingView().showMessage(messageId) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,295 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.content.Intent |
|
||||||
import android.os.Bundle |
|
||||||
import android.view.LayoutInflater |
|
||||||
import android.view.View |
|
||||||
import android.view.ViewGroup |
|
||||||
import android.view.animation.Animation |
|
||||||
import androidx.annotation.StringRes |
|
||||||
import androidx.annotation.UiThread |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import com.android.base.app.Sword |
|
||||||
import com.android.base.app.activity.BackHandlerHelper |
|
||||||
import com.android.base.app.activity.OnBackPressListener |
|
||||||
import com.android.base.app.fragment.animator.FragmentAnimatorHelper |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegate |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
import com.android.base.app.fragment.tools.FragmentConfig |
|
||||||
import com.android.base.app.ui.LoadingView |
|
||||||
import com.android.base.rx.autodispose.AutoDisposeLifecycleOwnerEx |
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate |
|
||||||
import timber.log.Timber |
|
||||||
|
|
||||||
/** |
|
||||||
*基础 BaseFragment 封装: |
|
||||||
* |
|
||||||
* 1. RxJava 生命周期绑定。 |
|
||||||
* 2. 返回键监听。 |
|
||||||
* 3. 显示 LoadingDialog 和 Message。 |
|
||||||
* 4. 可以添加生命周期代理。 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
open class BaseFragment : Fragment(), LoadingView, OnBackPressListener, FragmentDelegateOwner, AutoDisposeLifecycleOwnerEx { |
|
||||||
|
|
||||||
private var loadingView: LoadingView? = null |
|
||||||
|
|
||||||
private var layoutView: View? = null |
|
||||||
|
|
||||||
/** just for cache*/ |
|
||||||
private var cachedView: View? = null |
|
||||||
|
|
||||||
private var fragmentAnimatorHelper: FragmentAnimatorHelper? = null |
|
||||||
|
|
||||||
@Suppress("LeakingThis") |
|
||||||
private val fragmentDelegates = FragmentDelegates(this) |
|
||||||
|
|
||||||
private var recentShowingDialogTime: Long = 0 |
|
||||||
|
|
||||||
private var _state: Bundle? = null |
|
||||||
|
|
||||||
protected val state: Bundle |
|
||||||
get() { |
|
||||||
var state = _state |
|
||||||
if (state == null) { |
|
||||||
state = Bundle() |
|
||||||
_state = state |
|
||||||
} |
|
||||||
return state |
|
||||||
} |
|
||||||
|
|
||||||
private fun tag() = this.javaClass.simpleName |
|
||||||
|
|
||||||
override fun onAttach(context: Context) { |
|
||||||
super.onAttach(context) |
|
||||||
Timber.tag(tag()).d("onAttach() called with: context = [$context]") |
|
||||||
fragmentDelegates.onAttach(context) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) { |
|
||||||
super.onCreate(savedInstanceState) |
|
||||||
_state = getInstanceState(savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onCreate savedInstanceState = $savedInstanceState") |
|
||||||
fragmentDelegates.onCreate(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
|
||||||
if (cachedView == null) { |
|
||||||
val layout = provideLayout() ?: return null |
|
||||||
if (layout is Int) { |
|
||||||
return inflater.inflate(layout, container, false).also { cachedView = it } |
|
||||||
} |
|
||||||
if (layout is View) { |
|
||||||
cachedView = layout |
|
||||||
return layout |
|
||||||
} |
|
||||||
throw IllegalArgumentException("Here you should provide a layout id or a View") |
|
||||||
} |
|
||||||
|
|
||||||
Timber.tag(tag()).d("mCachedView.parent: " + cachedView?.parent) |
|
||||||
|
|
||||||
cachedView?.run { |
|
||||||
val viewParent = parent |
|
||||||
if (viewParent != null && viewParent is ViewGroup) { |
|
||||||
viewParent.removeView(this) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return cachedView |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 使用此方法提供的布局,将只会被缓存起来,即此方法将只会被调用一次。 |
|
||||||
* |
|
||||||
* @return provide a layout id or a View |
|
||||||
*/ |
|
||||||
protected open fun provideLayout(): Any? = null |
|
||||||
|
|
||||||
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
|
||||||
super.onViewCreated(view, savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onViewCreated savedInstanceState = %s", savedInstanceState) |
|
||||||
if (layoutView !== view) { |
|
||||||
layoutView = view |
|
||||||
internalOnViewPrepared(view, savedInstanceState) |
|
||||||
onViewPrepared(view, savedInstanceState) |
|
||||||
} |
|
||||||
fragmentDelegates.onViewCreated(view, savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
internal open fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) {} |
|
||||||
|
|
||||||
/** |
|
||||||
* View is prepared, If [androidx.fragment.app.Fragment.onCreateView] return same layout, it will be called once |
|
||||||
* |
|
||||||
* @param view view of fragment |
|
||||||
*/ |
|
||||||
protected open fun onViewPrepared(view: View, savedInstanceState: Bundle?) {} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
Timber.tag(tag()).d("-->onActivityCreated savedInstanceState = $savedInstanceState") |
|
||||||
fragmentDelegates.onActivityCreated(savedInstanceState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStart() { |
|
||||||
super.onStart() |
|
||||||
Timber.tag(tag()).d("-->onStart") |
|
||||||
fragmentDelegates.onStart() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
super.onResume() |
|
||||||
Timber.tag(tag()).d("-->onResume") |
|
||||||
fragmentDelegates.onResume() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPause() { |
|
||||||
Timber.tag(tag()).d("-->onPause") |
|
||||||
fragmentDelegates.onPause() |
|
||||||
super.onPause() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onStop() { |
|
||||||
Timber.tag(tag()).d("-->onStop") |
|
||||||
fragmentDelegates.onStop() |
|
||||||
super.onStop() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
Timber.tag(tag()).d("-->onDestroyView") |
|
||||||
fragmentDelegates.onDestroyView() |
|
||||||
super.onDestroyView() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroy() { |
|
||||||
Timber.tag(tag()).d("-->onDestroy") |
|
||||||
fragmentDelegates.onDestroy() |
|
||||||
super.onDestroy() |
|
||||||
dismissLoadingDialog() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDetach() { |
|
||||||
Timber.tag(tag()).d("-->onDetach") |
|
||||||
fragmentDelegates.onDetach() |
|
||||||
super.onDetach() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) { |
|
||||||
fragmentDelegates.onSaveInstanceState(outState) |
|
||||||
saveInstanceState(outState, _state) |
|
||||||
super.onSaveInstanceState(outState) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setUserVisibleHint(isVisibleToUser: Boolean) { |
|
||||||
super.setUserVisibleHint(isVisibleToUser) |
|
||||||
Timber.tag(tag()).d("-->setUserVisibleHint ==$isVisibleToUser") |
|
||||||
fragmentDelegates.setUserVisibleHint(isVisibleToUser) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onHiddenChanged(hidden: Boolean) { |
|
||||||
super.onHiddenChanged(hidden) |
|
||||||
Timber.tag(tag()).d("-->onHiddenChanged = $hidden") |
|
||||||
fragmentDelegates.onHiddenChanged(hidden) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { |
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
fragmentDelegates.onRequestPermissionsResult(requestCode, permissions, grantResults) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
|
||||||
super.onActivityResult(requestCode, resultCode, data) |
|
||||||
fragmentDelegates.onActivityResult(requestCode, resultCode, data) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
override fun addDelegate(fragmentDelegate: FragmentDelegate<*>?) { |
|
||||||
fragmentDelegates.addDelegate(fragmentDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
@UiThread |
|
||||||
override fun removeDelegate(fragmentDelegate: FragmentDelegate<*>?): Boolean { |
|
||||||
return fragmentDelegates.removeDelegate(fragmentDelegate) |
|
||||||
} |
|
||||||
|
|
||||||
override fun findDelegate(predicate: Predicate<FragmentDelegate<*>?>?): FragmentDelegate<*>? { |
|
||||||
return fragmentDelegates.findDelegate(predicate) |
|
||||||
} |
|
||||||
|
|
||||||
final override fun onBackPressed(): Boolean { |
|
||||||
return handleBackPress() || BackHandlerHelper.handleBackPress(this) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Fragment需要自己处理BackPress事件,如果不处理,就交给子Fragment处理。都不处理则由Activity处理 |
|
||||||
*/ |
|
||||||
protected open fun handleBackPress(): Boolean { |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
private fun loadingView(): LoadingView { |
|
||||||
val loadingViewImpl = loadingView |
|
||||||
return if (loadingViewImpl != null) { |
|
||||||
loadingViewImpl |
|
||||||
} else { |
|
||||||
loadingView = onCreateLoadingView() ?: Sword.loadingViewFactory?.invoke(requireContext()) |
|
||||||
loadingView ?: throw NullPointerException("you need to config LoadingViewFactory in Sword or implement onCreateLoadingView.") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onCreateLoadingView(): LoadingView? { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog() { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(true) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(message: CharSequence, cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(message, cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingDialog(@StringRes messageId: Int, cancelable: Boolean) { |
|
||||||
recentShowingDialogTime = System.currentTimeMillis() |
|
||||||
loadingView().showLoadingDialog(messageId, cancelable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun dismissLoadingDialog() { |
|
||||||
loadingView().dismissLoadingDialog() |
|
||||||
} |
|
||||||
|
|
||||||
override fun dismissLoadingDialog(minimumMills: Long, onDismiss: () -> Unit) { |
|
||||||
dismissDialog(recentShowingDialogTime, minimumMills, onDismiss) |
|
||||||
} |
|
||||||
|
|
||||||
override fun isLoadingDialogShowing(): Boolean { |
|
||||||
return loadingView().isLoadingDialogShowing() |
|
||||||
} |
|
||||||
|
|
||||||
override fun showMessage(message: CharSequence) { |
|
||||||
loadingView().showMessage(message) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showMessage(@StringRes messageId: Int) { |
|
||||||
loadingView().showMessage(messageId) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? { |
|
||||||
if (fragmentAnimatorHelper == null) { |
|
||||||
fragmentAnimatorHelper = FragmentAnimatorHelper(requireContext(), FragmentConfig.defaultFragmentAnimator()) |
|
||||||
} |
|
||||||
return fragmentAnimatorHelper?.onCreateAnimation(transit, enter) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,89 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import androidx.recyclerview.widget.RecyclerView.Adapter |
|
||||||
import com.android.base.adapter.DataManager |
|
||||||
import com.android.base.app.ui.AutoPageNumber |
|
||||||
import com.android.base.app.ui.PageNumber |
|
||||||
import com.android.base.app.ui.RefreshListLayout |
|
||||||
import com.ztiany.loadmore.adapter.ILoadMore |
|
||||||
import com.ztiany.loadmore.adapter.OnLoadMoreListener |
|
||||||
import com.ztiany.loadmore.adapter.WrapperAdapter |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
* @see [BaseListFragment] |
|
||||||
*/ |
|
||||||
abstract class BaseListDialogFragment<T> : BaseStateDialogFragment(), RefreshListLayout<T> { |
|
||||||
|
|
||||||
/**加载更多*/ |
|
||||||
private var loadMore: ILoadMore? = null |
|
||||||
|
|
||||||
/**列表数据管理*/ |
|
||||||
private lateinit var dataManager: DataManager<T> |
|
||||||
|
|
||||||
/**分页页码*/ |
|
||||||
private var pageNumber: PageNumber? = null |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
if (!::dataManager.isInitialized) { |
|
||||||
throw NullPointerException("you need set DataManager") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected fun setDataManager(dataManager: DataManager<T>) { |
|
||||||
this.dataManager = dataManager |
|
||||||
} |
|
||||||
|
|
||||||
protected fun setupLoadMore(recyclerAdapter: Adapter<*>, pageNumber: PageNumber = AutoPageNumber(this, dataManager)): Adapter<*> { |
|
||||||
this.pageNumber = pageNumber |
|
||||||
|
|
||||||
return WrapperAdapter.wrap(recyclerAdapter).apply { |
|
||||||
setOnLoadMoreListener(object : OnLoadMoreListener { |
|
||||||
override fun onLoadMore() { |
|
||||||
this@BaseListDialogFragment.onLoadMore() |
|
||||||
} |
|
||||||
|
|
||||||
override fun canLoadMore(): Boolean { |
|
||||||
return !isRefreshing |
|
||||||
} |
|
||||||
}) |
|
||||||
loadMore = this |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/**call by [.onRefresh] or [.onLoadMore], you can get current loading type from [.isRefreshing] or [.isLoadingMore].*/ |
|
||||||
protected open fun onStartLoad() {} |
|
||||||
|
|
||||||
override fun onRefresh() = onStartLoad() |
|
||||||
|
|
||||||
protected fun onLoadMore() = onStartLoad() |
|
||||||
|
|
||||||
override fun canRefresh() = !isLoadingMore |
|
||||||
|
|
||||||
override fun replaceData(data: List<T>) = dataManager.replaceAll(data) |
|
||||||
|
|
||||||
override fun addData(data: List<T>) = dataManager.addItems(data) |
|
||||||
|
|
||||||
override fun isEmpty(): Boolean = dataManager.isEmpty |
|
||||||
|
|
||||||
override fun isLoadingMore(): Boolean = loadMore != null && loadMore?.isLoadingMore ?: false |
|
||||||
|
|
||||||
override fun getPager(): PageNumber = pageNumber |
|
||||||
?: throw NullPointerException("you need to call setupLoadMore to init pageNumber") |
|
||||||
|
|
||||||
fun loadMoreController(): ILoadMore = loadMore |
|
||||||
?: throw NullPointerException("you need to call setupLoadMore to init loadMoreController") |
|
||||||
|
|
||||||
override fun loadMoreCompleted(hasMore: Boolean) { |
|
||||||
loadMore?.loadCompleted(hasMore) |
|
||||||
} |
|
||||||
|
|
||||||
override fun loadMoreFailed() { |
|
||||||
loadMore?.loadFail() |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,89 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import androidx.recyclerview.widget.RecyclerView.Adapter |
|
||||||
import com.android.base.adapter.DataManager |
|
||||||
import com.android.base.app.ui.AutoPageNumber |
|
||||||
import com.android.base.app.ui.PageNumber |
|
||||||
import com.android.base.app.ui.RefreshListLayout |
|
||||||
import com.ztiany.loadmore.adapter.ILoadMore |
|
||||||
import com.ztiany.loadmore.adapter.OnLoadMoreListener |
|
||||||
import com.ztiany.loadmore.adapter.WrapperAdapter |
|
||||||
|
|
||||||
/** |
|
||||||
* 通用的基于 RecyclerView 的列表界面,支持下拉刷新和加载更多。 |
|
||||||
* |
|
||||||
* @param <T> 当前列表使用的数据类型 |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
abstract class BaseListFragment<T> : BaseStateFragment(), RefreshListLayout<T> { |
|
||||||
|
|
||||||
/**加载更多*/ |
|
||||||
private var loadMore: ILoadMore? = null |
|
||||||
|
|
||||||
/**列表数据管理*/ |
|
||||||
private lateinit var dataManager: DataManager<T> |
|
||||||
|
|
||||||
/**分页页码*/ |
|
||||||
private var pageNumber: PageNumber? = null |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
if (!::dataManager.isInitialized) { |
|
||||||
throw NullPointerException("you need set DataManager") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected fun setDataManager(dataManager: DataManager<T>) { |
|
||||||
this.dataManager = dataManager |
|
||||||
} |
|
||||||
|
|
||||||
protected fun setupLoadMore(recyclerAdapter: Adapter<*>, pageNumber: PageNumber = AutoPageNumber(this, dataManager)): Adapter<*> { |
|
||||||
this.pageNumber = pageNumber |
|
||||||
|
|
||||||
return WrapperAdapter.wrap(recyclerAdapter).apply { |
|
||||||
setOnLoadMoreListener(object : OnLoadMoreListener { |
|
||||||
override fun onLoadMore() { |
|
||||||
this@BaseListFragment.onLoadMore() |
|
||||||
} |
|
||||||
|
|
||||||
override fun canLoadMore(): Boolean { |
|
||||||
return !isRefreshing |
|
||||||
} |
|
||||||
}) |
|
||||||
loadMore = this |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/**call by [.onRefresh] or [.onLoadMore], you can get current loading type from [.isRefreshing] or [.isLoadingMore].*/ |
|
||||||
protected open fun onStartLoad() {} |
|
||||||
|
|
||||||
override fun onRefresh() = onStartLoad() |
|
||||||
|
|
||||||
protected fun onLoadMore() = onStartLoad() |
|
||||||
|
|
||||||
override fun canRefresh() = !isLoadingMore |
|
||||||
|
|
||||||
override fun replaceData(data: List<T>)= dataManager.replaceAll(data) |
|
||||||
|
|
||||||
override fun addData(data: List<T>) = dataManager.addItems(data) |
|
||||||
|
|
||||||
override fun isEmpty(): Boolean = dataManager.isEmpty |
|
||||||
|
|
||||||
override fun isLoadingMore(): Boolean = loadMore != null && loadMore?.isLoadingMore ?: false |
|
||||||
|
|
||||||
override fun getPager(): PageNumber = pageNumber ?: throw NullPointerException("you need to call setupLoadMore to init pageNumber") |
|
||||||
|
|
||||||
fun loadMoreController(): ILoadMore = loadMore ?: throw NullPointerException("you need to call setupLoadMore to init loadMoreController") |
|
||||||
|
|
||||||
override fun loadMoreCompleted(hasMore: Boolean) { |
|
||||||
loadMore?.loadCompleted(hasMore) |
|
||||||
} |
|
||||||
|
|
||||||
override fun loadMoreFailed() { |
|
||||||
loadMore?.loadFail() |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,119 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import com.android.base.adapter.DataManager |
|
||||||
import com.android.base.app.ui.AutoPageNumber |
|
||||||
import com.android.base.app.ui.RefreshListLayout |
|
||||||
import com.android.base.app.ui.StateLayoutConfig |
|
||||||
|
|
||||||
/** |
|
||||||
* 区别于 [BaseListFragment] 只能支持 RecyclerView。[BaseListFragment] 采用包装 [androidx.recyclerview.widget.RecyclerView.Adapter] 的方式, |
|
||||||
* 在底部添加 load more view 的 item,来实现加载更多。[BaseListV2DialogFragment] 没有采用此种方式,所以你使用的 RefreshView 应该是支持这下来刷新和加载更多功能的。 |
|
||||||
* |
|
||||||
* 在调用 [BaseListV2DialogFragment] 的 [onActivityCreated] 之前,你应该设置好 [dataManager]。 |
|
||||||
* |
|
||||||
*@author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-03-26 15:06 |
|
||||||
*/ |
|
||||||
abstract class BaseListV2DialogFragment<T> : BaseFragment(), RefreshListLayout<T> { |
|
||||||
|
|
||||||
private lateinit var stateLayout: RefreshLoadMoreStateLayoutImpl |
|
||||||
|
|
||||||
protected open lateinit var dataManager: DataManager<T> |
|
||||||
|
|
||||||
override fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) { |
|
||||||
stateLayout = RefreshLoadMoreStateLayoutImpl.init(view) |
|
||||||
stateLayout.refreshView.setRefreshHandler { |
|
||||||
onRefresh() |
|
||||||
} |
|
||||||
stateLayout.refreshView.setLoadMoreHandler { |
|
||||||
onLoadMore() |
|
||||||
} |
|
||||||
stateLayout.setStateRetryListener(this::onRetry) |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRetry(state: Int) { |
|
||||||
if (!isRefreshing) { |
|
||||||
autoRefresh() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRefresh() = onStartLoad() |
|
||||||
|
|
||||||
protected open fun onLoadMore() = onStartLoad() |
|
||||||
|
|
||||||
/** call by [onRefresh] or [onLoadMore], you can get current loading type from [isRefreshing] or [isLoadingMore]. */ |
|
||||||
protected open fun onStartLoad() {} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
if (!::dataManager.isInitialized) { |
|
||||||
throw NullPointerException("you need set DataManager") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
super.onDestroyView() |
|
||||||
refreshCompleted() |
|
||||||
} |
|
||||||
|
|
||||||
override fun replaceData(data: MutableList<T>?) { |
|
||||||
dataManager.replaceAll(data) |
|
||||||
} |
|
||||||
|
|
||||||
override fun addData(data: MutableList<T>?) { |
|
||||||
dataManager.addItems(data) |
|
||||||
} |
|
||||||
|
|
||||||
fun setRefreshEnable(enable: Boolean) = stateLayout.refreshView.setRefreshEnable(enable) |
|
||||||
|
|
||||||
fun setLoadMoreEnable(enable: Boolean) = stateLayout.refreshView.setLoadMoreEnable(enable) |
|
||||||
|
|
||||||
override fun getPager() = AutoPageNumber(this, dataManager) |
|
||||||
|
|
||||||
override fun isEmpty() = dataManager.isEmpty |
|
||||||
|
|
||||||
override fun loadMoreCompleted(hasMore: Boolean) = stateLayout.refreshView.loadMoreCompleted(hasMore) |
|
||||||
|
|
||||||
override fun loadMoreFailed() = stateLayout.refreshView.loadMoreFailed() |
|
||||||
|
|
||||||
override fun isRefreshing() = stateLayout.refreshView.isRefreshing |
|
||||||
|
|
||||||
override fun showContentLayout() = stateLayout.showContentLayout() |
|
||||||
|
|
||||||
override fun showLoadingLayout() = stateLayout.showLoadingLayout() |
|
||||||
|
|
||||||
override fun refreshCompleted() = stateLayout.refreshView.refreshCompleted() |
|
||||||
|
|
||||||
override fun showEmptyLayout() = stateLayout.showEmptyLayout() |
|
||||||
|
|
||||||
override fun showErrorLayout() = stateLayout.showErrorLayout() |
|
||||||
|
|
||||||
override fun showRequesting() = stateLayout.showRequesting() |
|
||||||
|
|
||||||
override fun showBlank() = stateLayout.showBlank() |
|
||||||
|
|
||||||
override fun getStateLayoutConfig() = stateLayout.stateLayoutConfig |
|
||||||
|
|
||||||
override fun autoRefresh() = stateLayout.refreshView.autoRefresh() |
|
||||||
|
|
||||||
override fun showNetErrorLayout() = stateLayout.showNetErrorLayout() |
|
||||||
|
|
||||||
override fun showServerErrorLayout() = stateLayout.showServerErrorLayout() |
|
||||||
|
|
||||||
override fun isLoadingMore() = stateLayout.refreshView.isLoadingMore |
|
||||||
|
|
||||||
override fun currentStatus() = stateLayout.currentStatus() |
|
||||||
|
|
||||||
companion object { |
|
||||||
const val CONTENT = StateLayoutConfig.CONTENT |
|
||||||
const val LOADING = StateLayoutConfig.LOADING |
|
||||||
const val ERROR = StateLayoutConfig.ERROR |
|
||||||
const val EMPTY = StateLayoutConfig.EMPTY |
|
||||||
const val NET_ERROR = StateLayoutConfig.NET_ERROR |
|
||||||
const val SERVER_ERROR = StateLayoutConfig.SERVER_ERROR |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,115 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import com.android.base.adapter.DataManager |
|
||||||
import com.android.base.app.ui.AutoPageNumber |
|
||||||
import com.android.base.app.ui.RefreshListLayout |
|
||||||
import com.android.base.app.ui.StateLayoutConfig |
|
||||||
|
|
||||||
/** |
|
||||||
*@author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-03-26 15:06 |
|
||||||
*@see [BaseListV2Fragment] |
|
||||||
*/ |
|
||||||
abstract class BaseListV2Fragment<T> : BaseDialogFragment(), RefreshListLayout<T> { |
|
||||||
|
|
||||||
private lateinit var stateLayout: RefreshLoadMoreStateLayoutImpl |
|
||||||
|
|
||||||
protected open lateinit var dataManager: DataManager<T> |
|
||||||
|
|
||||||
override fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) { |
|
||||||
stateLayout = RefreshLoadMoreStateLayoutImpl.init(view) |
|
||||||
stateLayout.refreshView.setRefreshHandler { |
|
||||||
onRefresh() |
|
||||||
} |
|
||||||
stateLayout.refreshView.setLoadMoreHandler { |
|
||||||
onLoadMore() |
|
||||||
} |
|
||||||
stateLayout.setStateRetryListener(this::onRetry) |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRetry(state: Int) { |
|
||||||
if (!isRefreshing) { |
|
||||||
autoRefresh() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRefresh() = onStartLoad() |
|
||||||
|
|
||||||
protected open fun onLoadMore() = onStartLoad() |
|
||||||
|
|
||||||
/** call by [onRefresh] or [onLoadMore], you can get current loading type from [isRefreshing] or [isLoadingMore]. */ |
|
||||||
protected open fun onStartLoad() {} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
super.onActivityCreated(savedInstanceState) |
|
||||||
if (!::dataManager.isInitialized) { |
|
||||||
throw NullPointerException("you need set DataManager") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
super.onDestroyView() |
|
||||||
refreshCompleted() |
|
||||||
} |
|
||||||
|
|
||||||
override fun replaceData(data: MutableList<T>?) { |
|
||||||
dataManager.replaceAll(data) |
|
||||||
} |
|
||||||
|
|
||||||
override fun addData(data: MutableList<T>?) { |
|
||||||
dataManager.addItems(data) |
|
||||||
} |
|
||||||
|
|
||||||
fun setRefreshEnable(enable: Boolean) = stateLayout.refreshView.setRefreshEnable(enable) |
|
||||||
|
|
||||||
fun setLoadMoreEnable(enable: Boolean) = stateLayout.refreshView.setLoadMoreEnable(enable) |
|
||||||
|
|
||||||
override fun getPager() = AutoPageNumber(this, dataManager) |
|
||||||
|
|
||||||
override fun isEmpty() = dataManager.isEmpty |
|
||||||
|
|
||||||
override fun loadMoreCompleted(hasMore: Boolean) = stateLayout.refreshView.loadMoreCompleted(hasMore) |
|
||||||
|
|
||||||
override fun loadMoreFailed() = stateLayout.refreshView.loadMoreFailed() |
|
||||||
|
|
||||||
override fun isRefreshing() = stateLayout.refreshView.isRefreshing |
|
||||||
|
|
||||||
override fun showContentLayout() = stateLayout.showContentLayout() |
|
||||||
|
|
||||||
override fun showLoadingLayout() = stateLayout.showLoadingLayout() |
|
||||||
|
|
||||||
override fun refreshCompleted() = stateLayout.refreshView.refreshCompleted() |
|
||||||
|
|
||||||
override fun showEmptyLayout() = stateLayout.showEmptyLayout() |
|
||||||
|
|
||||||
override fun showErrorLayout() = stateLayout.showErrorLayout() |
|
||||||
|
|
||||||
override fun showRequesting() = stateLayout.showRequesting() |
|
||||||
|
|
||||||
override fun showBlank() = stateLayout.showBlank() |
|
||||||
|
|
||||||
override fun getStateLayoutConfig() = stateLayout.stateLayoutConfig |
|
||||||
|
|
||||||
override fun autoRefresh() = stateLayout.refreshView.autoRefresh() |
|
||||||
|
|
||||||
override fun showNetErrorLayout() = stateLayout.showNetErrorLayout() |
|
||||||
|
|
||||||
override fun showServerErrorLayout() = stateLayout.showServerErrorLayout() |
|
||||||
|
|
||||||
override fun isLoadingMore() = stateLayout.refreshView.isLoadingMore |
|
||||||
|
|
||||||
override fun currentStatus() = stateLayout.currentStatus() |
|
||||||
|
|
||||||
companion object { |
|
||||||
const val CONTENT = StateLayoutConfig.CONTENT |
|
||||||
const val LOADING = StateLayoutConfig.LOADING |
|
||||||
const val ERROR = StateLayoutConfig.ERROR |
|
||||||
const val EMPTY = StateLayoutConfig.EMPTY |
|
||||||
const val NET_ERROR = StateLayoutConfig.NET_ERROR |
|
||||||
const val SERVER_ERROR = StateLayoutConfig.SERVER_ERROR |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,94 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import com.android.base.app.ui.RefreshStateLayout |
|
||||||
import com.android.base.app.ui.RefreshView |
|
||||||
import com.android.base.app.ui.StateLayoutConfig |
|
||||||
import com.android.base.utils.common.ifNonNull |
|
||||||
import com.android.base.utils.common.otherwise |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
* @see BaseStateFragment |
|
||||||
*/ |
|
||||||
abstract class BaseStateDialogFragment : BaseDialogFragment(), RefreshStateLayout { |
|
||||||
|
|
||||||
private lateinit var stateLayout: RefreshableStateLayoutImpl |
|
||||||
|
|
||||||
override fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) { |
|
||||||
stateLayout = RefreshableStateLayoutImpl.init(view) |
|
||||||
stateLayout.setRefreshHandler(object : RefreshView.RefreshHandler() { |
|
||||||
override fun onRefresh() { |
|
||||||
this@BaseStateDialogFragment.onRefresh() |
|
||||||
} |
|
||||||
|
|
||||||
override fun canRefresh(): Boolean { |
|
||||||
return this@BaseStateDialogFragment.canRefresh() |
|
||||||
} |
|
||||||
}) |
|
||||||
stateLayout.setStateRetryListenerUnchecked { state -> onRetry(state) } |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
super.onDestroyView() |
|
||||||
refreshCompleted() |
|
||||||
} |
|
||||||
|
|
||||||
internal open fun canRefresh() = true |
|
||||||
|
|
||||||
private val refreshView: RefreshView? |
|
||||||
get() = stateLayout.refreshView |
|
||||||
|
|
||||||
protected open fun onRetry(@StateLayoutConfig.RetryableState state: Int) { |
|
||||||
refreshView.ifNonNull { |
|
||||||
if (!this.isRefreshing) { |
|
||||||
autoRefresh() |
|
||||||
} |
|
||||||
} otherwise { |
|
||||||
onRefresh() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRefresh() {} |
|
||||||
|
|
||||||
fun setRefreshEnable(enable: Boolean) = refreshView?.setRefreshEnable(enable) |
|
||||||
|
|
||||||
override fun getStateLayoutConfig(): StateLayoutConfig = stateLayout.stateLayoutConfig |
|
||||||
|
|
||||||
override fun isRefreshing() = stateLayout.isRefreshing |
|
||||||
|
|
||||||
override fun refreshCompleted() = stateLayout.refreshCompleted() |
|
||||||
|
|
||||||
override fun autoRefresh() = stateLayout.autoRefresh() |
|
||||||
|
|
||||||
override fun showContentLayout() = stateLayout.showContentLayout() |
|
||||||
|
|
||||||
override fun showLoadingLayout() = stateLayout.showLoadingLayout() |
|
||||||
|
|
||||||
override fun showEmptyLayout() = stateLayout.showEmptyLayout() |
|
||||||
|
|
||||||
override fun showErrorLayout() = stateLayout.showErrorLayout() |
|
||||||
|
|
||||||
override fun showRequesting() = stateLayout.showRequesting() |
|
||||||
|
|
||||||
override fun showBlank() = stateLayout.showBlank() |
|
||||||
|
|
||||||
override fun showNetErrorLayout() = stateLayout.showNetErrorLayout() |
|
||||||
|
|
||||||
override fun showServerErrorLayout() = stateLayout.showServerErrorLayout() |
|
||||||
|
|
||||||
override fun currentStatus() = stateLayout.currentStatus() |
|
||||||
|
|
||||||
companion object { |
|
||||||
const val CONTENT = StateLayoutConfig.CONTENT |
|
||||||
const val LOADING = StateLayoutConfig.LOADING |
|
||||||
const val ERROR = StateLayoutConfig.ERROR |
|
||||||
const val EMPTY = StateLayoutConfig.EMPTY |
|
||||||
const val NET_ERROR = StateLayoutConfig.NET_ERROR |
|
||||||
const val SERVER_ERROR = StateLayoutConfig.SERVER_ERROR |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,101 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import com.android.base.R |
|
||||||
import com.android.base.app.ui.RefreshStateLayout |
|
||||||
import com.android.base.app.ui.RefreshView |
|
||||||
import com.android.base.app.ui.RefreshView.RefreshHandler |
|
||||||
import com.android.base.app.ui.StateLayoutConfig |
|
||||||
import com.android.base.app.ui.StateLayoutConfig.RetryableState |
|
||||||
import com.android.base.utils.common.ifNonNull |
|
||||||
import com.android.base.utils.common.otherwise |
|
||||||
|
|
||||||
/** |
|
||||||
* 1. 支持显示{CONTENT, LOADING, ERROR, EMPTY}等状态布局、支持下拉刷新 |
|
||||||
* 2. 使用的布局中必须有一个id = [R.id.base_state_layout] 的 Layout,确保 Layout 实现了[com.android.base.app.ui.StateLayout] |
|
||||||
* 3. [RefreshView] (下拉刷新)的 id 必须设置为 :[R.id.base_refresh_layout],没有添加则表示不需要下拉刷新功能 |
|
||||||
* 4. 默认所有重试和下拉刷新都会调用 [onRefresh],子类可以修改该行为 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* date : 2016-03-19 23:09 |
|
||||||
* email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
abstract class BaseStateFragment : BaseFragment(), RefreshStateLayout { |
|
||||||
|
|
||||||
private lateinit var stateLayout: RefreshableStateLayoutImpl |
|
||||||
|
|
||||||
override fun internalOnViewPrepared(view: View, savedInstanceState: Bundle?) { |
|
||||||
stateLayout = RefreshableStateLayoutImpl.init(view) |
|
||||||
stateLayout.setRefreshHandler(object : RefreshHandler() { |
|
||||||
override fun onRefresh() { |
|
||||||
this@BaseStateFragment.onRefresh() |
|
||||||
} |
|
||||||
|
|
||||||
override fun canRefresh(): Boolean { |
|
||||||
return this@BaseStateFragment.canRefresh() |
|
||||||
} |
|
||||||
}) |
|
||||||
stateLayout.setStateRetryListenerUnchecked { state -> onRetry(state) } |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroyView() { |
|
||||||
super.onDestroyView() |
|
||||||
refreshCompleted() |
|
||||||
} |
|
||||||
|
|
||||||
internal open fun canRefresh() = true |
|
||||||
|
|
||||||
private val refreshView: RefreshView? |
|
||||||
get() = stateLayout.refreshView |
|
||||||
|
|
||||||
protected open fun onRetry(@RetryableState state: Int) { |
|
||||||
refreshView.ifNonNull { |
|
||||||
if (!this.isRefreshing) { |
|
||||||
autoRefresh() |
|
||||||
} |
|
||||||
} otherwise { |
|
||||||
onRefresh() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected open fun onRefresh() {} |
|
||||||
|
|
||||||
fun setRefreshEnable(enable: Boolean) = refreshView?.setRefreshEnable(enable) |
|
||||||
|
|
||||||
override fun getStateLayoutConfig(): StateLayoutConfig = stateLayout.stateLayoutConfig |
|
||||||
|
|
||||||
override fun isRefreshing() = stateLayout.isRefreshing |
|
||||||
|
|
||||||
override fun refreshCompleted() = stateLayout.refreshCompleted() |
|
||||||
|
|
||||||
override fun autoRefresh() = stateLayout.autoRefresh() |
|
||||||
|
|
||||||
override fun showContentLayout() = stateLayout.showContentLayout() |
|
||||||
|
|
||||||
override fun showLoadingLayout() = stateLayout.showLoadingLayout() |
|
||||||
|
|
||||||
override fun showEmptyLayout() = stateLayout.showEmptyLayout() |
|
||||||
|
|
||||||
override fun showErrorLayout() = stateLayout.showErrorLayout() |
|
||||||
|
|
||||||
override fun showRequesting() = stateLayout.showRequesting() |
|
||||||
|
|
||||||
override fun showBlank() = stateLayout.showBlank() |
|
||||||
|
|
||||||
override fun showNetErrorLayout() = stateLayout.showNetErrorLayout() |
|
||||||
|
|
||||||
override fun showServerErrorLayout() = stateLayout.showServerErrorLayout() |
|
||||||
|
|
||||||
override fun currentStatus() = stateLayout.currentStatus() |
|
||||||
|
|
||||||
companion object { |
|
||||||
const val CONTENT = StateLayoutConfig.CONTENT |
|
||||||
const val LOADING = StateLayoutConfig.LOADING |
|
||||||
const val ERROR = StateLayoutConfig.ERROR |
|
||||||
const val EMPTY = StateLayoutConfig.EMPTY |
|
||||||
const val NET_ERROR = StateLayoutConfig.NET_ERROR |
|
||||||
const val SERVER_ERROR = StateLayoutConfig.SERVER_ERROR |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,169 +0,0 @@ |
|||||||
package com.android.base.app.fragment; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.Intent; |
|
||||||
import android.os.Bundle; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegate; |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner; |
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.annotation.UiThread; |
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
|
|
||||||
|
|
||||||
@UiThread |
|
||||||
final class FragmentDelegates implements FragmentDelegate<Fragment>, FragmentDelegateOwner { |
|
||||||
|
|
||||||
private final Fragment mDelegateOwner; |
|
||||||
private List<FragmentDelegate> mDelegates = new ArrayList<>(4); |
|
||||||
|
|
||||||
<T extends Fragment & FragmentDelegateOwner> FragmentDelegates(T delegateOwner) { |
|
||||||
mDelegateOwner = delegateOwner; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onAttach(Context context) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onAttach(context); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onCreate(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onViewCreated(view, savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onActivityCreated(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onStart() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onStart(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onResume() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onResume(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onPause() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onPause(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onStop() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onStop(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onDestroy() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onDestroy(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onDestroyView() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onDestroyView(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onDetach() { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onDetach(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setUserVisibleHint(boolean isVisibleToUser) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.setUserVisibleHint(isVisibleToUser); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onSaveInstanceState(Bundle savedInstanceState) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onSaveInstanceState(savedInstanceState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onHiddenChanged(boolean hidden) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onHiddenChanged(hidden); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onActivityResult(requestCode, resultCode, data); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
|
||||||
for (FragmentDelegate fragmentDelegate : mDelegates) { |
|
||||||
fragmentDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public void addDelegate(FragmentDelegate fragmentDelegate) { |
|
||||||
mDelegates.add(fragmentDelegate); |
|
||||||
fragmentDelegate.onAttachToFragment(mDelegateOwner); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean removeDelegate(FragmentDelegate fragmentDelegate) { |
|
||||||
boolean remove = mDelegates.remove(fragmentDelegate); |
|
||||||
if (remove) { |
|
||||||
fragmentDelegate.onDetachFromFragment(); |
|
||||||
} |
|
||||||
return remove; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public FragmentDelegate findDelegate(Predicate<FragmentDelegate> predicate) { |
|
||||||
for (FragmentDelegate delegate : mDelegates) { |
|
||||||
if (predicate.test(delegate)) { |
|
||||||
return delegate; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,85 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable |
|
||||||
import android.view.View |
|
||||||
import com.android.base.app.ui.* |
|
||||||
import com.android.base.widget.StateProcessor |
|
||||||
|
|
||||||
internal class RefreshLoadMoreStateLayoutImpl private constructor(layout: View) : StateLayout, StateLayoutConfig { |
|
||||||
|
|
||||||
companion object { |
|
||||||
fun init(view: View): RefreshLoadMoreStateLayoutImpl { |
|
||||||
return RefreshLoadMoreStateLayoutImpl(view) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private var _multiStateView: StateLayout? = layout.findViewById<View>(CommonId.STATE_ID) as? StateLayout |
|
||||||
private var _refreshView: RefreshLoadMoreView |
|
||||||
|
|
||||||
val refreshView: RefreshLoadMoreView |
|
||||||
get() = _refreshView |
|
||||||
|
|
||||||
init { |
|
||||||
val refreshLayout = layout.findViewById<View>(CommonId.REFRESH_ID) |
|
||||||
?: throw NullPointerException("You need to provide a refreshable layout with id R.id.base_refresh_layout in your xml.") |
|
||||||
|
|
||||||
_refreshView = RefreshLoadViewFactory.createRefreshView(refreshLayout) |
|
||||||
} |
|
||||||
|
|
||||||
override fun showLoadingLayout() = checkMultiStateView().showLoadingLayout() |
|
||||||
override fun showContentLayout() = checkMultiStateView().showContentLayout() |
|
||||||
override fun showEmptyLayout() = checkMultiStateView().showEmptyLayout() |
|
||||||
override fun showErrorLayout() = checkMultiStateView().showErrorLayout() |
|
||||||
override fun showRequesting() = checkMultiStateView().showRequesting() |
|
||||||
override fun showBlank() = checkMultiStateView().showBlank() |
|
||||||
override fun showNetErrorLayout() = checkMultiStateView().showNetErrorLayout() |
|
||||||
override fun showServerErrorLayout() = checkMultiStateView().showServerErrorLayout() |
|
||||||
override fun currentStatus() = checkMultiStateView().currentStatus() |
|
||||||
|
|
||||||
override fun getStateLayoutConfig(): StateLayoutConfig = checkMultiStateView().stateLayoutConfig |
|
||||||
|
|
||||||
override fun setStateMessage(state: Int, message: CharSequence?): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setStateMessage(state, message) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun setStateIcon(state: Int, drawable: Drawable?): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setStateIcon(state, drawable) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun setStateIcon(state: Int, drawableId: Int): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setStateIcon(state, drawableId) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun setStateAction(state: Int, actionText: CharSequence?): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setStateAction(state, actionText) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun setStateRetryListener(retryActionListener: OnRetryActionListener?): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setStateRetryListener(retryActionListener) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun disableOperationWhenRequesting(disable: Boolean): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.disableOperationWhenRequesting(disable) |
|
||||||
return checkMultiStateView().stateLayoutConfig |
|
||||||
} |
|
||||||
|
|
||||||
override fun getProcessor(): StateProcessor { |
|
||||||
return checkMultiStateView().stateLayoutConfig.processor |
|
||||||
} |
|
||||||
|
|
||||||
override fun setMessageGravity(state: Int, gravity: Int): StateLayoutConfig { |
|
||||||
checkMultiStateView().stateLayoutConfig.setMessageGravity(state, gravity) |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
private fun checkMultiStateView(): StateLayout { |
|
||||||
return _multiStateView |
|
||||||
?: throw IllegalStateException("Calling this function requires defining a view that implements StateLayout in the Layout") |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,207 +0,0 @@ |
|||||||
package com.android.base.app.fragment; |
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import com.android.base.app.ui.OnRetryActionListener; |
|
||||||
import com.android.base.app.ui.RefreshStateLayout; |
|
||||||
import com.android.base.app.ui.RefreshView; |
|
||||||
import com.android.base.app.ui.RefreshViewFactory; |
|
||||||
import com.android.base.app.ui.StateLayout; |
|
||||||
import com.android.base.app.ui.StateLayoutConfig; |
|
||||||
import com.android.base.widget.StateProcessor; |
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes; |
|
||||||
|
|
||||||
import static com.android.base.app.ui.CommonId.REFRESH_ID; |
|
||||||
import static com.android.base.app.ui.CommonId.STATE_ID; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
*/ |
|
||||||
final class RefreshableStateLayoutImpl implements RefreshStateLayout, StateLayoutConfig { |
|
||||||
|
|
||||||
private StateLayout mMultiStateView; |
|
||||||
private RefreshView mRefreshView; |
|
||||||
private RefreshView.RefreshHandler mRefreshHandler; |
|
||||||
|
|
||||||
static RefreshableStateLayoutImpl init(View layoutView) { |
|
||||||
return new RefreshableStateLayoutImpl(layoutView); |
|
||||||
} |
|
||||||
|
|
||||||
private RefreshableStateLayoutImpl(View layoutView) { |
|
||||||
setupBaseUiLogic(layoutView); |
|
||||||
setupRefreshLogic(layoutView); |
|
||||||
} |
|
||||||
|
|
||||||
RefreshView getRefreshView() { |
|
||||||
return mRefreshView; |
|
||||||
} |
|
||||||
|
|
||||||
void setRefreshHandler(RefreshView.RefreshHandler refreshHandler) { |
|
||||||
mRefreshHandler = refreshHandler; |
|
||||||
} |
|
||||||
|
|
||||||
void setStateRetryListenerUnchecked(OnRetryActionListener retryActionListener) { |
|
||||||
if (mMultiStateView != null) { |
|
||||||
setStateRetryListener(retryActionListener); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("all") |
|
||||||
private void setupBaseUiLogic(View layoutView) { |
|
||||||
mMultiStateView = (StateLayout) layoutView.findViewById(STATE_ID); |
|
||||||
} |
|
||||||
|
|
||||||
private void setupRefreshLogic(View layoutView) { |
|
||||||
View refreshLayout = layoutView.findViewById(REFRESH_ID); |
|
||||||
if (refreshLayout == null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
mRefreshView = RefreshViewFactory.createRefreshView(refreshLayout); |
|
||||||
mRefreshView.setRefreshHandler(new RefreshView.RefreshHandler() { |
|
||||||
@Override |
|
||||||
public boolean canRefresh() { |
|
||||||
return mRefreshHandler.canRefresh(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onRefresh() { |
|
||||||
mRefreshHandler.onRefresh(); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public final void autoRefresh() { |
|
||||||
if (mRefreshView != null) { |
|
||||||
mRefreshView.autoRefresh(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showLoadingLayout() { |
|
||||||
checkMultiStateView().showLoadingLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showContentLayout() { |
|
||||||
refreshCompleted(); |
|
||||||
checkMultiStateView().showContentLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showEmptyLayout() { |
|
||||||
refreshCompleted(); |
|
||||||
checkMultiStateView().showEmptyLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showErrorLayout() { |
|
||||||
refreshCompleted(); |
|
||||||
checkMultiStateView().showErrorLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showRequesting() { |
|
||||||
checkMultiStateView().showRequesting(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showBlank() { |
|
||||||
checkMultiStateView().showBlank(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showNetErrorLayout() { |
|
||||||
refreshCompleted(); |
|
||||||
checkMultiStateView().showNetErrorLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void showServerErrorLayout() { |
|
||||||
refreshCompleted(); |
|
||||||
checkMultiStateView().showServerErrorLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig getStateLayoutConfig() { |
|
||||||
checkMultiStateView(); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int currentStatus() { |
|
||||||
return mMultiStateView.currentStatus(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void refreshCompleted() { |
|
||||||
if (mRefreshView != null) { |
|
||||||
mRefreshView.refreshCompleted(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isRefreshing() { |
|
||||||
if (mRefreshView != null) { |
|
||||||
return mRefreshView.isRefreshing(); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setStateMessage(@RetryableState int state, CharSequence message) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setStateMessage(state, message); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setMessageGravity(int state, int gravity) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setMessageGravity(state, gravity); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setStateIcon(@RetryableState int state, Drawable drawable) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setStateIcon(state, drawable); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setStateIcon(@RetryableState int state, @DrawableRes int drawableId) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setStateIcon(state, drawableId); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setStateAction(@RetryableState int state, CharSequence actionText) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setStateAction(state, actionText); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig setStateRetryListener(OnRetryActionListener retryActionListener) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().setStateRetryListener(retryActionListener); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateLayoutConfig disableOperationWhenRequesting(boolean disable) { |
|
||||||
checkMultiStateView().getStateLayoutConfig().disableOperationWhenRequesting(disable); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public StateProcessor getProcessor() { |
|
||||||
return checkMultiStateView().getStateLayoutConfig().getProcessor(); |
|
||||||
} |
|
||||||
|
|
||||||
private StateLayout checkMultiStateView() { |
|
||||||
if (mMultiStateView == null) { |
|
||||||
throw new IllegalStateException("Calling this function requires defining a view that implements StateLayout in the Layout"); |
|
||||||
} |
|
||||||
return mMultiStateView; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
package com.android.base.app.fragment.animator |
|
||||||
|
|
||||||
import android.view.animation.* |
|
||||||
import com.android.base.R |
|
||||||
import com.android.base.utils.BaseUtils |
|
||||||
|
|
||||||
interface FragmentAnimator { |
|
||||||
fun makeOpenEnter(): Animation? |
|
||||||
fun makeOpenExit(): Animation? |
|
||||||
fun makeCloseEnter(): Animation? |
|
||||||
fun makeCloseExit(): Animation? |
|
||||||
} |
|
||||||
|
|
||||||
class DefaultVerticalAnimator : FragmentAnimator { |
|
||||||
override fun makeOpenEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.v_fragment_open_enter) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeOpenExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.v_fragment_open_exit) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.v_fragment_close_enter) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.v_fragment_close_exit) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class DefaultHorizontalAnimator : FragmentAnimator { |
|
||||||
override fun makeOpenEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.h_fragment_open_enter) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeOpenExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.h_fragment_open_exit) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.h_fragment_close_enter) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.h_fragment_close_exit) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class DefaultNoAnimator : FragmentAnimator { |
|
||||||
override fun makeOpenEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.base_no_anim) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeOpenExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.base_no_anim) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseEnter(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.base_no_anim) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseExit(): Animation? { |
|
||||||
return AnimationUtils.loadAnimation(BaseUtils.getAppContext(), R.anim.base_no_anim) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
class DefaultScaleAnimator : FragmentAnimator { |
|
||||||
override fun makeOpenEnter(): Animation? { |
|
||||||
return makeOpenCloseAnimation(1.125f, 1.0f, 0f, 1f) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeOpenExit(): Animation? { |
|
||||||
return makeOpenCloseAnimation(1.0f, .975f, 1f, 0f) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseEnter(): Animation? { |
|
||||||
return makeOpenCloseAnimation(.975f, 1.0f, 0f, 1f) |
|
||||||
} |
|
||||||
|
|
||||||
override fun makeCloseExit(): Animation? { |
|
||||||
return makeOpenCloseAnimation(1.0f, 1.075f, 1f, 0f) |
|
||||||
} |
|
||||||
|
|
||||||
companion object { |
|
||||||
private val DECELERATE_QUINT: Interpolator = DecelerateInterpolator(2.5f) |
|
||||||
private val DECELERATE_CUBIC: Interpolator = DecelerateInterpolator(1.5f) |
|
||||||
private const val ANIM_DUR = 220 |
|
||||||
private fun makeOpenCloseAnimation(startScale: Float, endScale: Float, startAlpha: Float, endAlpha: Float): Animation { |
|
||||||
val set = AnimationSet(false) |
|
||||||
val scale = ScaleAnimation(startScale, endScale, startScale, endScale, Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f) |
|
||||||
scale.interpolator = DECELERATE_QUINT |
|
||||||
scale.duration = ANIM_DUR.toLong() |
|
||||||
set.addAnimation(scale) |
|
||||||
val alpha = AlphaAnimation(startAlpha, endAlpha) |
|
||||||
alpha.interpolator = DECELERATE_CUBIC |
|
||||||
alpha.duration = ANIM_DUR.toLong() |
|
||||||
set.addAnimation(alpha) |
|
||||||
return set |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
package com.android.base.app.fragment.animator; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.animation.Animation; |
|
||||||
import android.view.animation.AnimationUtils; |
|
||||||
|
|
||||||
import com.android.base.R; |
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentTransaction; |
|
||||||
|
|
||||||
public final class FragmentAnimatorHelper { |
|
||||||
|
|
||||||
private Context context; |
|
||||||
private FragmentAnimator fragmentAnimator; |
|
||||||
|
|
||||||
public FragmentAnimatorHelper(Context context, FragmentAnimator fragmentAnimator) { |
|
||||||
this.context = context; |
|
||||||
this.fragmentAnimator = fragmentAnimator; |
|
||||||
} |
|
||||||
|
|
||||||
public void changeAnimation(FragmentAnimator fragmentAnimator) { |
|
||||||
this.fragmentAnimator = fragmentAnimator; |
|
||||||
} |
|
||||||
|
|
||||||
public Animation getNoneAnim() { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} |
|
||||||
|
|
||||||
public Animation getNoneAnimFixed() { |
|
||||||
return new Animation() { |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
private Animation initEnterAnim() { |
|
||||||
if (fragmentAnimator == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
Animation animation = fragmentAnimator.makeOpenEnter(); |
|
||||||
if (animation == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
return animation; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Animation initExitAnim() { |
|
||||||
if (fragmentAnimator == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
Animation animation = fragmentAnimator.makeOpenExit(); |
|
||||||
if (animation == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
return animation; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Animation initPopEnterAnim() { |
|
||||||
if (fragmentAnimator == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
Animation animation = fragmentAnimator.makeCloseEnter(); |
|
||||||
if (animation == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
return animation; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Animation initPopExitAnim() { |
|
||||||
if (fragmentAnimator == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
Animation animation = fragmentAnimator.makeCloseExit(); |
|
||||||
if (animation == null) { |
|
||||||
return AnimationUtils.loadAnimation(context, R.anim.base_no_anim); |
|
||||||
} else { |
|
||||||
return animation; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Animation onCreateAnimation(int transit, boolean enter) { |
|
||||||
if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) { |
|
||||||
if (enter) { |
|
||||||
return initEnterAnim(); |
|
||||||
} else { |
|
||||||
return initExitAnim(); |
|
||||||
} |
|
||||||
} else if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) { |
|
||||||
if (enter) { |
|
||||||
return initPopEnterAnim(); |
|
||||||
} else { |
|
||||||
return initPopExitAnim(); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,74 +0,0 @@ |
|||||||
package com.android.base.app.fragment.delegates; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.Intent; |
|
||||||
import android.os.Bundle; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
|
|
||||||
public interface FragmentDelegate<T extends Fragment> { |
|
||||||
|
|
||||||
/** |
|
||||||
* 当该Delegate被添加到Fragment中 |
|
||||||
*/ |
|
||||||
default void onAttachToFragment(T fragment) { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 调用此方法时,清除Fragment的引用 |
|
||||||
*/ |
|
||||||
default void onDetachFromFragment() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onAttach(Context context) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onCreate(@Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onActivityCreated(@Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onSaveInstanceState(Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onStart() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onResume() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onPause() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onStop() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onDestroy() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onDestroyView() { |
|
||||||
} |
|
||||||
|
|
||||||
default void onDetach() { |
|
||||||
} |
|
||||||
|
|
||||||
default void setUserVisibleHint(boolean isVisibleToUser) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onHiddenChanged(boolean hidden) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onActivityResult(int requestCode, int resultCode, Intent data) { |
|
||||||
} |
|
||||||
|
|
||||||
default void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
package com.android.base.app.fragment.delegates; |
|
||||||
|
|
||||||
|
|
||||||
import com.github.dmstocking.optional.java.util.function.Predicate; |
|
||||||
|
|
||||||
import androidx.annotation.UiThread; |
|
||||||
|
|
||||||
@UiThread |
|
||||||
public interface FragmentDelegateOwner { |
|
||||||
|
|
||||||
void addDelegate(FragmentDelegate fragmentDelegate); |
|
||||||
|
|
||||||
boolean removeDelegate(FragmentDelegate fragmentDelegate); |
|
||||||
|
|
||||||
FragmentDelegate findDelegate(Predicate<FragmentDelegate> predicate); |
|
||||||
|
|
||||||
} |
|
@ -1,96 +0,0 @@ |
|||||||
package com.android.base.app.fragment.delegates |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import android.view.View |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
|
|
||||||
/** |
|
||||||
* 用于在ViewPager中实现懒加载的Fragment: |
|
||||||
* |
|
||||||
* - changed-1: Android Support 24 把 setUserVisibleHint 方法放到了Attach 之前调用了,所以请在在构造代码块中设置 LazyDelegate。 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Date : Date : 2016-05-06 15:02 |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
open class LazyDelegate private constructor() : FragmentDelegate<Fragment?> { |
|
||||||
|
|
||||||
/** View是否准备好,如果不需要绑定view数据,只是加载网络数据,那么该字段可以去掉 */ |
|
||||||
private var isViewPrepared = false |
|
||||||
|
|
||||||
/** 滑动过来后,View是否可见 */ |
|
||||||
private var isViewVisible = false |
|
||||||
|
|
||||||
private var preparedListener: (() -> Unit)? = null |
|
||||||
|
|
||||||
/** |
|
||||||
* 在这里实现Fragment数据的缓加载. |
|
||||||
* |
|
||||||
* @param isVisibleToUser true 表用户可见,false 表不可见 |
|
||||||
*/ |
|
||||||
override fun setUserVisibleHint(isVisibleToUser: Boolean) { |
|
||||||
if (isVisibleToUser) { |
|
||||||
isViewVisible = true |
|
||||||
onVisible() |
|
||||||
} else { |
|
||||||
isViewVisible = false |
|
||||||
onInvisible() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
|
||||||
isViewPrepared = true |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
lazyLoad() |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 滑动过来后,界面可见时执行 |
|
||||||
*/ |
|
||||||
protected fun onVisible() { |
|
||||||
lazyLoad() |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 滑动过来后,界面不可见时执行 |
|
||||||
*/ |
|
||||||
protected fun onInvisible() {} |
|
||||||
|
|
||||||
private fun lazyLoad() { |
|
||||||
if (isViewPrepared && isViewVisible) { |
|
||||||
notifyLazyLoad() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 懒加载数据,并在此绑定View数据 |
|
||||||
*/ |
|
||||||
private fun notifyLazyLoad() { |
|
||||||
preparedListener?.invoke() |
|
||||||
} |
|
||||||
|
|
||||||
companion object { |
|
||||||
fun attach(delegateFragment: FragmentDelegateOwner, onPreparedListener: () -> Unit): LazyDelegate { |
|
||||||
val delegate = LazyDelegate() |
|
||||||
delegate.preparedListener = onPreparedListener |
|
||||||
delegateFragment.addDelegate(delegate) |
|
||||||
return delegate |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
class SimpleLazyLoadListener(private val onFirstLoad: () -> Unit) : (() -> Unit) { |
|
||||||
|
|
||||||
private var isCalled = false |
|
||||||
|
|
||||||
override fun invoke() { |
|
||||||
if (!isCalled) { |
|
||||||
onFirstLoad() |
|
||||||
isCalled = true |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,114 +0,0 @@ |
|||||||
package com.android.base.app.fragment.tools |
|
||||||
|
|
||||||
import android.os.Binder |
|
||||||
import android.os.Bundle |
|
||||||
import androidx.core.app.BundleCompat |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import kotlin.properties.ReadWriteProperty |
|
||||||
import kotlin.reflect.KProperty |
|
||||||
|
|
||||||
fun <T : Any> fragmentArgument(name: String? = null, defaultValue: T? = null): ReadWriteProperty<Fragment, T> { |
|
||||||
return FragmentArgumentDelegate(name, defaultValue) |
|
||||||
} |
|
||||||
|
|
||||||
fun <T : Any?> nullableFragmentArgument(name: String? = null): ReadWriteProperty<Fragment, T?> { |
|
||||||
return NullableFragmentArgumentDelegate(name) |
|
||||||
} |
|
||||||
|
|
||||||
internal class FragmentArgumentDelegate<T : Any>( |
|
||||||
/**value name*/ |
|
||||||
private val name: String? = null, |
|
||||||
/**default cannot be null*/ |
|
||||||
private val defaultValue: T? = null |
|
||||||
) : ReadWriteProperty<Fragment, T> { |
|
||||||
|
|
||||||
private lateinit var value: T |
|
||||||
|
|
||||||
override operator fun getValue(thisRef: Fragment, property: KProperty<*>): T { |
|
||||||
if (!::value.isInitialized) { |
|
||||||
|
|
||||||
val args = thisRef.arguments |
|
||||||
|
|
||||||
if (args == null) { |
|
||||||
if (defaultValue != null) { |
|
||||||
value = defaultValue |
|
||||||
} else { |
|
||||||
throw IllegalStateException("Cannot read property ${confirmPropertyName(name, property)} if no arguments have been set") |
|
||||||
} |
|
||||||
} else { |
|
||||||
@Suppress("UNCHECKED_CAST") |
|
||||||
value = args.get(confirmPropertyName(name, property)) as? T |
|
||||||
?: throw IllegalStateException("Property ${confirmPropertyName(name, property)} could not be read") |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
return value |
|
||||||
} |
|
||||||
|
|
||||||
override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) { |
|
||||||
this.value = value |
|
||||||
saveValue(thisRef, name, property, value) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
internal class NullableFragmentArgumentDelegate<T : Any?>( |
|
||||||
/**value name*/ |
|
||||||
private val name: String? = null |
|
||||||
) : ReadWriteProperty<Fragment, T?> { |
|
||||||
|
|
||||||
private var value: T? = null |
|
||||||
|
|
||||||
override operator fun getValue(thisRef: Fragment, property: KProperty<*>): T? { |
|
||||||
if (value == null) { |
|
||||||
@Suppress("UNCHECKED_CAST") |
|
||||||
value = thisRef.arguments?.get(confirmPropertyName(name, property)) as? T |
|
||||||
} |
|
||||||
|
|
||||||
return value |
|
||||||
} |
|
||||||
|
|
||||||
override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T?) { |
|
||||||
this.value = value |
|
||||||
saveValue(thisRef, name, property, value) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private fun confirmPropertyName(name: String?, property: KProperty<*>): String { |
|
||||||
return name ?: property.name |
|
||||||
} |
|
||||||
|
|
||||||
private fun saveValue(thisRef: Fragment, name: String?, property: KProperty<*>, value: Any?) { |
|
||||||
var args = thisRef.arguments |
|
||||||
val key = confirmPropertyName(name, property) |
|
||||||
|
|
||||||
if (value == null) { |
|
||||||
args?.remove(key) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if (args == null) { |
|
||||||
args = Bundle() |
|
||||||
thisRef.arguments = args |
|
||||||
} |
|
||||||
|
|
||||||
when (value) { |
|
||||||
is String -> args.putString(key, value) |
|
||||||
is Int -> args.putInt(key, value) |
|
||||||
is Short -> args.putShort(key, value) |
|
||||||
is Long -> args.putLong(key, value) |
|
||||||
is Byte -> args.putByte(key, value) |
|
||||||
is ByteArray -> args.putByteArray(key, value) |
|
||||||
is Char -> args.putChar(key, value) |
|
||||||
is CharArray -> args.putCharArray(key, value) |
|
||||||
is CharSequence -> args.putCharSequence(key, value) |
|
||||||
is Float -> args.putFloat(key, value) |
|
||||||
is Bundle -> args.putBundle(key, value) |
|
||||||
is Binder -> BundleCompat.putBinder(args, key, value) |
|
||||||
is android.os.Parcelable -> args.putParcelable(key, value) |
|
||||||
is java.io.Serializable -> args.putSerializable(key, value) |
|
||||||
else -> throw IllegalStateException("Type \"$value\" of property ${property.name} is not supported") |
|
||||||
} |
|
||||||
} |
|
@ -1,35 +0,0 @@ |
|||||||
package com.android.base.app.fragment.tools; |
|
||||||
|
|
||||||
import com.android.base.app.fragment.animator.FragmentAnimator; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-03-05 15:25 |
|
||||||
*/ |
|
||||||
public class FragmentConfig { |
|
||||||
|
|
||||||
private static final int INVALIDATE_ID = -1; |
|
||||||
private static int sDefaultContainerId = INVALIDATE_ID; |
|
||||||
private static FragmentAnimator sFragmentAnimator = null; |
|
||||||
|
|
||||||
public static void setDefaultContainerId(int defaultContainerId) { |
|
||||||
sDefaultContainerId = defaultContainerId; |
|
||||||
} |
|
||||||
|
|
||||||
public static int defaultContainerId() { |
|
||||||
if (sDefaultContainerId == INVALIDATE_ID) { |
|
||||||
throw new IllegalStateException("sDefaultContainerId has not set"); |
|
||||||
} |
|
||||||
return sDefaultContainerId; |
|
||||||
} |
|
||||||
|
|
||||||
public static void setDefaultFragmentAnimator(FragmentAnimator animator) { |
|
||||||
sFragmentAnimator = animator; |
|
||||||
} |
|
||||||
|
|
||||||
public static FragmentAnimator defaultFragmentAnimator() { |
|
||||||
return sFragmentAnimator; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,133 +0,0 @@ |
|||||||
package com.android.base.app.fragment.tools; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.os.Bundle; |
|
||||||
|
|
||||||
import java.lang.ref.WeakReference; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess,unused") |
|
||||||
public class FragmentInfo { |
|
||||||
|
|
||||||
private final int mPageId; |
|
||||||
private final String mTag; |
|
||||||
private final Class<? extends Fragment> mClazz; |
|
||||||
private final int mTitleId; |
|
||||||
private final Bundle mArguments; |
|
||||||
private final boolean mIsToStack; |
|
||||||
private final String mStackName; |
|
||||||
private WeakReference<Fragment> mFragment; |
|
||||||
|
|
||||||
private FragmentInfo(int pageId, String tag, Class<? extends Fragment> clazz, int titleId, Bundle arguments, boolean toStack, String stackName) { |
|
||||||
mPageId = pageId; |
|
||||||
mTag = tag; |
|
||||||
mClazz = clazz; |
|
||||||
mTitleId = titleId; |
|
||||||
mArguments = arguments; |
|
||||||
mIsToStack = toStack; |
|
||||||
mStackName = stackName; |
|
||||||
} |
|
||||||
|
|
||||||
public Fragment getInstance() { |
|
||||||
return mFragment == null ? null : mFragment.get(); |
|
||||||
} |
|
||||||
|
|
||||||
public void setInstance(Fragment fragment) { |
|
||||||
mFragment = new WeakReference<>(fragment); |
|
||||||
} |
|
||||||
|
|
||||||
public Fragment newFragment(Context context) { |
|
||||||
return Fragment.instantiate(context, mClazz.getName(), mArguments); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isToStack() { |
|
||||||
return mIsToStack; |
|
||||||
} |
|
||||||
|
|
||||||
public String getStackName() { |
|
||||||
return mStackName; |
|
||||||
} |
|
||||||
|
|
||||||
public Bundle getArguments() { |
|
||||||
return mArguments; |
|
||||||
} |
|
||||||
|
|
||||||
public int getTitleId() { |
|
||||||
return mTitleId; |
|
||||||
} |
|
||||||
|
|
||||||
public int getPageId() { |
|
||||||
return mPageId; |
|
||||||
} |
|
||||||
|
|
||||||
public String getTag() { |
|
||||||
return mTag; |
|
||||||
} |
|
||||||
|
|
||||||
public Class<? extends Fragment> getClazz() { |
|
||||||
return mClazz; |
|
||||||
} |
|
||||||
|
|
||||||
public static PageBuilder builder() { |
|
||||||
return new PageBuilder(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static class PageBuilder { |
|
||||||
|
|
||||||
private int mPagerId; |
|
||||||
private String mTag; |
|
||||||
private Class<? extends Fragment> mClazz; |
|
||||||
private int mTitleId; |
|
||||||
private Bundle mArguments; |
|
||||||
private boolean mIsToStack; |
|
||||||
private String mStackName; |
|
||||||
|
|
||||||
public FragmentInfo build() { |
|
||||||
return new FragmentInfo(mPagerId, mTag, mClazz, mTitleId, mArguments, mIsToStack, mStackName); |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder pagerId(int pagerId) { |
|
||||||
mPagerId = pagerId; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder tag(String tag) { |
|
||||||
this.mTag = tag; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder clazz(Class<? extends Fragment> clazz) { |
|
||||||
mClazz = clazz; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder titleId(int titleId) { |
|
||||||
mTitleId = titleId; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder arguments(Bundle arguments) { |
|
||||||
mArguments = arguments; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public PageBuilder toStack(boolean toStack) { |
|
||||||
this.mIsToStack = toStack; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 如果需要加入到Stack,建议加上StackName。 |
|
||||||
* |
|
||||||
* @param stackName StackName |
|
||||||
* @return PageBuilder |
|
||||||
*/ |
|
||||||
public PageBuilder stackName(String stackName) { |
|
||||||
mStackName = stackName; |
|
||||||
return this; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,500 +0,0 @@ |
|||||||
@file:JvmName("Fragments") |
|
||||||
|
|
||||||
package com.android.base.app.fragment.tools |
|
||||||
|
|
||||||
|
|
||||||
import android.view.View |
|
||||||
import androidx.annotation.NonNull |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import androidx.fragment.app.FragmentActivity |
|
||||||
import androidx.fragment.app.FragmentManager |
|
||||||
import androidx.fragment.app.FragmentTransaction |
|
||||||
import com.android.base.app.activity.ActivityDelegate |
|
||||||
import com.android.base.app.activity.ActivityDelegateOwner |
|
||||||
import com.android.base.app.activity.ActivityState |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegate |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
import com.android.base.utils.common.javaClassName |
|
||||||
import kotlin.reflect.KClass |
|
||||||
|
|
||||||
/**被此 annotation 标注的方法,表示需要使用 [Fragment] 的全类名作为 [FragmentTransaction] 中相关方法的 flag 参数的实参,比如 add/replace 等*/ |
|
||||||
annotation class UsingFragmentClassNameAsFlag |
|
||||||
|
|
||||||
@JvmOverloads |
|
||||||
fun Fragment.exitFragment(immediate: Boolean = false) { |
|
||||||
activity.exitFragment(immediate) |
|
||||||
} |
|
||||||
|
|
||||||
@JvmOverloads |
|
||||||
fun FragmentActivity?.exitFragment(immediate: Boolean = false) { |
|
||||||
if (this == null) { |
|
||||||
return |
|
||||||
} |
|
||||||
val supportFragmentManager = this.supportFragmentManager |
|
||||||
val backStackEntryCount = supportFragmentManager.backStackEntryCount |
|
||||||
if (backStackEntryCount > 0) { |
|
||||||
if (immediate) { |
|
||||||
supportFragmentManager.popBackStackImmediate() |
|
||||||
} else { |
|
||||||
supportFragmentManager.popBackStack() |
|
||||||
} |
|
||||||
} else { |
|
||||||
this.supportFinishAfterTransition() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param clazz the interface container must implemented |
|
||||||
* @param <T> Type |
|
||||||
* @return the interface context must implemented |
|
||||||
*/ |
|
||||||
fun <T> Fragment.requireContainerImplement(clazz: Class<T>): T? { |
|
||||||
if (clazz.isInstance(parentFragment)) { |
|
||||||
return clazz.cast(parentFragment) |
|
||||||
} |
|
||||||
return if (clazz.isInstance(activity)) { |
|
||||||
clazz.cast(activity) |
|
||||||
} else { |
|
||||||
throw RuntimeException("use this Fragment:$this, Activity or Fragment must impl interface :$clazz") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param clazz the interface context must implemented |
|
||||||
* @param <T> Type |
|
||||||
* @return the interface context must implemented |
|
||||||
*/ |
|
||||||
fun <T> Fragment.requireContextImplement(clazz: Class<T>): T? { |
|
||||||
return if (!clazz.isInstance(activity)) { |
|
||||||
throw RuntimeException("use this Fragment:$this, Activity must impl interface :$clazz") |
|
||||||
} else { |
|
||||||
clazz.cast(activity) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param clazz the interface parent must implemented |
|
||||||
* @param <T> Type |
|
||||||
* @return the interface context must implemented |
|
||||||
*/ |
|
||||||
fun <T> Fragment.requireParentImplement(clazz: Class<T>): T? { |
|
||||||
return if (!clazz.isInstance(parentFragment)) { |
|
||||||
throw RuntimeException("use this Fragment:$this, ParentFragment must impl interface :$clazz") |
|
||||||
} else { |
|
||||||
clazz.cast(parentFragment) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** 使用 [clazz] 的全限定类名作为 tag 查找 Fragment */ |
|
||||||
fun <T : Fragment> FragmentManager.findFragmentByTag(clazz: KClass<T>): T? { |
|
||||||
@Suppress("UNCHECKED_CAST") |
|
||||||
return findFragmentByTag(clazz.java.name) as? T |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Fragment 出栈,包括 flag 对应的 Fragment,如果 flag 对应的 Fragment 不在栈中,此方法什么都不做。 |
|
||||||
*/ |
|
||||||
@UsingFragmentClassNameAsFlag |
|
||||||
fun FragmentManager.popBackUntil(flag: String, immediate: Boolean = false) { |
|
||||||
if (immediate) { |
|
||||||
popBackStackImmediate(flag, FragmentManager.POP_BACK_STACK_INCLUSIVE) |
|
||||||
} else { |
|
||||||
popBackStack(flag, FragmentManager.POP_BACK_STACK_INCLUSIVE) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Fragment 出栈,不包括 flag 对应的 Fragment,如果 flag 对应的 Fragment 不在栈中,此方法什么都不做。 |
|
||||||
*/ |
|
||||||
@UsingFragmentClassNameAsFlag |
|
||||||
fun FragmentManager.popBackTo(flag: String, immediate: Boolean = false) { |
|
||||||
if (immediate) { |
|
||||||
popBackStackImmediate(flag, 0) |
|
||||||
} else { |
|
||||||
popBackStack(flag, 0) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 回到对应的 Fragment,如果 Fragment 在栈中,则该 Fragment 回到栈顶,如果 Fragment 不在栈中,则做一次弹栈操作。 |
|
||||||
*/ |
|
||||||
@UsingFragmentClassNameAsFlag |
|
||||||
fun FragmentManager.backToFragment(flag: String, immediate: Boolean = false) { |
|
||||||
val target = findFragmentByTag(flag) |
|
||||||
|
|
||||||
if (target != null) { |
|
||||||
if (isFragmentInStack(target.javaClass)) { |
|
||||||
if (immediate) { |
|
||||||
popBackStackImmediate(flag, 0) |
|
||||||
} else { |
|
||||||
popBackStack(flag, 0) |
|
||||||
} |
|
||||||
} else { |
|
||||||
popBackStack() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fun FragmentManager.clearBackStack(immediate: Boolean = false) { |
|
||||||
if (immediate) { |
|
||||||
this.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) |
|
||||||
} else { |
|
||||||
this.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@UsingFragmentClassNameAsFlag |
|
||||||
fun FragmentManager.isFragmentInStack(clazz: Class<out Fragment>): Boolean { |
|
||||||
val backStackEntryCount = backStackEntryCount |
|
||||||
if (backStackEntryCount == 0) { |
|
||||||
return false |
|
||||||
} |
|
||||||
for (i in 0 until backStackEntryCount) { |
|
||||||
if (clazz.name == getBackStackEntryAt(i).name) { |
|
||||||
return true |
|
||||||
} |
|
||||||
} |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
inline fun FragmentManager.inTransaction(func: EnhanceFragmentTransaction.() -> Unit) { |
|
||||||
val fragmentTransaction = beginTransaction() |
|
||||||
EnhanceFragmentTransaction(this, fragmentTransaction).func() |
|
||||||
fragmentTransaction.commit() |
|
||||||
} |
|
||||||
|
|
||||||
inline fun FragmentActivity.inFragmentTransaction(func: EnhanceFragmentTransaction.() -> Unit) { |
|
||||||
val transaction = supportFragmentManager.beginTransaction() |
|
||||||
EnhanceFragmentTransaction(supportFragmentManager, transaction).func() |
|
||||||
transaction.commit() |
|
||||||
} |
|
||||||
|
|
||||||
fun <T> T.inSafelyFragmentTransaction( |
|
||||||
func: EnhanceFragmentTransaction.() -> Unit |
|
||||||
): Boolean where T : FragmentActivity, T : ActivityDelegateOwner { |
|
||||||
|
|
||||||
var delegate = findDelegate { |
|
||||||
it is SafelyFragmentTransactionActivityDelegate |
|
||||||
} as? SafelyFragmentTransactionActivityDelegate |
|
||||||
|
|
||||||
if (delegate == null) { |
|
||||||
delegate = SafelyFragmentTransactionActivityDelegate() |
|
||||||
addDelegate(delegate) |
|
||||||
} |
|
||||||
|
|
||||||
val transaction = supportFragmentManager.beginTransaction() |
|
||||||
|
|
||||||
EnhanceFragmentTransaction(supportFragmentManager, transaction).func() |
|
||||||
|
|
||||||
return delegate.safeCommit(this, transaction) |
|
||||||
} |
|
||||||
|
|
||||||
inline fun Fragment.inChildFragmentTransaction(func: EnhanceFragmentTransaction.() -> Unit) { |
|
||||||
val transaction = childFragmentManager.beginTransaction() |
|
||||||
EnhanceFragmentTransaction(childFragmentManager, transaction).func() |
|
||||||
transaction.commit() |
|
||||||
} |
|
||||||
|
|
||||||
fun <T> T.inSafelyChildFragmentTransaction( |
|
||||||
func: EnhanceFragmentTransaction.() -> Unit |
|
||||||
): Boolean where T : Fragment, T : FragmentDelegateOwner { |
|
||||||
|
|
||||||
var delegate: SafelyFragmentTransactionFragmentDelegate? = findDelegate { |
|
||||||
it is SafelyFragmentTransactionFragmentDelegate |
|
||||||
} as? SafelyFragmentTransactionFragmentDelegate |
|
||||||
|
|
||||||
if (delegate == null) { |
|
||||||
delegate = SafelyFragmentTransactionFragmentDelegate() |
|
||||||
addDelegate(delegate) |
|
||||||
} |
|
||||||
|
|
||||||
val transaction = childFragmentManager.beginTransaction() |
|
||||||
|
|
||||||
EnhanceFragmentTransaction(childFragmentManager, transaction).func() |
|
||||||
|
|
||||||
return delegate.safeCommit(this, transaction) |
|
||||||
} |
|
||||||
|
|
||||||
private class SafelyFragmentTransactionActivityDelegate : ActivityDelegate<FragmentActivity> { |
|
||||||
|
|
||||||
private val mPendingTransactions = mutableListOf<FragmentTransaction>() |
|
||||||
|
|
||||||
fun safeCommit(@NonNull activityDelegateOwner: ActivityDelegateOwner, @NonNull transaction: FragmentTransaction): Boolean { |
|
||||||
val status = activityDelegateOwner.status |
|
||||||
val isCommitterResumed = (status == ActivityState.CREATE || status == ActivityState.START || status == ActivityState.RESUME) |
|
||||||
|
|
||||||
return if (isCommitterResumed) { |
|
||||||
transaction.commit() |
|
||||||
false |
|
||||||
} else { |
|
||||||
mPendingTransactions.add(transaction) |
|
||||||
true |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResumeFragments() { |
|
||||||
if (mPendingTransactions.isNotEmpty()) { |
|
||||||
mPendingTransactions.forEach { it.commit() } |
|
||||||
mPendingTransactions.clear() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private class SafelyFragmentTransactionFragmentDelegate : FragmentDelegate<Fragment> { |
|
||||||
|
|
||||||
private val pendingTransactions = mutableListOf<FragmentTransaction>() |
|
||||||
|
|
||||||
fun safeCommit(@NonNull fragment: Fragment, @NonNull transaction: FragmentTransaction): Boolean { |
|
||||||
return if (fragment.isResumed) { |
|
||||||
transaction.commit() |
|
||||||
false |
|
||||||
} else { |
|
||||||
pendingTransactions.add(transaction) |
|
||||||
true |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
if (pendingTransactions.isNotEmpty()) { |
|
||||||
pendingTransactions.forEach { it.commit() } |
|
||||||
pendingTransactions.clear() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
class EnhanceFragmentTransaction constructor( |
|
||||||
private val fragmentManager: FragmentManager, |
|
||||||
private val fragmentTransaction: FragmentTransaction |
|
||||||
) : FragmentTransaction() { |
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------ |
|
||||||
// extra functions |
|
||||||
//------------------------------------------------------------------------------------------------ |
|
||||||
|
|
||||||
/** |
|
||||||
* 把 [fragment] 添加到回退栈中,并 hide 其他 fragment, |
|
||||||
* 如果 [containerId]==0,则使用 [com.android.base.app.Sword.setDefaultFragmentContainerId] 中配置的 id, |
|
||||||
* 如果 [tag] ==null 则使用 fragment 对应 class 的全限定类名。 |
|
||||||
*/ |
|
||||||
fun addWithStack(containerId: Int = 0, fragment: Fragment, tag: String? = null, transition: Boolean = true): EnhanceFragmentTransaction { |
|
||||||
//set add to stack |
|
||||||
val nonnullTag = (tag ?: fragment.javaClassName()) |
|
||||||
addToBackStack(nonnullTag) |
|
||||||
//add |
|
||||||
fragmentTransaction.add(confirmLayoutId(containerId), fragment, nonnullTag) |
|
||||||
//hide top |
|
||||||
hideTopFragment() |
|
||||||
if (transition) { |
|
||||||
//set a transition |
|
||||||
setOpeningTransition() |
|
||||||
} |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* replace 方式把 [fragment] 添加到回退栈中,如果 [containerId]==0,则使用 [com.android.base.app.Sword.setDefaultFragmentContainerId] 中配置的 id, |
|
||||||
* 如果 [tag] ==null 则使用 fragment 对应 class 的全限定类名。 |
|
||||||
*/ |
|
||||||
fun replaceWithStack(containerId: Int = 0, fragment: Fragment, tag: String? = null, transition: Boolean = true): EnhanceFragmentTransaction { |
|
||||||
//set add to stack |
|
||||||
val nonnullTag = (tag ?: fragment.javaClassName()) |
|
||||||
addToBackStack(nonnullTag) |
|
||||||
//add |
|
||||||
fragmentTransaction.replace(confirmLayoutId(containerId), fragment, nonnullTag) |
|
||||||
//set a transition |
|
||||||
if (transition) { |
|
||||||
setOpeningTransition() |
|
||||||
} |
|
||||||
return this |
|
||||||
} |
|
||||||
|
|
||||||
private fun confirmLayoutId(layoutId: Int): Int { |
|
||||||
return if (layoutId == 0) { |
|
||||||
FragmentConfig.defaultContainerId() |
|
||||||
} else { |
|
||||||
layoutId |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 添加 [fragment],默认使用 [com.android.base.app.Sword.setDefaultFragmentContainerId] 中配置的 id,如果 [tag] 为null,则使用 [fragment] 的全限定类。 |
|
||||||
*/ |
|
||||||
fun addFragment(fragment: Fragment, tag: String? = null): FragmentTransaction { |
|
||||||
val nonnullTag = (tag ?: fragment.javaClassName()) |
|
||||||
return fragmentTransaction.add(FragmentConfig.defaultContainerId(), fragment, nonnullTag) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 替换为 [fragment],id 使用 [com.android.base.app.Sword.setDefaultFragmentContainerId] 中配置的 id,如果 [tag] 为null,则使用 [fragment] 的全限定类名。 |
|
||||||
*/ |
|
||||||
fun replaceFragment(fragment: Fragment, tag: String? = null, transition: Boolean = true): FragmentTransaction { |
|
||||||
val nonnullTag = (tag ?: fragment.javaClassName()) |
|
||||||
if (transition) { |
|
||||||
setOpeningTransition() |
|
||||||
} |
|
||||||
return fragmentTransaction.replace(FragmentConfig.defaultContainerId(), fragment, nonnullTag) |
|
||||||
} |
|
||||||
|
|
||||||
/**隐藏所有的 fragment */ |
|
||||||
private fun hideFragments() { |
|
||||||
for (fragment in fragmentManager.fragments) { |
|
||||||
if (fragment != null && fragment.isVisible) { |
|
||||||
fragmentTransaction.hide(fragment) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/**隐藏第一个可见的 fragment */ |
|
||||||
private fun hideTopFragment() { |
|
||||||
fragmentManager.fragments.lastOrNull { it.isVisible }?.let { |
|
||||||
fragmentTransaction.hide(it) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fun setOpeningTransition(): FragmentTransaction { |
|
||||||
return fragmentTransaction.setTransition(TRANSIT_FRAGMENT_OPEN) |
|
||||||
} |
|
||||||
|
|
||||||
fun setClosingTransition(): FragmentTransaction { |
|
||||||
return fragmentTransaction.setTransition(TRANSIT_FRAGMENT_CLOSE) |
|
||||||
} |
|
||||||
|
|
||||||
fun setFadingTransition(): FragmentTransaction { |
|
||||||
return fragmentTransaction.setTransition(TRANSIT_FRAGMENT_FADE) |
|
||||||
} |
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------ |
|
||||||
// original functions |
|
||||||
//------------------------------------------------------------------------------------------------ |
|
||||||
override fun setBreadCrumbShortTitle(res: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setBreadCrumbShortTitle(res) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setBreadCrumbShortTitle(text: CharSequence?): FragmentTransaction { |
|
||||||
return fragmentTransaction.setBreadCrumbShortTitle(text) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setPrimaryNavigationFragment(fragment: Fragment?): FragmentTransaction { |
|
||||||
return fragmentTransaction.setPrimaryNavigationFragment(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun runOnCommit(runnable: Runnable): FragmentTransaction { |
|
||||||
return fragmentTransaction.runOnCommit(runnable) |
|
||||||
} |
|
||||||
|
|
||||||
override fun add(fragment: Fragment, tag: String?): FragmentTransaction { |
|
||||||
return fragmentTransaction.add(fragment, tag) |
|
||||||
} |
|
||||||
|
|
||||||
override fun add(containerViewId: Int, fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.add(containerViewId, fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun add(containerViewId: Int, fragment: Fragment, tag: String?): FragmentTransaction { |
|
||||||
return fragmentTransaction.add(containerViewId, fragment, tag) |
|
||||||
} |
|
||||||
|
|
||||||
override fun hide(fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.hide(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun replace(containerViewId: Int, fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.replace(containerViewId, fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun replace(containerViewId: Int, fragment: Fragment, tag: String?): FragmentTransaction { |
|
||||||
return fragmentTransaction.replace(containerViewId, fragment, tag) |
|
||||||
} |
|
||||||
|
|
||||||
override fun detach(fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.detach(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated("") |
|
||||||
override fun setAllowOptimization(allowOptimization: Boolean): FragmentTransaction { |
|
||||||
return fragmentTransaction.setAllowOptimization(allowOptimization) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setCustomAnimations(enter: Int, exit: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setCustomAnimations(enter, exit) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setCustomAnimations(enter: Int, exit: Int, popEnter: Int, popExit: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setCustomAnimations(enter, exit, popEnter, popExit) |
|
||||||
} |
|
||||||
|
|
||||||
override fun addToBackStack(name: String?): FragmentTransaction { |
|
||||||
return fragmentTransaction.addToBackStack(name) |
|
||||||
} |
|
||||||
|
|
||||||
override fun disallowAddToBackStack(): FragmentTransaction { |
|
||||||
return fragmentTransaction.disallowAddToBackStack() |
|
||||||
} |
|
||||||
|
|
||||||
override fun setTransitionStyle(styleRes: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setTransitionStyle(styleRes) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setTransition(transit: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setTransition(transit) |
|
||||||
} |
|
||||||
|
|
||||||
override fun attach(fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.attach(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun show(fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.show(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun isEmpty(): Boolean { |
|
||||||
return fragmentTransaction.isEmpty |
|
||||||
} |
|
||||||
|
|
||||||
override fun remove(fragment: Fragment): FragmentTransaction { |
|
||||||
return fragmentTransaction.remove(fragment) |
|
||||||
} |
|
||||||
|
|
||||||
override fun isAddToBackStackAllowed(): Boolean { |
|
||||||
return fragmentTransaction.isAddToBackStackAllowed |
|
||||||
} |
|
||||||
|
|
||||||
override fun addSharedElement(sharedElement: View, name: String): FragmentTransaction { |
|
||||||
return fragmentTransaction.addSharedElement(sharedElement, name) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setBreadCrumbTitle(res: Int): FragmentTransaction { |
|
||||||
return fragmentTransaction.setBreadCrumbTitle(res) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setBreadCrumbTitle(text: CharSequence?): FragmentTransaction { |
|
||||||
return fragmentTransaction.setBreadCrumbTitle(text) |
|
||||||
} |
|
||||||
|
|
||||||
override fun setReorderingAllowed(reorderingAllowed: Boolean): FragmentTransaction { |
|
||||||
return fragmentTransaction.setReorderingAllowed(reorderingAllowed) |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated("commit will be called automatically") |
|
||||||
override fun commit(): Int { |
|
||||||
throw UnsupportedOperationException("commit will be called automatically") |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated("commitAllowingStateLoss will be called automatically") |
|
||||||
override fun commitAllowingStateLoss(): Int { |
|
||||||
throw UnsupportedOperationException("commitAllowingStateLoss will be called automatically") |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated("commitNow will be called automatically", ReplaceWith("throw UnsupportedOperationException(\"commitNow will be called automatically\")")) |
|
||||||
override fun commitNow() { |
|
||||||
throw UnsupportedOperationException("commitNow will be called automatically") |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated("commitNowAllowingStateLoss will be called automatically", ReplaceWith("throw UnsupportedOperationException(\"commitNowAllowingStateLoss will be called automatically\")")) |
|
||||||
override fun commitNowAllowingStateLoss() { |
|
||||||
throw UnsupportedOperationException("commitNowAllowingStateLoss will be called automatically") |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,211 +0,0 @@ |
|||||||
package com.android.base.app.fragment.tools; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.os.Bundle; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment; |
|
||||||
import androidx.fragment.app.FragmentManager; |
|
||||||
import androidx.fragment.app.FragmentTransaction; |
|
||||||
|
|
||||||
public abstract class TabManager { |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") public static final int ATTACH_DETACH = 1; |
|
||||||
@SuppressWarnings("WeakerAccess") public static final int SHOW_HIDE = 2; |
|
||||||
|
|
||||||
private final FragmentManager mFragmentManager; |
|
||||||
private final int mContainerId; |
|
||||||
private final Tabs mMainTabs; |
|
||||||
private final Context mContext; |
|
||||||
|
|
||||||
private FragmentInfo mCurrentFragmentInfo; |
|
||||||
|
|
||||||
private static final String CURRENT_ID_KET = "main_tab_id"; |
|
||||||
private static final int NONE = -1; |
|
||||||
private int mCurrentId = NONE; |
|
||||||
private final int mOperationType; |
|
||||||
|
|
||||||
public TabManager(Context context, FragmentManager fragmentManager, Tabs tabs, int containerId) { |
|
||||||
this(context, fragmentManager, tabs, containerId, ATTACH_DETACH); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param operationType {@link #ATTACH_DETACH} or {@link #SHOW_HIDE} |
|
||||||
*/ |
|
||||||
public TabManager(Context context, FragmentManager fragmentManager, Tabs tabs, int containerId, int operationType) { |
|
||||||
if (operationType != ATTACH_DETACH && operationType != SHOW_HIDE) { |
|
||||||
throw new IllegalArgumentException("the operationType must be ATTACH_DETACH or SHOW_HIDE"); |
|
||||||
} |
|
||||||
mMainTabs = tabs; |
|
||||||
mContainerId = containerId; |
|
||||||
mContext = context; |
|
||||||
mFragmentManager = fragmentManager; |
|
||||||
mOperationType = operationType; |
|
||||||
} |
|
||||||
|
|
||||||
public final void setup(Bundle bundle) { |
|
||||||
int pageId = mMainTabs.homePage().getPageId(); |
|
||||||
if (bundle == null) { |
|
||||||
switchPage(pageId); |
|
||||||
} else { |
|
||||||
mCurrentId = bundle.getInt(CURRENT_ID_KET, pageId); |
|
||||||
restoreState(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void restoreState() { |
|
||||||
List<FragmentInfo> pages = mMainTabs.getPages(); |
|
||||||
for (FragmentInfo page : pages) { |
|
||||||
page.setInstance(mFragmentManager.findFragmentByTag(page.getTag())); |
|
||||||
if (mCurrentId == page.getPageId()) { |
|
||||||
mCurrentFragmentInfo = page; |
|
||||||
} |
|
||||||
} |
|
||||||
if (mCurrentId == NONE) { |
|
||||||
doChangeTab(mMainTabs.homePage().getPageId()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void switchPage(int pageId) { |
|
||||||
if (mCurrentId == pageId) { |
|
||||||
return; |
|
||||||
} |
|
||||||
FragmentTransaction ft = null; |
|
||||||
if (mCurrentFragmentInfo != null) { |
|
||||||
Fragment fragment = mCurrentFragmentInfo.getInstance(); |
|
||||||
if (fragment != null) { |
|
||||||
ft = mFragmentManager.beginTransaction(); |
|
||||||
hideOrDetach(ft, fragment); |
|
||||||
} |
|
||||||
} |
|
||||||
if (ft != null) { |
|
||||||
ft.commit(); |
|
||||||
} |
|
||||||
doChangeTab(pageId); |
|
||||||
} |
|
||||||
|
|
||||||
private void hideOrDetach(FragmentTransaction ft, Fragment fragment) { |
|
||||||
if (mOperationType == SHOW_HIDE) { |
|
||||||
ft.hide(fragment); |
|
||||||
} else { |
|
||||||
ft.detach(fragment); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void showOrAttach(FragmentTransaction fragmentTransaction, Fragment fragment) { |
|
||||||
if (mOperationType == SHOW_HIDE) { |
|
||||||
fragmentTransaction.show(fragment); |
|
||||||
} else { |
|
||||||
fragmentTransaction.attach(fragment); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void doChangeTab(int fragmentId) { |
|
||||||
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); |
|
||||||
FragmentInfo fragmentInfo = mMainTabs.getFragmentInfo(fragmentId); |
|
||||||
Fragment fragment = fragmentInfo.getInstance(); |
|
||||||
if (fragment != null) { |
|
||||||
showOrAttach(fragmentTransaction, fragment); |
|
||||||
} else { |
|
||||||
Fragment newFragment = fragmentInfo.newFragment(mContext); |
|
||||||
fragmentInfo.setInstance(newFragment); |
|
||||||
onFragmentCreated(fragmentId, newFragment); |
|
||||||
fragmentTransaction.add(mContainerId, newFragment, fragmentInfo.getTag()); |
|
||||||
} |
|
||||||
mCurrentFragmentInfo = fragmentInfo; |
|
||||||
mCurrentId = fragmentId; |
|
||||||
fragmentTransaction.commit(); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public void selectTabByPosition(int position) { |
|
||||||
switchPage(mMainTabs.getIdByPosition(position)); |
|
||||||
} |
|
||||||
|
|
||||||
public void selectTabById(int tabId) { |
|
||||||
selectTabByPosition(mMainTabs.getPositionById(tabId)); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public int getCurrentPosition() { |
|
||||||
return mMainTabs.getPositionById(mCurrentId); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess,unused") |
|
||||||
protected void onFragmentCreated(int id, Fragment newFragment) { |
|
||||||
} |
|
||||||
|
|
||||||
public void onSaveInstanceState(Bundle bundle) { |
|
||||||
bundle.putInt(CURRENT_ID_KET, mCurrentId); |
|
||||||
} |
|
||||||
|
|
||||||
public static abstract class Tabs { |
|
||||||
|
|
||||||
private final List<FragmentInfo> mPages; |
|
||||||
|
|
||||||
protected Tabs() { |
|
||||||
mPages = new ArrayList<>(); |
|
||||||
} |
|
||||||
|
|
||||||
protected void add(FragmentInfo page) { |
|
||||||
mPages.add(page); |
|
||||||
} |
|
||||||
|
|
||||||
FragmentInfo homePage() { |
|
||||||
return mPages.get(defaultIndex()); |
|
||||||
} |
|
||||||
|
|
||||||
protected int defaultIndex() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
public int size() { |
|
||||||
return mPages.size(); |
|
||||||
} |
|
||||||
|
|
||||||
FragmentInfo getFragmentInfo(int id) { |
|
||||||
for (FragmentInfo page : mPages) { |
|
||||||
if (page.getPageId() == id) { |
|
||||||
return page; |
|
||||||
} |
|
||||||
} |
|
||||||
throw new IllegalArgumentException("MainPages not has this pageId :" + id); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param clazz Fragment对应的clazz |
|
||||||
* @return pagerId ,没有则返回-1 |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
int getIdByClazz(Class<? extends Fragment> clazz) { |
|
||||||
for (FragmentInfo page : mPages) { |
|
||||||
if (page.getClazz() == clazz) { |
|
||||||
return page.getPageId(); |
|
||||||
} |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
List<FragmentInfo> getPages() { |
|
||||||
return Collections.unmodifiableList(mPages); |
|
||||||
} |
|
||||||
|
|
||||||
private int getPositionById(int tabId) { |
|
||||||
int size = mPages.size(); |
|
||||||
for (int i = 0; i < size; i++) { |
|
||||||
if (mPages.get(i).getPageId() == tabId) { |
|
||||||
return i; |
|
||||||
} |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
private int getIdByPosition(int position) { |
|
||||||
return mPages.get(position).getPageId(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,52 +0,0 @@ |
|||||||
package com.android.base.app.fragment |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import androidx.lifecycle.LifecycleOwner |
|
||||||
import androidx.lifecycle.lifecycleScope |
|
||||||
import com.android.base.app.ui.LoadingView |
|
||||||
import kotlinx.coroutines.CancellationException |
|
||||||
import kotlinx.coroutines.delay |
|
||||||
import kotlinx.coroutines.launch |
|
||||||
|
|
||||||
/** |
|
||||||
*@author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2019-10-16 17:28 |
|
||||||
*/ |
|
||||||
internal fun <T> T.dismissDialog(recentShowingDialogTime: Long, minimumMills: Long, onDismiss: () -> Unit) where T : LoadingView, T : LifecycleOwner { |
|
||||||
|
|
||||||
if (!isLoadingDialogShowing()) { |
|
||||||
onDismiss() |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
val dialogShowingTime = System.currentTimeMillis() - recentShowingDialogTime |
|
||||||
|
|
||||||
if (dialogShowingTime >= minimumMills) { |
|
||||||
dismissLoadingDialog() |
|
||||||
onDismiss() |
|
||||||
} else { |
|
||||||
lifecycleScope.launch { |
|
||||||
try { |
|
||||||
delay(minimumMills - dialogShowingTime) |
|
||||||
dismissLoadingDialog() |
|
||||||
onDismiss() |
|
||||||
} catch (e: CancellationException) { |
|
||||||
onDismiss() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private const val FRAGMENT_STATE_KEY = "fragment_state_key" |
|
||||||
|
|
||||||
internal fun saveInstanceState(outState: Bundle, _state: Bundle?) { |
|
||||||
_state?.let { |
|
||||||
outState.putBundle(FRAGMENT_STATE_KEY, it) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal fun getInstanceState(state: Bundle?): Bundle? { |
|
||||||
return state?.getBundle(FRAGMENT_STATE_KEY) |
|
||||||
} |
|
@ -1,44 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
import androidx.annotation.CallSuper |
|
||||||
import java.lang.ref.WeakReference |
|
||||||
|
|
||||||
abstract class AbstractPresenter<V : IBaseView> : IPresenter<V> { |
|
||||||
|
|
||||||
private var _view: WeakReference<V>? = null |
|
||||||
|
|
||||||
protected val view: V? |
|
||||||
get() = if (_view != null) { |
|
||||||
_view?.get() |
|
||||||
} else null |
|
||||||
|
|
||||||
protected val isViewAttached: Boolean |
|
||||||
get() = _view != null && _view?.get() != null |
|
||||||
|
|
||||||
final override fun bindView(view: V?) { |
|
||||||
if (view == null) { |
|
||||||
throw NullPointerException("Presenter bindView --> view is null") |
|
||||||
} |
|
||||||
if (_view != null) { |
|
||||||
throw UnsupportedOperationException("Presenter bindView --> the view already bind") |
|
||||||
} |
|
||||||
_view = WeakReference(view) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPostStart() {} |
|
||||||
|
|
||||||
override fun onPause() { |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
} |
|
||||||
|
|
||||||
@CallSuper |
|
||||||
override fun onDestroy() { |
|
||||||
if (_view != null) { |
|
||||||
_view?.clear() |
|
||||||
_view = null |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,3 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
interface IBaseView |
|
@ -1,13 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
|
|
||||||
interface IPresenter<V : IBaseView> : Lifecycle { |
|
||||||
|
|
||||||
/** |
|
||||||
* bind a view |
|
||||||
* |
|
||||||
* @param view V |
|
||||||
*/ |
|
||||||
fun bindView(view: V?) |
|
||||||
|
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2017-04-18 16:23 |
|
||||||
*/ |
|
||||||
interface Lifecycle { |
|
||||||
|
|
||||||
/** |
|
||||||
* start the Lifecycle , initialize something, will be called only once |
|
||||||
*/ |
|
||||||
fun onStart() |
|
||||||
|
|
||||||
/** |
|
||||||
* will be called when view is ready. |
|
||||||
*/ |
|
||||||
fun onPostStart() |
|
||||||
|
|
||||||
fun onResume() |
|
||||||
|
|
||||||
fun onPause() |
|
||||||
|
|
||||||
/** |
|
||||||
* destroy the Lifecycle and release resource, will be called only once |
|
||||||
*/ |
|
||||||
fun onDestroy() |
|
||||||
|
|
||||||
} |
|
||||||
|
|
@ -1,66 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
import android.os.Bundle |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import android.view.View |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegate |
|
||||||
import com.android.base.app.fragment.delegates.FragmentDelegateOwner |
|
||||||
|
|
||||||
|
|
||||||
class PresenterBinder constructor(private val lifecycle: Lifecycle) : FragmentDelegate<Fragment> { |
|
||||||
|
|
||||||
private var isCalled: Boolean = false |
|
||||||
private var host: Fragment? = null |
|
||||||
|
|
||||||
override fun onAttachToFragment(fragment: Fragment) { |
|
||||||
host = fragment |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDetachFromFragment() { |
|
||||||
host = null |
|
||||||
} |
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) { |
|
||||||
if (!isCalled) { |
|
||||||
lifecycle.onStart() |
|
||||||
val activity = host?.activity |
|
||||||
activity?.findViewById<View>(android.R.id.content)?.post { lifecycle.onPostStart() } |
|
||||||
isCalled = true |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun onResume() { |
|
||||||
lifecycle.onResume() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onPause() { |
|
||||||
lifecycle.onPause() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onDestroy() { |
|
||||||
lifecycle.onDestroy() |
|
||||||
} |
|
||||||
|
|
||||||
companion object { |
|
||||||
|
|
||||||
/** |
|
||||||
* @param v The MVP of the V |
|
||||||
* @param p The MVP of the P |
|
||||||
* @param <V> The MVP of the V |
|
||||||
</V> */ |
|
||||||
fun <V : IBaseView> bind(fragmentDelegateOwner: FragmentDelegateOwner, v: V, p: IPresenter<V>): PresenterBinder { |
|
||||||
p.bindView(v) |
|
||||||
val lifecycleDelegate = PresenterBinder(p) |
|
||||||
fragmentDelegateOwner.addDelegate(lifecycleDelegate) |
|
||||||
return lifecycleDelegate |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
fun <V : IBaseView> FragmentDelegateOwner.bindPresenter(v: V, p: IPresenter<V>): PresenterBinder { |
|
||||||
p.bindView(v) |
|
||||||
val lifecycleDelegate = PresenterBinder(p) |
|
||||||
addDelegate(lifecycleDelegate) |
|
||||||
return lifecycleDelegate |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
package com.android.base.app.mvp |
|
||||||
|
|
||||||
import androidx.annotation.CallSuper |
|
||||||
import com.android.base.rx.autodispose.AutoDisposeLifecycleScopeProviderEx |
|
||||||
import com.uber.autodispose.lifecycle.CorrespondingEventsFunction |
|
||||||
import com.uber.autodispose.lifecycle.LifecycleEndedException |
|
||||||
import com.uber.autodispose.lifecycle.LifecycleScopes |
|
||||||
import io.reactivex.CompletableSource |
|
||||||
import io.reactivex.Observable |
|
||||||
import io.reactivex.subjects.BehaviorSubject |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* work with RxJava |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Date : 2016-10-19 12:17 |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
*/ |
|
||||||
abstract class RxPresenter<V : IBaseView> : AbstractPresenter<V>(), AutoDisposeLifecycleScopeProviderEx<RxPresenter.LifecycleEvent> { |
|
||||||
|
|
||||||
private val lifecycleSubject = BehaviorSubject.create<LifecycleEvent>() |
|
||||||
|
|
||||||
enum class LifecycleEvent { |
|
||||||
START, |
|
||||||
DESTROY |
|
||||||
} |
|
||||||
|
|
||||||
@CallSuper |
|
||||||
override fun onStart() { |
|
||||||
lifecycleSubject.onNext(LifecycleEvent.START) |
|
||||||
} |
|
||||||
|
|
||||||
@CallSuper |
|
||||||
override fun onDestroy() { |
|
||||||
lifecycleSubject.onNext(LifecycleEvent.DESTROY) |
|
||||||
super@RxPresenter.onDestroy() |
|
||||||
} |
|
||||||
|
|
||||||
final override fun lifecycle(): Observable<LifecycleEvent> { |
|
||||||
return lifecycleSubject |
|
||||||
} |
|
||||||
|
|
||||||
final override fun correspondingEvents(): CorrespondingEventsFunction<LifecycleEvent> { |
|
||||||
return LIFECYCLE_CORRESPONDING_EVENTS |
|
||||||
} |
|
||||||
|
|
||||||
final override fun peekLifecycle(): LifecycleEvent? { |
|
||||||
return lifecycleSubject.value |
|
||||||
} |
|
||||||
|
|
||||||
final override fun requestScope(): CompletableSource { |
|
||||||
return LifecycleScopes.resolveScopeFromLifecycle<LifecycleEvent>(this) |
|
||||||
} |
|
||||||
|
|
||||||
companion object { |
|
||||||
internal val LIFECYCLE_CORRESPONDING_EVENTS: CorrespondingEventsFunction<LifecycleEvent> = CorrespondingEventsFunction { |
|
||||||
return@CorrespondingEventsFunction when (it) { |
|
||||||
LifecycleEvent.START -> LifecycleEvent.DESTROY |
|
||||||
else -> throw LifecycleEndedException("Cannot bind to LifecycleEvent when outside of it.") |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,61 +0,0 @@ |
|||||||
package com.android.base.app.mvvm |
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.CallSuper |
|
||||||
import androidx.lifecycle.ViewModel |
|
||||||
import com.android.base.rx.autodispose.AutoDisposeLifecycleScopeProviderEx |
|
||||||
import com.uber.autodispose.lifecycle.CorrespondingEventsFunction |
|
||||||
import com.uber.autodispose.lifecycle.LifecycleEndedException |
|
||||||
import com.uber.autodispose.lifecycle.LifecycleScopes |
|
||||||
import io.reactivex.CompletableSource |
|
||||||
import io.reactivex.Observable |
|
||||||
import io.reactivex.subjects.BehaviorSubject |
|
||||||
|
|
||||||
/** |
|
||||||
* ArchViewModel work with Rx |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2017-04-18 16:25 |
|
||||||
*/ |
|
||||||
abstract class RxViewModel : ViewModel(), AutoDisposeLifecycleScopeProviderEx<RxViewModel.ViewModelEvent> { |
|
||||||
|
|
||||||
private val archLifecycleSubject = BehaviorSubject.createDefault(ViewModelEvent.CREATED) |
|
||||||
|
|
||||||
enum class ViewModelEvent { |
|
||||||
CREATED, CLEARED |
|
||||||
} |
|
||||||
|
|
||||||
@CallSuper |
|
||||||
override fun onCleared() { |
|
||||||
archLifecycleSubject.onNext(ViewModelEvent.CLEARED) |
|
||||||
super.onCleared() |
|
||||||
} |
|
||||||
|
|
||||||
final override fun correspondingEvents(): CorrespondingEventsFunction<ViewModelEvent> { |
|
||||||
return CORRESPONDING_EVENTS |
|
||||||
} |
|
||||||
|
|
||||||
final override fun lifecycle(): Observable<ViewModelEvent> { |
|
||||||
return archLifecycleSubject.hide() |
|
||||||
} |
|
||||||
|
|
||||||
final override fun peekLifecycle(): ViewModelEvent? { |
|
||||||
return archLifecycleSubject.value |
|
||||||
} |
|
||||||
|
|
||||||
final override fun requestScope(): CompletableSource { |
|
||||||
return LifecycleScopes.resolveScopeFromLifecycle(this) |
|
||||||
} |
|
||||||
|
|
||||||
companion object { |
|
||||||
private val CORRESPONDING_EVENTS = CorrespondingEventsFunction<ViewModelEvent> { event -> |
|
||||||
when (event) { |
|
||||||
ViewModelEvent.CREATED -> ViewModelEvent.CLEARED |
|
||||||
else -> throw LifecycleEndedException( |
|
||||||
"Cannot bind to ViewModel lifecycle after onCleared.") |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,39 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
import com.android.base.adapter.DataManager; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: ztiany3@gmail.com |
|
||||||
* Date : 2018-04-27 14:04 |
|
||||||
*/ |
|
||||||
public class AutoPageNumber extends PageNumber { |
|
||||||
|
|
||||||
private final DataManager mDataManager; |
|
||||||
private final RefreshListLayout mRefreshListLayout; |
|
||||||
|
|
||||||
public AutoPageNumber(RefreshListLayout refreshListLayout, DataManager dataManager) { |
|
||||||
mRefreshListLayout = refreshListLayout; |
|
||||||
mDataManager = dataManager; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getCurrentPage() { |
|
||||||
return calcPageNumber(mDataManager.getDataSize()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getLoadingPage() { |
|
||||||
if (mRefreshListLayout.isRefreshing()) { |
|
||||||
return getPageStart(); |
|
||||||
} else { |
|
||||||
return getCurrentPage() + 1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemCount() { |
|
||||||
return mDataManager.getDataSize(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
|
|
||||||
import com.android.base.R; |
|
||||||
|
|
||||||
public class CommonId { |
|
||||||
|
|
||||||
private CommonId() { |
|
||||||
throw new UnsupportedOperationException(); |
|
||||||
} |
|
||||||
|
|
||||||
public static final int REFRESH_ID = R.id.base_refresh_layout; |
|
||||||
public static final int STATE_ID = R.id.base_state_layout; |
|
||||||
public static final int LIST_ID = R.id.base_list_layout; |
|
||||||
|
|
||||||
public static final int RETRY_TV_ID = R.id.base_retry_tv; |
|
||||||
public static final int RETRY_IV_ID = R.id.base_retry_icon; |
|
||||||
public static final int RETRY_BTN_ID = R.id.base_retry_btn; |
|
||||||
|
|
||||||
public static final int TOOLBAR_ID = R.id.common_toolbar; |
|
||||||
|
|
||||||
} |
|
@ -1,11 +0,0 @@ |
|||||||
package com.android.base.app.ui |
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner |
|
||||||
import androidx.lifecycle.LiveData |
|
||||||
import androidx.lifecycle.Observer |
|
||||||
import com.android.base.app.Sword |
|
||||||
import com.android.base.data.State |
|
||||||
import timber.log.Timber |
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,25 +0,0 @@ |
|||||||
package com.android.base.app.ui |
|
||||||
|
|
||||||
import androidx.annotation.StringRes |
|
||||||
|
|
||||||
/** |
|
||||||
* 显示通用的 LoadingDialog 和 Message |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2016-12-02 15:12 |
|
||||||
*/ |
|
||||||
interface LoadingView { |
|
||||||
|
|
||||||
fun showLoadingDialog() |
|
||||||
fun showLoadingDialog(cancelable: Boolean) |
|
||||||
fun showLoadingDialog(message: CharSequence, cancelable: Boolean) |
|
||||||
fun showLoadingDialog(@StringRes messageId: Int, cancelable: Boolean) |
|
||||||
fun dismissLoadingDialog() |
|
||||||
fun dismissLoadingDialog(minimumMills: Long, onDismiss: () -> Unit) |
|
||||||
fun isLoadingDialogShowing(): Boolean |
|
||||||
|
|
||||||
fun showMessage(message: CharSequence) |
|
||||||
fun showMessage(@StringRes messageId: Int) |
|
||||||
|
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
import static com.android.base.app.ui.StateLayoutConfig.*; |
|
||||||
|
|
||||||
public interface OnRetryActionListener { |
|
||||||
|
|
||||||
void onRetry(@RetryableState int state); |
|
||||||
|
|
||||||
} |
|
@ -1,99 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* @version 1.0 |
|
||||||
*/ |
|
||||||
public abstract class PageNumber { |
|
||||||
|
|
||||||
private static int PAGE_START = 1; |
|
||||||
private static int PAGE_SIZE = 20; |
|
||||||
|
|
||||||
private int mPageStart; |
|
||||||
private int mPageSize; |
|
||||||
|
|
||||||
private Object mPageToken; |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess,unused") |
|
||||||
public PageNumber() { |
|
||||||
this(PAGE_START, PAGE_SIZE); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public PageNumber(int pageStart, int pageSize) { |
|
||||||
mPageStart = pageStart; |
|
||||||
mPageSize = pageSize; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public void setPageToken(Object pageToken) { |
|
||||||
mPageToken = pageToken; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unchecked,unused") |
|
||||||
public <T> T getPageToken() { |
|
||||||
return (T) mPageToken; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public int getPageSize() { |
|
||||||
return mPageSize; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") |
|
||||||
public int getPageStart() { |
|
||||||
return mPageStart; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean hasMore(int size) { |
|
||||||
return size >= mPageSize; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据page size计算当前的页码 |
|
||||||
*/ |
|
||||||
int calcPageNumber(int dataSize) { |
|
||||||
/* s=1 s=0 |
|
||||||
19/20 = 0 1 0 |
|
||||||
21/20 = 1 2 1 |
|
||||||
54/20 = 2 3 2 |
|
||||||
64/20 = 3 4 3 |
|
||||||
*/ |
|
||||||
int pageNumber; |
|
||||||
int pageSize = mPageSize; |
|
||||||
int pageStart = mPageStart; |
|
||||||
if (pageStart == 0) { |
|
||||||
pageNumber = (dataSize / pageSize) - 1; |
|
||||||
pageNumber = pageNumber < 0 ? 0 : pageNumber; |
|
||||||
} else if (pageStart == 1) { |
|
||||||
pageNumber = (dataSize / pageSize); |
|
||||||
pageNumber = pageNumber < 1 ? 1 : pageNumber; |
|
||||||
} else { |
|
||||||
throw new RuntimeException("pageStart must be 0 or 1"); |
|
||||||
} |
|
||||||
return pageNumber; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public void changePageSetting(int pageStart, int pageSize) { |
|
||||||
mPageStart = pageStart; |
|
||||||
mPageSize = pageSize; |
|
||||||
} |
|
||||||
|
|
||||||
public static void setDefaultPageStart(int pageSize) { |
|
||||||
PAGE_START = pageSize; |
|
||||||
} |
|
||||||
|
|
||||||
public static void setDefaultPageSize(int pageSize) { |
|
||||||
PAGE_SIZE = pageSize; |
|
||||||
} |
|
||||||
|
|
||||||
public abstract int getCurrentPage(); |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public abstract int getLoadingPage(); |
|
||||||
|
|
||||||
@SuppressWarnings("unused") |
|
||||||
public abstract int getItemCount(); |
|
||||||
|
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* 列表视图行为 |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2017-03-29 22:16 |
|
||||||
*/ |
|
||||||
public interface RefreshListLayout<T> extends RefreshStateLayout { |
|
||||||
|
|
||||||
void replaceData(List<T> data); |
|
||||||
|
|
||||||
void addData(List<T> data); |
|
||||||
|
|
||||||
PageNumber getPager(); |
|
||||||
|
|
||||||
boolean isEmpty(); |
|
||||||
|
|
||||||
void loadMoreCompleted(boolean hasMore); |
|
||||||
|
|
||||||
void loadMoreFailed(); |
|
||||||
|
|
||||||
boolean isLoadingMore(); |
|
||||||
|
|
||||||
@Override |
|
||||||
boolean isRefreshing(); |
|
||||||
|
|
||||||
} |
|
@ -1,40 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
/** |
|
||||||
* <br/> 对下拉刷新的抽象 |
|
||||||
* <br/> Email: 1169654504@qq.com |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* @version 1.0 |
|
||||||
*/ |
|
||||||
public interface RefreshLoadMoreView { |
|
||||||
|
|
||||||
void autoRefresh(); |
|
||||||
|
|
||||||
void refreshCompleted(); |
|
||||||
|
|
||||||
void loadMoreCompleted(boolean hasMore); |
|
||||||
|
|
||||||
void loadMoreFailed(); |
|
||||||
|
|
||||||
void setRefreshHandler(RefreshHandler refreshHandler); |
|
||||||
|
|
||||||
void setLoadMoreHandler(LoadMoreHandler loadMoreHandler); |
|
||||||
|
|
||||||
boolean isRefreshing(); |
|
||||||
|
|
||||||
boolean isLoadingMore(); |
|
||||||
|
|
||||||
void setRefreshEnable(boolean enable); |
|
||||||
|
|
||||||
void setLoadMoreEnable(boolean enable); |
|
||||||
|
|
||||||
interface RefreshHandler { |
|
||||||
void onRefresh(); |
|
||||||
} |
|
||||||
|
|
||||||
interface LoadMoreHandler { |
|
||||||
void onRefresh(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
/** |
|
||||||
* RefreshLoadMoreView Factory |
|
||||||
* |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* @version 1.0 |
|
||||||
*/ |
|
||||||
public class RefreshLoadViewFactory { |
|
||||||
|
|
||||||
private static Factory sFactory; |
|
||||||
|
|
||||||
public static RefreshLoadMoreView createRefreshView(View view) { |
|
||||||
if (sFactory != null) { |
|
||||||
return sFactory.createRefreshView(view); |
|
||||||
} |
|
||||||
throw new IllegalArgumentException("RefreshLoadViewFactory does not support create RefreshLoadMoreView . the view :" + view); |
|
||||||
} |
|
||||||
|
|
||||||
public static void registerFactory(Factory factory) { |
|
||||||
sFactory = factory; |
|
||||||
} |
|
||||||
|
|
||||||
public interface Factory { |
|
||||||
RefreshLoadMoreView createRefreshView(View view); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,11 +0,0 @@ |
|||||||
package com.android.base.app.ui; |
|
||||||
|
|
||||||
public interface RefreshStateLayout extends StateLayout{ |
|
||||||
|
|
||||||
void autoRefresh(); |
|
||||||
|
|
||||||
void refreshCompleted(); |
|
||||||
|
|
||||||
boolean isRefreshing(); |
|
||||||
|
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue