{
+ ProtoAdapter_Transform() {
+ super(FieldEncoding.LENGTH_DELIMITED, Transform.class);
+ }
+
+ @Override
+ public int encodedSize(Transform value) {
+ return (value.a != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(1, value.a) : 0)
+ + (value.b != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(2, value.b) : 0)
+ + (value.c != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(3, value.c) : 0)
+ + (value.d != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(4, value.d) : 0)
+ + (value.tx != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(5, value.tx) : 0)
+ + (value.ty != null ? ProtoAdapter.FLOAT.encodedSizeWithTag(6, value.ty) : 0)
+ + value.unknownFields().size();
+ }
+
+ @Override
+ public void encode(ProtoWriter writer, Transform value) throws IOException {
+ if (value.a != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 1, value.a);
+ if (value.b != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 2, value.b);
+ if (value.c != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 3, value.c);
+ if (value.d != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 4, value.d);
+ if (value.tx != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 5, value.tx);
+ if (value.ty != null) ProtoAdapter.FLOAT.encodeWithTag(writer, 6, value.ty);
+ writer.writeBytes(value.unknownFields());
+ }
+
+ @Override
+ public Transform decode(ProtoReader reader) throws IOException {
+ Builder builder = new Builder();
+ long token = reader.beginMessage();
+ for (int tag; (tag = reader.nextTag()) != -1;) {
+ switch (tag) {
+ case 1: builder.a(ProtoAdapter.FLOAT.decode(reader)); break;
+ case 2: builder.b(ProtoAdapter.FLOAT.decode(reader)); break;
+ case 3: builder.c(ProtoAdapter.FLOAT.decode(reader)); break;
+ case 4: builder.d(ProtoAdapter.FLOAT.decode(reader)); break;
+ case 5: builder.tx(ProtoAdapter.FLOAT.decode(reader)); break;
+ case 6: builder.ty(ProtoAdapter.FLOAT.decode(reader)); break;
+ default: {
+ FieldEncoding fieldEncoding = reader.peekFieldEncoding();
+ Object value = fieldEncoding.rawProtoAdapter().decode(reader);
+ builder.addUnknownField(tag, fieldEncoding, value);
+ }
+ }
+ }
+ reader.endMessage(token);
+ return builder.build();
+ }
+
+ @Override
+ public Transform redact(Transform value) {
+ Builder builder = value.newBuilder();
+ builder.clearUnknownFields();
+ return builder.build();
+ }
+ }
+}
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/Pools.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/Pools.kt
new file mode 100644
index 000000000..7382ab84b
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/Pools.kt
@@ -0,0 +1,102 @@
+package com.opensource.svgaplayer.utils
+
+/**
+ * Helper class for creating pools of objects. An example use looks like this:
+ *
+ * public class MyPooledClass {
+ *
+ * private static final SynchronizedPool sPool =
+ * new SynchronizedPool(10);
+ *
+ * public static MyPooledClass obtain() {
+ * MyPooledClass instance = sPool.acquire();
+ * return (instance != null) ? instance : new MyPooledClass();
+ * }
+ *
+ * public void recycle() {
+ * // Clear state if needed.
+ * sPool.release(this);
+ * }
+ *
+ * . . .
+ * }
+ *
+ *
+ */
+class Pools private constructor() {
+
+ /**
+ * Interface for managing a pool of objects.
+ *
+ * @param The pooled type.
+ */
+ interface Pool {
+ /**
+ * @return An instance from the pool if such, null otherwise.
+ */
+ fun acquire(): T?
+
+ /**
+ * Release an instance to the pool.
+ *
+ * @param instance The instance to release.
+ * @return Whether the instance was put in the pool.
+ *
+ * @throws IllegalStateException If the instance is already in the pool.
+ */
+ fun release(instance: T): Boolean
+ }
+
+ /**
+ * Simple (non-synchronized) pool of objects.
+ *
+ * @param maxPoolSize The max pool size.
+ *
+ * @throws IllegalArgumentException If the max pool size is less than zero.
+ *
+ * @param The pooled type.
+ */
+ open class SimplePool(maxPoolSize: Int) : Pool {
+ private val mPool: Array
+ private var mPoolSize = 0
+
+ init {
+ require(maxPoolSize > 0) { "The max pool size must be > 0" }
+ mPool = arrayOfNulls(maxPoolSize)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun acquire(): T? {
+ if (mPoolSize > 0) {
+ val lastPooledIndex = mPoolSize - 1
+ val instance = mPool[lastPooledIndex] as T?
+ mPool[lastPooledIndex] = null
+ mPoolSize--
+ return instance
+ }
+ return null
+ }
+
+ override fun release(instance: T): Boolean {
+ check(!isInPool(instance)) { "Already in the pool!" }
+ if (mPoolSize < mPool.size) {
+ mPool[mPoolSize] = instance
+ mPoolSize++
+ return true
+ }
+ return false
+ }
+
+ private fun isInPool(instance: T): Boolean {
+ for (i in 0 until mPoolSize) {
+ if (mPool[i] === instance) {
+ return true
+ }
+ }
+ return false
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAScaleInfo.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAScaleInfo.kt
new file mode 100644
index 000000000..792abc266
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAScaleInfo.kt
@@ -0,0 +1,146 @@
+package com.opensource.svgaplayer.utils
+
+import android.widget.ImageView
+
+/**
+ * Created by ubt on 2018/1/19.
+ */
+class SVGAScaleInfo {
+
+ var tranFx : Float = 0.0f
+ var tranFy : Float = 0.0f
+ var scaleFx : Float = 1.0f
+ var scaleFy : Float = 1.0f
+ var ratio = 1.0f
+ var ratioX = false
+
+ private fun resetVar(){
+ tranFx = 0.0f
+ tranFy = 0.0f
+ scaleFx = 1.0f
+ scaleFy = 1.0f
+ ratio = 1.0f
+ ratioX = false
+ }
+
+ fun performScaleType(canvasWidth : Float, canvasHeight: Float, videoWidth : Float, videoHeight : Float, scaleType: ImageView.ScaleType) {
+ if (canvasWidth == 0.0f || canvasHeight == 0.0f || videoWidth == 0.0f || videoHeight == 0.0f) {
+ return
+ }
+
+ resetVar()
+ val canW_vidW_f = (canvasWidth - videoWidth) / 2.0f
+ val canH_vidH_f = (canvasHeight - videoHeight) / 2.0f
+
+ val videoRatio = videoWidth / videoHeight
+ val canvasRatio = canvasWidth / canvasHeight
+
+ val canH_d_vidH = canvasHeight / videoHeight
+ val canW_d_vidW = canvasWidth / videoWidth
+
+ when (scaleType) {
+ ImageView.ScaleType.CENTER -> {
+ tranFx = canW_vidW_f
+ tranFy = canH_vidH_f
+ }
+ ImageView.ScaleType.CENTER_CROP -> {
+ if (videoRatio > canvasRatio) {
+ ratio = canH_d_vidH
+ ratioX = false
+ scaleFx = canH_d_vidH
+ scaleFy = canH_d_vidH
+ tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
+ }
+ else {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
+ }
+ }
+ ImageView.ScaleType.CENTER_INSIDE -> {
+ if (videoWidth < canvasWidth && videoHeight < canvasHeight) {
+ tranFx = canW_vidW_f
+ tranFy = canH_vidH_f
+ }
+ else {
+ if (videoRatio > canvasRatio) {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
+
+ }
+ else {
+ ratio = canH_d_vidH
+ ratioX = false
+ scaleFx = canH_d_vidH
+ scaleFy = canH_d_vidH
+ tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
+ }
+ }
+ }
+ ImageView.ScaleType.FIT_CENTER -> {
+ if (videoRatio > canvasRatio) {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ tranFy = (canvasHeight - videoHeight * (canW_d_vidW)) / 2.0f
+ }
+ else {
+ ratio = canH_d_vidH
+ ratioX = false
+ scaleFx = canH_d_vidH
+ scaleFy = canH_d_vidH
+ tranFx = (canvasWidth - videoWidth * (canH_d_vidH)) / 2.0f
+ }
+ }
+ ImageView.ScaleType.FIT_START -> {
+ if (videoRatio > canvasRatio) {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ }
+ else {
+ ratio = canH_d_vidH
+ ratioX = false
+ scaleFx = canH_d_vidH
+ scaleFy = canH_d_vidH
+ }
+ }
+ ImageView.ScaleType.FIT_END -> {
+ if (videoRatio > canvasRatio) {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ tranFy= canvasHeight - videoHeight * (canW_d_vidW)
+ }
+ else {
+ ratio = canH_d_vidH
+ ratioX = false
+ scaleFx = canH_d_vidH
+ scaleFy = canH_d_vidH
+ tranFx = canvasWidth - videoWidth * (canH_d_vidH)
+ }
+ }
+ ImageView.ScaleType.FIT_XY -> {
+ ratio = Math.max(canW_d_vidW, canH_d_vidH)
+ ratioX = canW_d_vidW > canH_d_vidH
+ scaleFx = canW_d_vidW
+ scaleFy = canH_d_vidH
+ }
+ else -> {
+ ratio = canW_d_vidW
+ ratioX = true
+ scaleFx = canW_d_vidW
+ scaleFy = canW_d_vidW
+ }
+ }
+ }
+
+}
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAStructs.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAStructs.kt
new file mode 100644
index 000000000..f87b30db0
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/SVGAStructs.kt
@@ -0,0 +1,11 @@
+package com.opensource.svgaplayer.utils
+
+/**
+ * Created by cuiminghui on 2017/3/29.
+ */
+
+class SVGAPoint(val x: Float, val y: Float, val value: Float)
+
+class SVGARect(val x: Double, val y: Double, val width: Double, val height: Double)
+
+class SVGARange(val location: Int, val length: Int)
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/DefaultLogCat.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/DefaultLogCat.kt
new file mode 100644
index 000000000..33200b0e1
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/DefaultLogCat.kt
@@ -0,0 +1,28 @@
+package com.opensource.svgaplayer.utils.log
+
+import android.util.Log
+
+/**
+ * 内部默认 ILogger 接口实现
+ */
+class DefaultLogCat : ILogger {
+ override fun verbose(tag: String, msg: String) {
+ Log.v(tag, msg)
+ }
+
+ override fun info(tag: String, msg: String) {
+ Log.i(tag, msg)
+ }
+
+ override fun debug(tag: String, msg: String) {
+ Log.d(tag, msg)
+ }
+
+ override fun warn(tag: String, msg: String) {
+ Log.w(tag, msg)
+ }
+
+ override fun error(tag: String, msg: String?, error: Throwable?) {
+ Log.e(tag, msg, error)
+ }
+}
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/ILogger.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/ILogger.kt
new file mode 100644
index 000000000..ad935104c
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/ILogger.kt
@@ -0,0 +1,12 @@
+package com.opensource.svgaplayer.utils.log
+
+/**
+ * log 外部接管接口
+ **/
+interface ILogger {
+ fun verbose(tag: String, msg: String)
+ fun info(tag: String, msg: String)
+ fun debug(tag: String, msg: String)
+ fun warn(tag: String, msg: String)
+ fun error(tag: String, msg: String?, error: Throwable?)
+}
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/LogUtils.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/LogUtils.kt
new file mode 100644
index 000000000..60c67f9c2
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/LogUtils.kt
@@ -0,0 +1,57 @@
+package com.opensource.svgaplayer.utils.log
+
+/**
+ * 日志输出
+ */
+internal object LogUtils {
+ private const val TAG = "SVGALog"
+
+ fun verbose(tag: String = TAG, msg: String) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.verbose(tag, msg)
+ }
+
+ fun info(tag: String = TAG, msg: String) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.info(tag, msg)
+ }
+
+ fun debug(tag: String = TAG, msg: String) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.debug(tag, msg)
+ }
+
+ fun warn(tag: String = TAG, msg: String) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.warn(tag, msg)
+ }
+
+ fun error(tag: String = TAG, msg: String) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.error(tag, msg, null)
+ }
+
+ fun error(tag: String, error: Throwable) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.error(tag, error.message, error)
+ }
+
+ fun error(tag: String = TAG, msg: String, error: Throwable) {
+ if (!SVGALogger.isLogEnabled()) {
+ return
+ }
+ SVGALogger.getSVGALogger()?.error(tag, msg, error)
+ }
+}
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/SVGALogger.kt b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/SVGALogger.kt
new file mode 100644
index 000000000..5767c6385
--- /dev/null
+++ b/SVGAlibrary/src/main/java/com/opensource/svgaplayer/utils/log/SVGALogger.kt
@@ -0,0 +1,40 @@
+package com.opensource.svgaplayer.utils.log
+
+/**
+ * SVGA logger 配置管理
+ **/
+object SVGALogger {
+
+ private var mLogger: ILogger? = DefaultLogCat()
+ private var isLogEnabled = false
+
+ /**
+ * log 接管注入
+ */
+ fun injectSVGALoggerImp(logImp: ILogger): SVGALogger {
+ mLogger = logImp
+ return this
+ }
+
+ /**
+ * 设置是否开启 log
+ */
+ fun setLogEnabled(isEnabled: Boolean): SVGALogger {
+ isLogEnabled = isEnabled
+ return this
+ }
+
+ /**
+ * 获取当前 ILogger 实现类
+ */
+ fun getSVGALogger(): ILogger? {
+ return mLogger
+ }
+
+ /**
+ * 是否开启 log
+ */
+ fun isLogEnabled(): Boolean {
+ return isLogEnabled
+ }
+}
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/res/values/attrs.xml b/SVGAlibrary/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..471c34453
--- /dev/null
+++ b/SVGAlibrary/src/main/res/values/attrs.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SVGAlibrary/src/main/res/values/strings.xml b/SVGAlibrary/src/main/res/values/strings.xml
new file mode 100644
index 000000000..475f55349
--- /dev/null
+++ b/SVGAlibrary/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ SVGAPlayer
+
diff --git a/Share/src/main/res/drawable/bg_invite_title.xml b/Share/src/main/res/drawable/bg_invite_title.xml
deleted file mode 100644
index 1d7b0cf28..000000000
--- a/Share/src/main/res/drawable/bg_invite_title.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- -
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Share/src/main/res/layout/dialog_invite_list.xml b/Share/src/main/res/layout/dialog_invite_list.xml
deleted file mode 100644
index 877aab9e3..000000000
--- a/Share/src/main/res/layout/dialog_invite_list.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Share/src/main/res/layout/item_internal_user.xml b/Share/src/main/res/layout/item_internal_user.xml
index 5968e734c..348150bc7 100644
--- a/Share/src/main/res/layout/item_internal_user.xml
+++ b/Share/src/main/res/layout/item_internal_user.xml
@@ -2,7 +2,6 @@
@@ -47,7 +45,6 @@
android:src="@mipmap/chat_head_mo" />
-
- Share
- Come and watch %s live on PDLIVE and meet more interesting people!
- Invite Friends
- Come to PDLIVE to discover more and better live streams.
- Copy
- Site friends
- Share To
- cancel
- Search nickname
- Send
- Share success
- Go chat
- Please select friends
-
\ No newline at end of file
diff --git a/Share/src/main/res/values-zh/strings.xml b/Share/src/main/res/values-zh/strings.xml
new file mode 100644
index 000000000..ec54569a2
--- /dev/null
+++ b/Share/src/main/res/values-zh/strings.xml
@@ -0,0 +1,18 @@
+
+
+ZWRrZnRUNlBlcHVxMXpsMzVmb2k6MTpjaQ
+aq0eV4R1pqMK_AAeKRWnjPr7ErGMGgTPGgZJdm73WeRY-Kluws
+
+分享
+快來 PDLIVE觀看%s直播,認識更多有趣的朋友吧!
+Facebook
+Line
+Twitter
+WhatsApp
+Messenger
+Instagram
+
+邀請好友
+快來 PDLIVE觀看直播,認識更多有趣的朋友吧!
+複製
+
\ No newline at end of file
diff --git a/Share/src/main/res/values/strings.xml b/Share/src/main/res/values/strings.xml
index 9cc433273..7702b2fc7 100644
--- a/Share/src/main/res/values/strings.xml
+++ b/Share/src/main/res/values/strings.xml
@@ -1,6 +1,5 @@
+
- ZWRrZnRUNlBlcHVxMXpsMzVmb2k6MTpjaQ
- aq0eV4R1pqMK_AAeKRWnjPr7ErGMGgTPGgZJdm73WeRY-Kluws
分享
快來 PDLIVE觀看%s直播,認識更多有趣的朋友吧!
@@ -16,10 +15,10 @@
快來 PDLIVE觀看直播,認識更多有趣的朋友吧!
複製
分享至
- 取消
搜索昵稱
發送
分享成功
去聊聊
请选择好友
+
\ No newline at end of file
diff --git a/TabLayout/build.gradle b/TabLayout/build.gradle
new file mode 100644
index 000000000..d5b6e0cfd
--- /dev/null
+++ b/TabLayout/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+
+ namespace "com.angcyo.tablayout"
+ compileSdk rootProject.ext.android.compileSdkVersion
+
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.android.minSdkVersion
+ targetSdkVersion rootProject.ext.android.targetSdkVersion
+ versionCode rootProject.ext.android.versionCode
+ versionName rootProject.ext.android.versionName
+ manifestPlaceholders = rootProject.ext.manifestPlaceholders
+
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_18
+ targetCompatibility JavaVersion.VERSION_18
+ }
+}
+
+dependencies {
+ implementation 'androidx.core:core-ktx:1.10.1'
+
+}
+
+//apply from: "$gradleHost/master/publish.gradle"
\ No newline at end of file
diff --git a/TabLayout/consumer-rules.pro b/TabLayout/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/TabLayout/proguard-rules.pro b/TabLayout/proguard-rules.pro
new file mode 100644
index 000000000..f1b424510
--- /dev/null
+++ b/TabLayout/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/TabLayout/src/main/AndroidManifest.xml b/TabLayout/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..50f22e4ad
--- /dev/null
+++ b/TabLayout/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/AbsDslDrawable.kt b/TabLayout/src/main/java/com/angcyo/tablayout/AbsDslDrawable.kt
new file mode 100644
index 000000000..d790825ad
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/AbsDslDrawable.kt
@@ -0,0 +1,200 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.*
+import android.graphics.drawable.Drawable
+import android.text.TextPaint
+import android.util.AttributeSet
+import android.view.View
+import androidx.core.view.ViewCompat
+
+/**
+ * 基础自绘Drawable
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/25
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+
+abstract class AbsDslDrawable : Drawable() {
+
+ companion object {
+ /**不绘制*/
+ const val DRAW_TYPE_DRAW_NONE = 0x00
+
+ /**[android.view.View.draw]*/
+ const val DRAW_TYPE_DRAW_AFTER = 0x01
+ const val DRAW_TYPE_DRAW_BEFORE = 0x02
+
+ /**[android.view.View.onDraw]*/
+ const val DRAW_TYPE_ON_DRAW_AFTER = 0x04
+ const val DRAW_TYPE_ON_DRAW_BEFORE = 0x08
+ }
+
+ /**画笔*/
+ val textPaint: TextPaint by lazy {
+ TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
+ isFilterBitmap = true
+ style = Paint.Style.FILL
+ textSize = 12 * dp
+ }
+ }
+
+ val drawRect = Rect()
+ val drawRectF = RectF()
+
+ /**需要在那个方法中触发绘制*/
+ var drawType = DRAW_TYPE_ON_DRAW_AFTER
+
+ /**xml属性读取*/
+ open fun initAttribute(
+ context: Context,
+ attributeSet: AttributeSet? = null
+ ) {
+ //val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.xxx)
+ //typedArray.recycle()
+ }
+
+ //
+
+ /**附着的[View]*/
+ val attachView: View?
+ get() = if (callback is View) callback as? View else null
+
+ val isInEditMode: Boolean
+ get() = attachView?.isInEditMode ?: false
+ val paddingLeft: Int
+ get() = attachView?.paddingLeft ?: 0
+ val paddingRight: Int
+ get() = attachView?.paddingRight ?: 0
+ val paddingTop: Int
+ get() = attachView?.paddingTop ?: 0
+ val paddingBottom: Int
+ get() = attachView?.paddingBottom ?: 0
+ val viewHeight: Int
+ get() = attachView?.measuredHeight ?: 0
+ val viewWidth: Int
+ get() = attachView?.measuredWidth ?: 0
+ val viewDrawHeight: Int
+ get() = viewHeight - paddingTop - paddingBottom
+ val viewDrawWidth: Int
+ get() = viewWidth - paddingLeft - paddingRight
+
+ val isViewRtl: Boolean
+ get() = attachView != null && ViewCompat.getLayoutDirection(attachView!!) == ViewCompat.LAYOUT_DIRECTION_RTL
+
+ //
+
+ //
+
+ /**核心方法, 绘制*/
+ override fun draw(canvas: Canvas) {
+
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return super.getIntrinsicWidth()
+ }
+
+ override fun getMinimumWidth(): Int {
+ return super.getMinimumWidth()
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ return super.getIntrinsicHeight()
+ }
+
+ override fun getMinimumHeight(): Int {
+ return super.getMinimumHeight()
+ }
+
+ override fun setAlpha(alpha: Int) {
+ if (textPaint.alpha != alpha) {
+ textPaint.alpha = alpha
+ invalidateSelf()
+ }
+ }
+
+ override fun getAlpha(): Int {
+ return textPaint.alpha
+ }
+
+ override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
+ super.setBounds(left, top, right, bottom)
+ }
+
+ override fun setBounds(bounds: Rect) {
+ super.setBounds(bounds)
+ }
+
+ //不透明度
+ override fun getOpacity(): Int {
+ return if (alpha < 255) PixelFormat.TRANSLUCENT else PixelFormat.OPAQUE
+ }
+
+ override fun getColorFilter(): ColorFilter? {
+ return textPaint.colorFilter
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ textPaint.colorFilter = colorFilter
+ invalidateSelf()
+ }
+
+ override fun mutate(): Drawable {
+ return super.mutate()
+ }
+
+ override fun setDither(dither: Boolean) {
+ textPaint.isDither = dither
+ invalidateSelf()
+ }
+
+ override fun setFilterBitmap(filter: Boolean) {
+ textPaint.isFilterBitmap = filter
+ invalidateSelf()
+ }
+
+ override fun isFilterBitmap(): Boolean {
+ return textPaint.isFilterBitmap
+ }
+
+ override fun onBoundsChange(bounds: Rect) {
+ super.onBoundsChange(bounds)
+ }
+
+ override fun onLevelChange(level: Int): Boolean {
+ return super.onLevelChange(level)
+ }
+
+ override fun onStateChange(state: IntArray): Boolean {
+ return super.onStateChange(state)
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ super.setTintList(tint)
+ }
+
+ override fun setTintMode(tintMode: PorterDuff.Mode?) {
+ super.setTintMode(tintMode)
+ }
+
+ override fun setTintBlendMode(blendMode: BlendMode?) {
+ super.setTintBlendMode(blendMode)
+ }
+
+ override fun setHotspot(x: Float, y: Float) {
+ super.setHotspot(x, y)
+ }
+
+ override fun setHotspotBounds(left: Int, top: Int, right: Int, bottom: Int) {
+ super.setHotspotBounds(left, top, right, bottom)
+ }
+
+ override fun getHotspotBounds(outRect: Rect) {
+ super.getHotspotBounds(outRect)
+ }
+
+ //
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslBadgeDrawable.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslBadgeDrawable.kt
new file mode 100644
index 000000000..1962d3d8f
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslBadgeDrawable.kt
@@ -0,0 +1,275 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.text.TextUtils
+import android.util.AttributeSet
+import android.view.Gravity
+import kotlin.math.max
+
+/**
+ * 未读数, 未读小红点, 角标绘制Drawable
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/12/13
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslBadgeDrawable : DslGradientDrawable() {
+
+ val dslGravity = DslGravity()
+
+ /**重力*/
+ var badgeGravity: Int = Gravity.CENTER //Gravity.TOP or Gravity.RIGHT
+
+ /**角标文本颜色*/
+ var badgeTextColor = Color.WHITE
+
+ /**角标的文本(默认居中绘制文本,暂不支持修改), 空字符串会绘制成小圆点
+ * null 不绘制角标
+ * "" 空字符绘制圆点
+ * 其他 正常绘制
+ * */
+ var badgeText: String? = null
+
+ /**角标的文本大小*/
+ var badgeTextSize: Float = 12 * dp
+ set(value) {
+ field = value
+ textPaint.textSize = field
+ }
+
+ /**当[badgeText]只有1个字符时, 使用圆形背景*/
+ var badgeAutoCircle: Boolean = true
+
+ /**圆点状态时的半径大小*/
+ var badgeCircleRadius = 4 * dpi
+
+ /**原点状态下, 单独配置的偏移*/
+ var badgeCircleOffsetX: Int = 0
+ var badgeCircleOffsetY: Int = 0
+
+ /**额外偏移距离, 会根据[Gravity]自动取负值*/
+ var badgeOffsetX: Int = 0
+ var badgeOffsetY: Int = 0
+
+ /**文本偏移*/
+ var badgeTextOffsetX: Int = 0
+ var badgeTextOffsetY: Int = 0
+
+ /**圆点状态时无效*/
+ var badgePaddingLeft = 0
+ var badgePaddingRight = 0
+ var badgePaddingTop = 0
+ var badgePaddingBottom = 0
+
+ /**最小的高度大小, px. 大于0生效; 圆点时属性无效*/
+ var badgeMinHeight = -2
+
+ /**最小的宽度大小, px. 大于0生效; 圆点时属性无效;
+ * -1 表示使用使用计算出来的高度值*/
+ var badgeMinWidth = -2
+
+ //计算属性
+ val textWidth: Float
+ get() = textPaint.textWidth(badgeText)
+
+ //最大的宽度
+ val maxWidth: Int
+ get() = max(
+ textWidth.toInt(),
+ originDrawable?.minimumWidth ?: 0
+ ) + badgePaddingLeft + badgePaddingRight
+
+ //最大的高度
+ val maxHeight: Int
+ get() = max(
+ textHeight.toInt(),
+ originDrawable?.minimumHeight ?: 0
+ ) + badgePaddingTop + badgePaddingBottom
+
+ val textHeight: Float
+ get() = textPaint.textHeight()
+
+ //原型状态
+ val isCircle: Boolean
+ get() = TextUtils.isEmpty(badgeText)
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ super.initAttribute(context, attributeSet)
+ updateOriginDrawable()
+ }
+
+ override fun draw(canvas: Canvas) {
+ //super.draw(canvas)
+
+ if (badgeText == null) {
+ return
+ }
+
+ with(dslGravity) {
+ gravity = if (isViewRtl) {
+ when (badgeGravity) {
+ Gravity.RIGHT -> {
+ Gravity.LEFT
+ }
+ Gravity.LEFT -> {
+ Gravity.RIGHT
+ }
+ else -> {
+ badgeGravity
+ }
+ }
+ } else {
+ badgeGravity
+ }
+
+ setGravityBounds(bounds)
+
+ if (isCircle) {
+ gravityOffsetX = badgeCircleOffsetX
+ gravityOffsetY = badgeCircleOffsetY
+ } else {
+ gravityOffsetX = badgeOffsetX
+ gravityOffsetY = badgeOffsetY
+ }
+
+ val textWidth = textPaint.textWidth(badgeText)
+ val textHeight = textPaint.textHeight()
+
+ val drawHeight = if (isCircle) {
+ badgeCircleRadius.toFloat()
+ } else {
+ val height = textHeight + badgePaddingTop + badgePaddingBottom
+ if (badgeMinHeight > 0) {
+ max(height, badgeMinHeight.toFloat())
+ } else {
+ height
+ }
+ }
+
+ val drawWidth = if (isCircle) {
+ badgeCircleRadius.toFloat()
+ } else {
+ val width = textWidth + badgePaddingLeft + badgePaddingRight
+ if (badgeMinWidth == -1) {
+ max(width, drawHeight)
+ } else if (badgeMinWidth > 0) {
+ max(width, badgeMinWidth.toFloat())
+ } else {
+ width
+ }
+ }
+
+ applyGravity(drawWidth, drawHeight) { centerX, centerY ->
+
+ if (isCircle) {
+ textPaint.color = gradientSolidColor
+
+ //圆心计算
+ val cx: Float
+ val cy: Float
+ if (gravity.isCenter()) {
+ cx = centerX.toFloat()
+ cy = centerY.toFloat()
+ } else {
+ cx = centerX.toFloat() + _gravityOffsetX
+ cy = centerY.toFloat() + _gravityOffsetY
+ }
+
+ //绘制圆
+ textPaint.color = gradientSolidColor
+ canvas.drawCircle(
+ cx,
+ cy,
+ badgeCircleRadius.toFloat(),
+ textPaint
+ )
+
+ //圆的描边
+ if (gradientStrokeWidth > 0 && gradientStrokeColor != Color.TRANSPARENT) {
+ val oldWidth = textPaint.strokeWidth
+ val oldStyle = textPaint.style
+
+ textPaint.color = gradientStrokeColor
+ textPaint.strokeWidth = gradientStrokeWidth.toFloat()
+ textPaint.style = Paint.Style.STROKE
+
+ canvas.drawCircle(
+ cx,
+ cy,
+ badgeCircleRadius.toFloat(),
+ textPaint
+ )
+
+ textPaint.strokeWidth = oldWidth
+ textPaint.style = oldStyle
+ }
+
+ } else {
+ textPaint.color = badgeTextColor
+
+ val textDrawX: Float = centerX - textWidth / 2
+ val textDrawY: Float = centerY + textHeight / 2
+
+ val bgLeft = _gravityLeft
+ val bgTop = _gravityTop
+
+ //绘制背景
+ if (badgeAutoCircle && badgeText?.length == 1) {
+ if (gradientSolidColor != Color.TRANSPARENT) {
+ textPaint.color = gradientSolidColor
+ canvas.drawCircle(
+ centerX.toFloat(),
+ centerY.toFloat(),
+ max(maxWidth, maxHeight).toFloat() / 2,
+ textPaint
+ )
+ }
+ } else {
+ originDrawable?.apply {
+ setBounds(
+ bgLeft, bgTop,
+ (bgLeft + drawWidth).toInt(),
+ (bgTop + drawHeight).toInt()
+ )
+ draw(canvas)
+ }
+ }
+
+ //绘制文本
+ textPaint.color = badgeTextColor
+ canvas.drawText(
+ badgeText!!,
+ textDrawX + badgeTextOffsetX,
+ textDrawY - textPaint.descent() + badgeTextOffsetY,
+ textPaint
+ )
+ }
+ }
+ }
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ val width = if (isCircle) {
+ badgeCircleRadius * 2
+ } else if (badgeAutoCircle && badgeText?.length == 1) {
+ max(maxWidth, maxHeight)
+ } else {
+ maxWidth
+ }
+ return max(badgeMinWidth, width)
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ val height = if (isCircle) {
+ badgeCircleRadius * 2
+ } else if (badgeAutoCircle && badgeText?.length == 1) {
+ max(maxWidth, maxHeight)
+ } else {
+ maxHeight
+ }
+ return max(badgeMinHeight, height)
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslGradientDrawable.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslGradientDrawable.kt
new file mode 100644
index 000000000..336c5b9d7
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslGradientDrawable.kt
@@ -0,0 +1,306 @@
+package com.angcyo.tablayout
+
+import android.content.res.ColorStateList
+import android.content.res.Resources
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.os.Build
+import androidx.annotation.IntDef
+import java.util.*
+
+/**
+ * 用来构建GradientDrawable
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/27
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslGradientDrawable : AbsDslDrawable() {
+
+ /**形状*/
+ @Shape
+ var gradientShape = GradientDrawable.RECTANGLE
+
+ /**填充的颜色*/
+ var gradientSolidColor = Color.TRANSPARENT
+
+ /**边框的颜色*/
+ var gradientStrokeColor = Color.TRANSPARENT
+
+ /**边框的宽度*/
+ var gradientStrokeWidth = 0
+
+ /**蚂蚁线的宽度*/
+ var gradientDashWidth = 0f
+
+ /**蚂蚁线之间的间距*/
+ var gradientDashGap = 0f
+
+ /**
+ * 四个角, 8个设置点的圆角信息
+ * 从 左上y轴->左上x轴->右上x轴->右上y轴..., 开始设置.
+ */
+ var gradientRadii = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)
+
+ /**颜色渐变*/
+ var gradientColors: IntArray? = null
+ var gradientColorsOffsets: FloatArray? = null
+
+ /**渐变中心点坐标*/
+ var gradientCenterX = 0.5f
+ var gradientCenterY = 0.5f
+
+ /**渐变半径, 非比例值, 是px值. [GradientDrawable.RADIAL_GRADIENT]类型才有效*/
+ var gradientRadius = 0.5f
+
+ /** 渐变方向, 默认从左到右 */
+ var gradientOrientation = GradientDrawable.Orientation.LEFT_RIGHT
+
+ /** 渐变类型 */
+ @GradientType
+ var gradientType = GradientDrawable.LINEAR_GRADIENT
+
+ /**真正绘制的[Drawable]*/
+ var originDrawable: Drawable? = null
+
+ /**宽度补偿*/
+ var gradientWidthOffset: Int = 0
+
+ /**高度补偿*/
+ var gradientHeightOffset: Int = 0
+
+ /**当前的配置, 是否能生成有效的[GradientDrawable]*/
+ open fun isValidConfig(): Boolean {
+ return gradientSolidColor != Color.TRANSPARENT ||
+ gradientStrokeColor != Color.TRANSPARENT ||
+ gradientColors != null
+ }
+
+ fun _fillRadii(array: FloatArray, radii: String?) {
+ if (radii.isNullOrEmpty()) {
+ return
+ }
+ val split = radii.split(",")
+ if (split.size != 8) {
+ throw IllegalArgumentException("radii 需要8个值.")
+ } else {
+ val dp = Resources.getSystem().displayMetrics.density
+ for (i in split.indices) {
+ array[i] = split[i].toFloat() * dp
+ }
+ }
+ }
+
+ fun fillRadii(radius: Float) {
+ Arrays.fill(gradientRadii, radius)
+ }
+
+ fun fillRadii(radius: Int) {
+ _fillRadii(gradientRadii, radius.toFloat())
+ }
+
+ fun _fillRadii(array: FloatArray, radius: Float) {
+ Arrays.fill(array, radius)
+ }
+
+ fun _fillRadii(array: FloatArray, radius: Int) {
+ _fillRadii(array, radius.toFloat())
+ }
+
+ fun _fillColor(colors: String?): IntArray? {
+ if (colors.isNullOrEmpty()) {
+ return null
+ }
+ val split = colors.split(",")
+
+ return IntArray(split.size) {
+ val str = split[it]
+ if (str.startsWith("#")) {
+ Color.parseColor(str)
+ } else {
+ str.toInt()
+ }
+ }
+ }
+
+ /**构建或者更新[originDrawable]*/
+ open fun updateOriginDrawable(): GradientDrawable? {
+ val drawable: GradientDrawable? = when (originDrawable) {
+ null -> GradientDrawable()
+ is GradientDrawable -> originDrawable as GradientDrawable
+ else -> {
+ null
+ }
+ }
+
+ drawable?.apply {
+ bounds = this@DslGradientDrawable.bounds
+
+ shape = gradientShape
+ setStroke(
+ gradientStrokeWidth,
+ gradientStrokeColor,
+ gradientDashWidth,
+ gradientDashGap
+ )
+ setColor(gradientSolidColor)
+ cornerRadii = gradientRadii
+
+ if (gradientColors != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ setGradientCenter(
+ this@DslGradientDrawable.gradientCenterX,
+ this@DslGradientDrawable.gradientCenterY
+ )
+ }
+ gradientRadius = this@DslGradientDrawable.gradientRadius
+ gradientType = this@DslGradientDrawable.gradientType
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ orientation = gradientOrientation
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ setColors(gradientColors, gradientColorsOffsets)
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ colors = gradientColors
+ }
+ }
+
+ originDrawable = this
+ invalidateSelf()
+ }
+
+ return drawable
+ }
+
+ open fun configDrawable(config: DslGradientDrawable.() -> Unit): DslGradientDrawable {
+ this.config()
+ updateOriginDrawable()
+ return this
+ }
+
+ override fun draw(canvas: Canvas) {
+ super.draw(canvas)
+ originDrawable?.apply {
+ setBounds(
+ this@DslGradientDrawable.bounds.left - gradientWidthOffset / 2,
+ this@DslGradientDrawable.bounds.top - gradientHeightOffset / 2,
+ this@DslGradientDrawable.bounds.right + gradientWidthOffset / 2,
+ this@DslGradientDrawable.bounds.bottom + gradientHeightOffset / 2
+ )
+ draw(canvas)
+ }
+ }
+
+ //
+
+ /**
+ * 4个角, 8个点 圆角配置
+ */
+ fun cornerRadii(radii: FloatArray) {
+ gradientRadii = radii
+ }
+
+ fun cornerRadius(radii: Float) {
+ Arrays.fill(gradientRadii, radii)
+ }
+
+ fun cornerRadius(
+ leftTop: Float = 0f,
+ rightTop: Float = 0f,
+ rightBottom: Float = 0f,
+ leftBottom: Float = 0f
+ ) {
+ gradientRadii[0] = leftTop
+ gradientRadii[1] = leftTop
+ gradientRadii[2] = rightTop
+ gradientRadii[3] = rightTop
+ gradientRadii[4] = rightBottom
+ gradientRadii[5] = rightBottom
+ gradientRadii[6] = leftBottom
+ gradientRadii[7] = leftBottom
+ }
+
+ /**
+ * 只配置左边的圆角
+ */
+ fun cornerRadiiLeft(radii: Float) {
+ gradientRadii[0] = radii
+ gradientRadii[1] = radii
+ gradientRadii[6] = radii
+ gradientRadii[7] = radii
+ }
+
+ fun cornerRadiiRight(radii: Float) {
+ gradientRadii[2] = radii
+ gradientRadii[3] = radii
+ gradientRadii[4] = radii
+ gradientRadii[5] = radii
+ }
+
+ fun cornerRadiiTop(radii: Float) {
+ gradientRadii[0] = radii
+ gradientRadii[1] = radii
+ gradientRadii[2] = radii
+ gradientRadii[3] = radii
+ }
+
+ fun cornerRadiiBottom(radii: Float) {
+ gradientRadii[4] = radii
+ gradientRadii[5] = radii
+ gradientRadii[6] = radii
+ gradientRadii[7] = radii
+ }
+
+ //
+
+ //
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ super.setColorFilter(colorFilter)
+ originDrawable?.colorFilter = colorFilter
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ super.setTintList(tint)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ originDrawable?.setTintList(tint)
+ }
+ }
+
+ override fun setState(stateSet: IntArray): Boolean {
+ return originDrawable?.setState(stateSet) ?: super.setState(stateSet)
+ }
+
+ override fun getState(): IntArray {
+ return originDrawable?.state ?: super.getState()
+ }
+
+ //
+}
+
+@IntDef(
+ GradientDrawable.RECTANGLE,
+ GradientDrawable.OVAL,
+ GradientDrawable.LINE,
+ GradientDrawable.RING
+)
+@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
+annotation class Shape
+
+@IntDef(
+ GradientDrawable.LINEAR_GRADIENT,
+ GradientDrawable.RADIAL_GRADIENT,
+ GradientDrawable.SWEEP_GRADIENT
+)
+@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
+annotation class GradientType
+
+/**快速创建[GradientDrawable]*/
+fun dslGradientDrawable(action: DslGradientDrawable.() -> Unit): GradientDrawable {
+ return DslGradientDrawable().run {
+ action()
+ updateOriginDrawable()!!
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslGravity.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslGravity.kt
new file mode 100644
index 000000000..66cc1d40e
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslGravity.kt
@@ -0,0 +1,215 @@
+package com.angcyo.tablayout
+
+import android.graphics.Rect
+import android.graphics.RectF
+import android.view.Gravity
+
+/**
+ * [android.view.Gravity] 辅助计算类
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/12/13
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+class DslGravity {
+
+ /**束缚范围*/
+ val gravityBounds: RectF = RectF()
+
+ /**束缚重力*/
+ var gravity: Int = Gravity.LEFT or Gravity.TOP
+
+ /**使用中心坐标作为定位参考, 否则就是四条边*/
+ var gravityRelativeCenter: Boolean = true
+
+ /**额外偏移距离, 会根据[Gravity]自动取负值*/
+ var gravityOffsetX: Int = 0
+ var gravityOffsetY: Int = 0
+
+ fun setGravityBounds(rectF: RectF) {
+ gravityBounds.set(rectF)
+ }
+
+ fun setGravityBounds(rect: Rect) {
+ gravityBounds.set(rect)
+ }
+
+ fun setGravityBounds(
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int
+ ) {
+ gravityBounds.set(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
+ }
+
+ fun setGravityBounds(
+ left: Float,
+ top: Float,
+ right: Float,
+ bottom: Float
+ ) {
+ gravityBounds.set(left, top, right, bottom)
+ }
+
+ //计算后的属性
+ var _horizontalGravity: Int = Gravity.LEFT
+ var _verticalGravity: Int = Gravity.TOP
+ var _isCenterGravity: Boolean = false
+ var _targetWidth = 0f
+ var _targetHeight = 0f
+ var _gravityLeft = 0
+ var _gravityTop = 0
+ var _gravityRight = 0
+ var _gravityBottom = 0
+
+ //根据gravity调整后的offset
+ var _gravityOffsetX = 0
+ var _gravityOffsetY = 0
+
+ /**根据[gravity]返回在[gravityBounds]中的[left] [top]位置*/
+ fun applyGravity(
+ width: Float = _targetWidth,
+ height: Float = _targetHeight,
+ callback: (centerX: Int, centerY: Int) -> Unit
+ ) {
+
+ _targetWidth = width
+ _targetHeight = height
+
+ val layoutDirection = 0
+ val absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection)
+ val verticalGravity = gravity and Gravity.VERTICAL_GRAVITY_MASK
+ val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+
+ //调整offset
+ _gravityOffsetX = when (horizontalGravity) {
+ Gravity.RIGHT -> -gravityOffsetX
+ Gravity.END -> -gravityOffsetX
+ else -> gravityOffsetX
+ }
+ _gravityOffsetY = when (verticalGravity) {
+ Gravity.BOTTOM -> -gravityOffsetY
+ else -> gravityOffsetY
+ }
+
+ //计算居中的坐标
+ val centerX = when (horizontalGravity) {
+ Gravity.CENTER_HORIZONTAL -> (gravityBounds.left + gravityBounds.width() / 2 + _gravityOffsetX).toInt()
+ Gravity.RIGHT -> (gravityBounds.right + _gravityOffsetX - if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
+ Gravity.END -> (gravityBounds.right + _gravityOffsetX - if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
+ else -> (gravityBounds.left + _gravityOffsetX + if (gravityRelativeCenter) 0f else _targetWidth / 2).toInt()
+ }
+
+ val centerY = when (verticalGravity) {
+ Gravity.CENTER_VERTICAL -> (gravityBounds.top + gravityBounds.height() / 2 + _gravityOffsetY).toInt()
+ Gravity.BOTTOM -> (gravityBounds.bottom + _gravityOffsetY - if (gravityRelativeCenter) 0f else _targetHeight / 2).toInt()
+ else -> (gravityBounds.top + _gravityOffsetY + if (gravityRelativeCenter) 0f else _targetHeight / 2).toInt()
+ }
+
+ //缓存
+ _horizontalGravity = horizontalGravity
+ _verticalGravity = verticalGravity
+ _isCenterGravity = horizontalGravity == Gravity.CENTER_HORIZONTAL &&
+ verticalGravity == Gravity.CENTER_VERTICAL
+
+ _gravityLeft = (centerX - _targetWidth / 2).toInt()
+ _gravityRight = (centerX + _targetWidth / 2).toInt()
+ _gravityTop = (centerY - _targetHeight / 2).toInt()
+ _gravityBottom = (centerY + _targetHeight / 2).toInt()
+
+ //回调
+ callback(centerX, centerY)
+ }
+}
+
+/**
+ * 默认计算出的是目标中心点坐标参考距离
+ * [com.angcyo.drawable.DslGravity.getGravityRelativeCenter]
+ * */
+fun dslGravity(
+ rect: RectF, //计算的矩形
+ gravity: Int, //重力
+ width: Float, //放置目标的宽度
+ height: Float, //放置目标的高度
+ offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
+ offsetY: Int = 0,
+ callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
+): DslGravity {
+ val _dslGravity = DslGravity()
+ _dslGravity.setGravityBounds(rect)
+ _config(_dslGravity, gravity, width, height, offsetX, offsetY, callback)
+ return _dslGravity
+}
+
+/**
+ * 默认计算出的是目标中心点坐标参考距离
+ * [com.angcyo.drawable.DslGravity.getGravityRelativeCenter]
+ * */
+fun dslGravity(
+ rect: Rect, //计算的矩形
+ gravity: Int, //重力
+ width: Float, //放置目标的宽度
+ height: Float, //放置目标的高度
+ offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
+ offsetY: Int = 0,
+ callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
+): DslGravity {
+ val _dslGravity = DslGravity()
+ _dslGravity.setGravityBounds(rect)
+ _config(_dslGravity, gravity, width, height, offsetX, offsetY, callback)
+ return _dslGravity
+}
+
+private fun _config(
+ _dslGravity: DslGravity,
+ gravity: Int, //重力
+ width: Float, //放置目标的宽度
+ height: Float, //放置目标的高度
+ offsetX: Int = 0, //额外的偏移,会根据[gravity]进行左右|上下取反
+ offsetY: Int = 0,
+ callback: (dslGravity: DslGravity, centerX: Int, centerY: Int) -> Unit
+) {
+ _dslGravity.gravity = gravity
+ _dslGravity.gravityOffsetX = offsetX
+ _dslGravity.gravityOffsetY = offsetY
+ _dslGravity.applyGravity(width, height) { centerX, centerY ->
+ callback(_dslGravity, centerX, centerY)
+ }
+}
+
+/**居中*/
+fun Int.isCenter(): Boolean {
+ val layoutDirection = 0
+ val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
+ val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
+ val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+
+ return verticalGravity == Gravity.CENTER_VERTICAL && horizontalGravity == Gravity.CENTER_HORIZONTAL
+}
+
+fun Int.isLeft(): Boolean {
+ val layoutDirection = 0
+ val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
+ val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+
+ return horizontalGravity == Gravity.LEFT
+}
+
+fun Int.isRight(): Boolean {
+ val layoutDirection = 0
+ val absoluteGravity = Gravity.getAbsoluteGravity(this, layoutDirection)
+ val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+
+ return horizontalGravity == Gravity.RIGHT
+}
+
+fun Int.isTop(): Boolean {
+ val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
+ return verticalGravity == Gravity.TOP
+}
+
+fun Int.isBottom(): Boolean {
+ val verticalGravity = this and Gravity.VERTICAL_GRAVITY_MASK
+ return verticalGravity == Gravity.BOTTOM
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslSelector.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslSelector.kt
new file mode 100644
index 000000000..955680e86
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslSelector.kt
@@ -0,0 +1,438 @@
+package com.angcyo.tablayout
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CompoundButton
+
+/**
+ * 用来操作[ViewGroup]中的[child], 支持单选, 多选, 拦截.
+ * 操作的都是可见性为[VISIBLE]的[View]
+ *
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/24
+ */
+
+open class DslSelector {
+
+ var parent: ViewGroup? = null
+ var dslSelectorConfig: DslSelectorConfig = DslSelectorConfig()
+
+ //可见view列表
+ val visibleViewList: MutableList = mutableListOf()
+
+ /**
+ * 选中的索引列表
+ * */
+ val selectorIndexList: MutableList = mutableListOf()
+ get() {
+ field.clear()
+ visibleViewList.forEachIndexed { index, view ->
+ if (view.isSe()) {
+ field.add(index)
+ }
+ }
+
+ return field
+ }
+
+ /**
+ * 选中的View列表
+ * */
+ val selectorViewList: MutableList = mutableListOf()
+ get() {
+ field.clear()
+ visibleViewList.forEachIndexed { index, view ->
+ if (view.isSe() || index == dslSelectIndex) {
+ field.add(view)
+ }
+ }
+ return field
+ }
+
+ //child 点击事件处理
+ val _onChildClickListener = View.OnClickListener {
+ val index = visibleViewList.indexOf(it)
+ val select =
+ if (dslSelectorConfig.dslMultiMode || dslSelectorConfig.dslMinSelectLimit < 1) {
+ !it.isSe()
+ } else {
+ true
+ }
+
+ if (!interceptSelector(index, select, true)) {
+ selector(
+ visibleViewList.indexOf(it),
+ select,
+ notify = true,
+ fromUser = true,
+ forceNotify = it is CompoundButton && dslSelectorConfig.dslMultiMode
+ )
+ }
+ }
+
+ /**兼容[CompoundButton]*/
+ val _onCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
+ buttonView.isChecked = buttonView.isSelected //恢复状态 不做任何处理, 在[OnClickListener]中处理
+ /*val index = visibleViewList.indexOf(buttonView)
+
+ if (interceptSelector(index, isChecked, false)) {
+ //拦截了此操作
+ buttonView.isChecked = !isChecked //恢复状态
+ }
+
+ val selectorViewList = selectorViewList
+ val sum = selectorViewList.size
+ //Limit 过滤
+ if (buttonView.isChecked) {
+ if (sum > dslSelectorConfig.dslMaxSelectLimit) {
+ //不允许选择
+ buttonView.isChecked = false //恢复状态
+ }
+ } else {
+ //取消选择, 检查是否达到了 limit
+ if (sum < dslSelectorConfig.dslMinSelectLimit) {
+ //不允许取消选择
+ buttonView.isChecked = true //恢复状态
+ }
+ }
+
+ if (isChecked) {
+ //已经选中了控件
+ } else {
+ //已经取消了控件
+ }*/
+ }
+
+ /**当前选中的索引*/
+ var dslSelectIndex = -1
+
+ /**安装*/
+ fun install(viewGroup: ViewGroup, config: DslSelectorConfig.() -> Unit = {}): DslSelector {
+ dslSelectIndex = -1
+ parent = viewGroup
+ updateVisibleList()
+ dslSelectorConfig.config()
+
+ updateStyle()
+ updateClickListener()
+
+ if (dslSelectIndex in 0 until visibleViewList.size) {
+ selector(dslSelectIndex)
+ }
+
+ return this
+ }
+
+ /**更新样式*/
+ fun updateStyle() {
+ visibleViewList.forEachIndexed { index, view ->
+ val selector = dslSelectIndex == index || view.isSe()
+ dslSelectorConfig.onStyleItemView(view, index, selector)
+ }
+ }
+
+ /**更新child的点击事件*/
+ fun updateClickListener() {
+ parent?.apply {
+ for (i in 0 until childCount) {
+ getChildAt(i)?.let {
+ it.setOnClickListener(_onChildClickListener)
+ if (it is CompoundButton) {
+ it.setOnCheckedChangeListener(_onCheckedChangeListener)
+ }
+ }
+ }
+ }
+ }
+
+ /**更新可见视图列表*/
+ fun updateVisibleList(): List {
+ visibleViewList.clear()
+ parent?.apply {
+ for (i in 0 until childCount) {
+ getChildAt(i)?.let {
+ if (it.visibility == View.VISIBLE) {
+ visibleViewList.add(it)
+ }
+ }
+ }
+ }
+ if (dslSelectIndex in visibleViewList.indices) {
+ if (!visibleViewList[dslSelectIndex].isSe()) {
+ visibleViewList[dslSelectIndex].setSe(true)
+ }
+ } else {
+ //如果当前选中的索引, 不在可见视图列表中
+ dslSelectIndex = -1
+ }
+ return visibleViewList
+ }
+
+ /**
+ * 操作单个
+ * @param index 操作目标的索引值
+ * @param select 选中 or 取消选中
+ * @param notify 是否需要通知事件
+ * @param forceNotify 是否强制通知事件.child使用[CompoundButton]时, 推荐使用
+ * */
+ fun selector(
+ index: Int,
+ select: Boolean = true,
+ notify: Boolean = true,
+ fromUser: Boolean = false,
+ forceNotify: Boolean = false
+ ) {
+ val oldSelectorList = selectorIndexList.toList()
+ val lastSelectorIndex: Int? = oldSelectorList.lastOrNull()
+ val reselect = !dslSelectorConfig.dslMultiMode &&
+ oldSelectorList.isNotEmpty() &&
+ oldSelectorList.contains(index)
+
+ var needNotify = _selector(index, select, fromUser) || forceNotify
+
+ if (!oldSelectorList.isChange(selectorIndexList)) {
+ //选中项, 未改变时不通知
+ needNotify = false
+ }
+
+ if (needNotify || reselect) {
+ dslSelectIndex = selectorIndexList.lastOrNull() ?: -1
+ if (notify) {
+ notifySelectChange(lastSelectorIndex ?: -1, reselect, fromUser)
+ }
+ }
+ }
+
+ /**选择所有
+ * [select] true:选择所有, false:取消所有*/
+ fun selectorAll(
+ select: Boolean = true,
+ notify: Boolean = true,
+ fromUser: Boolean = true
+ ) {
+ val indexList = visibleViewList.mapIndexedTo(mutableListOf()) { index, _ ->
+ index
+ }
+ selector(indexList, select, notify, fromUser)
+ }
+
+ /**
+ * 操作多个
+ * @param select 选中 or 取消选中
+ * [selector]
+ * */
+ fun selector(
+ indexList: MutableList,
+ select: Boolean = true,
+ notify: Boolean = true,
+ fromUser: Boolean = false
+ ) {
+ val oldSelectorIndexList = selectorIndexList
+ val lastSelectorIndex: Int? = oldSelectorIndexList.lastOrNull()
+
+ var result = false
+
+ indexList.forEach {
+ result = _selector(it, select, fromUser) || result
+ }
+
+ if (result) {
+ dslSelectIndex = selectorIndexList.lastOrNull() ?: -1
+ if (notify) {
+ notifySelectChange(lastSelectorIndex ?: -1, false, fromUser)
+ }
+ }
+ }
+
+ /**通知事件*/
+ fun notifySelectChange(lastSelectorIndex: Int, reselect: Boolean, fromUser: Boolean) {
+ val indexSelectorList = selectorIndexList
+ dslSelectorConfig.onSelectViewChange(
+ visibleViewList.getOrNull(lastSelectorIndex),
+ selectorViewList,
+ reselect,
+ fromUser
+ )
+ dslSelectorConfig.onSelectIndexChange(
+ lastSelectorIndex,
+ indexSelectorList,
+ reselect,
+ fromUser
+ )
+ }
+
+ /**当前的操作是否被拦截*/
+ fun interceptSelector(index: Int, select: Boolean, fromUser: Boolean): Boolean {
+ val visibleViewList = visibleViewList
+ if (index !in 0 until visibleViewList.size) {
+ return true
+ }
+ return dslSelectorConfig.onSelectItemView(visibleViewList[index], index, select, fromUser)
+ }
+
+ /**@return 是否发生过改变*/
+ fun _selector(index: Int, select: Boolean, fromUser: Boolean): Boolean {
+ val visibleViewList = visibleViewList
+ //超范围过滤
+ if (index !in 0 until visibleViewList.size) {
+ "index out of list.".logi()
+ return false
+ }
+
+ val selectorIndexList = selectorIndexList
+ val selectorViewList = selectorViewList
+
+ if (selectorIndexList.isNotEmpty()) {
+ if (select) {
+ //需要选中某项
+
+ if (dslSelectorConfig.dslMultiMode) {
+ //多选模式
+ if (selectorIndexList.contains(index)) {
+ //已经选中
+ return false
+ }
+ } else {
+ //单选模式
+
+ //取消之前选中
+ selectorIndexList.forEach {
+ if (it != index) {
+ visibleViewList[it].setSe(false)
+ }
+ }
+
+ if (selectorIndexList.contains(index)) {
+ //已经选中
+ return true
+ }
+ }
+
+ } else {
+ //需要取消选中
+ if (!selectorIndexList.contains(index)) {
+ //目标已经是未选中
+ return false
+ }
+ }
+ }
+
+ //Limit 过滤
+ if (select) {
+ val sum = selectorViewList.size + 1
+ if (sum > dslSelectorConfig.dslMaxSelectLimit) {
+ //不允许选择
+ return false
+ }
+ } else {
+ //取消选择, 检查是否达到了 limit
+ val sum = selectorViewList.size - 1
+ if (sum < dslSelectorConfig.dslMinSelectLimit) {
+ //不允许取消选择
+ return false
+ }
+ }
+
+ val selectorView = visibleViewList[index]
+
+ //更新选中样式
+ selectorView.setSe(select)
+
+ if (dslSelectorConfig.dslMultiMode) {
+ //多选
+ } else {
+ //单选
+
+ //取消之前
+ selectorViewList.forEach { view ->
+ //更新样式
+ val indexOf = visibleViewList.indexOf(view)
+ if (indexOf != index &&
+ !dslSelectorConfig.onSelectItemView(view, indexOf, false, fromUser)
+ ) {
+ view.setSe(false)
+ dslSelectorConfig.onStyleItemView(view, indexOf, false)
+ }
+ }
+ }
+
+ dslSelectorConfig.onStyleItemView(selectorView, index, select)
+
+ return true
+ }
+
+ /**是否选中状态*/
+ fun View.isSe(): Boolean {
+ return isSelected || if (this is CompoundButton) isChecked else false
+ }
+
+ fun View.setSe(se: Boolean) {
+ isSelected = se
+ if (this is CompoundButton) isChecked = se
+ }
+}
+
+/**
+ * Dsl配置项
+ * */
+open class DslSelectorConfig {
+
+ /**取消选择时, 最小需要保持多个选中. 可以决定单选时, 是否允许取消所有选中*/
+ var dslMinSelectLimit = 1
+
+ /**多选时, 最大允许多个选中*/
+ var dslMaxSelectLimit = Int.MAX_VALUE
+
+ /**是否是多选模式*/
+ var dslMultiMode: Boolean = false
+
+ /**
+ * 用来初始化[itemView]的样式
+ * [onSelectItemView]
+ * */
+ var onStyleItemView: (itemView: View, index: Int, select: Boolean) -> Unit =
+ { _, _, _ ->
+
+ }
+
+ /**
+ * 选中[View]改变回调, 优先于[onSelectIndexChange]触发, 区别在于参数类型不一样
+ * @param fromView 单选模式下有效, 表示之前选中的[View]
+ * @param reselect 是否是重复选择, 只在单选模式下有效
+ * @param fromUser 是否是用户产生的回调, 而非代码设置
+ * */
+ var onSelectViewChange: (fromView: View?, selectViewList: List, reselect: Boolean, fromUser: Boolean) -> Unit =
+ { _, _, _, _ ->
+
+ }
+
+ /**
+ * 选中改变回调
+ * [onSelectViewChange]
+ * @param fromIndex 单选模式下有效, 表示之前选中的[View], 在可见性[child]列表中的索引
+ * */
+ var onSelectIndexChange: (fromIndex: Int, selectIndexList: List, reselect: Boolean, fromUser: Boolean) -> Unit =
+ { fromIndex, selectList, reselect, fromUser ->
+ "选择:[$fromIndex]->${selectList} reselect:$reselect fromUser:$fromUser".logi()
+ }
+
+ /**
+ * 当需要选中[itemView]时回调, 返回[true]表示拦截默认处理
+ * @param itemView 操作的[View]
+ * @param index [itemView]在可见性view列表中的索引. 非ViewGroup中的索引
+ * @param select 选中 or 取消选中
+ * @return true 表示拦截默认处理
+ * */
+ var onSelectItemView: (itemView: View, index: Int, select: Boolean, fromUser: Boolean) -> Boolean =
+ { _, _, _, _ ->
+ false
+ }
+}
+
+/**[DslSelector]组件*/
+fun dslSelector(viewGroup: ViewGroup, config: DslSelectorConfig.() -> Unit = {}): DslSelector {
+ return DslSelector().apply {
+ install(viewGroup, config)
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBadge.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBadge.kt
new file mode 100644
index 000000000..0761d1d3a
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBadge.kt
@@ -0,0 +1,222 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Color
+import android.util.AttributeSet
+import android.view.Gravity
+import androidx.annotation.Px
+
+/**
+ * 角标
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/12/13
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslTabBadge : DslBadgeDrawable() {
+
+ /**角标默认配置项*/
+ val defaultBadgeConfig = TabBadgeConfig()
+
+ /**预览的角标属性*/
+ var xmlBadgeText: String? = null
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ val typedArray =
+ context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+ gradientSolidColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_badge_solid_color,
+ defaultBadgeConfig.badgeSolidColor
+ )
+ defaultBadgeConfig.badgeSolidColor = gradientSolidColor
+
+ badgeTextColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_badge_text_color,
+ defaultBadgeConfig.badgeTextColor
+ )
+ defaultBadgeConfig.badgeTextColor = badgeTextColor
+
+ gradientStrokeColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_badge_stroke_color,
+ defaultBadgeConfig.badgeStrokeColor
+ )
+ defaultBadgeConfig.badgeStrokeColor = gradientStrokeColor
+
+ gradientStrokeWidth =
+ typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_stroke_width,
+ defaultBadgeConfig.badgeStrokeWidth
+ )
+ defaultBadgeConfig.badgeStrokeWidth = gradientStrokeWidth
+
+ badgeGravity = typedArray.getInt(
+ R.styleable.DslTabLayout_tab_badge_gravity,
+ defaultBadgeConfig.badgeGravity
+ )
+ defaultBadgeConfig.badgeGravity = badgeGravity
+
+ badgeOffsetX = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_offset_x,
+ defaultBadgeConfig.badgeOffsetX
+ )
+ defaultBadgeConfig.badgeOffsetX = badgeOffsetX
+ badgeOffsetY = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_offset_y,
+ defaultBadgeConfig.badgeOffsetY
+ )
+ defaultBadgeConfig.badgeOffsetY = badgeOffsetY
+
+ badgeCircleOffsetX = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_circle_offset_x,
+ defaultBadgeConfig.badgeOffsetX
+ )
+ defaultBadgeConfig.badgeCircleOffsetX = badgeCircleOffsetX
+ badgeCircleOffsetY = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_circle_offset_y,
+ defaultBadgeConfig.badgeOffsetY
+ )
+ defaultBadgeConfig.badgeCircleOffsetY = badgeCircleOffsetY
+
+ badgeCircleRadius = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_circle_radius,
+ defaultBadgeConfig.badgeCircleRadius
+ )
+ defaultBadgeConfig.badgeCircleRadius = badgeCircleRadius
+
+ val badgeRadius = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_radius,
+ defaultBadgeConfig.badgeRadius
+ )
+ cornerRadius(badgeRadius.toFloat())
+ defaultBadgeConfig.badgeRadius = badgeRadius
+
+ badgePaddingLeft = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_padding_left,
+ defaultBadgeConfig.badgePaddingLeft
+ )
+ defaultBadgeConfig.badgePaddingLeft = badgePaddingLeft
+
+ badgePaddingRight = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_padding_right,
+ defaultBadgeConfig.badgePaddingRight
+ )
+ defaultBadgeConfig.badgePaddingRight = badgePaddingRight
+
+ badgePaddingTop = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_padding_top,
+ defaultBadgeConfig.badgePaddingTop
+ )
+ defaultBadgeConfig.badgePaddingTop = badgePaddingTop
+
+ badgePaddingBottom = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_padding_bottom,
+ defaultBadgeConfig.badgePaddingBottom
+ )
+ defaultBadgeConfig.badgePaddingBottom = badgePaddingBottom
+
+ xmlBadgeText = typedArray.getString(R.styleable.DslTabLayout_tab_badge_text)
+
+ badgeTextSize = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_badge_text_size,
+ defaultBadgeConfig.badgeTextSize.toInt()
+ ).toFloat()
+ defaultBadgeConfig.badgeTextSize = badgeTextSize
+
+ defaultBadgeConfig.badgeAnchorChildIndex =
+ typedArray.getInteger(
+ R.styleable.DslTabLayout_tab_badge_anchor_child_index,
+ defaultBadgeConfig.badgeAnchorChildIndex
+ )
+ defaultBadgeConfig.badgeIgnoreChildPadding = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_badge_ignore_child_padding,
+ defaultBadgeConfig.badgeIgnoreChildPadding
+ )
+
+ defaultBadgeConfig.badgeMinWidth = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_badge_min_width,
+ defaultBadgeConfig.badgeMinWidth
+ )
+
+ defaultBadgeConfig.badgeMinHeight = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_badge_min_height,
+ defaultBadgeConfig.badgeMinHeight
+ )
+
+ typedArray.recycle()
+ super.initAttribute(context, attributeSet)
+ }
+
+ /**使用指定配置, 更新[DslBadgeDrawable]*/
+ fun updateBadgeConfig(badgeConfig: TabBadgeConfig) {
+ gradientSolidColor = badgeConfig.badgeSolidColor
+ gradientStrokeColor = badgeConfig.badgeStrokeColor
+ gradientStrokeWidth = badgeConfig.badgeStrokeWidth
+ badgeTextColor = badgeConfig.badgeTextColor
+ badgeGravity = badgeConfig.badgeGravity
+ badgeOffsetX = badgeConfig.badgeOffsetX
+ badgeOffsetY = badgeConfig.badgeOffsetY
+ badgeCircleOffsetX = badgeConfig.badgeCircleOffsetX
+ badgeCircleOffsetY = badgeConfig.badgeCircleOffsetY
+ badgeCircleRadius = badgeConfig.badgeCircleRadius
+ badgePaddingLeft = badgeConfig.badgePaddingLeft
+ badgePaddingRight = badgeConfig.badgePaddingRight
+ badgePaddingTop = badgeConfig.badgePaddingTop
+ badgePaddingBottom = badgeConfig.badgePaddingBottom
+ badgeTextSize = badgeConfig.badgeTextSize
+ cornerRadius(badgeConfig.badgeRadius.toFloat())
+ badgeMinHeight = badgeConfig.badgeMinHeight
+ badgeMinWidth = badgeConfig.badgeMinWidth
+ badgeText = badgeConfig.badgeText
+ }
+}
+
+/**角标绘制参数配置*/
+data class TabBadgeConfig(
+ /**角标的文本(默认居中绘制文本,暂不支持修改), 空字符串会绘制成小圆点
+ * null 不绘制角标
+ * "" 空字符绘制圆点
+ * 其他 正常绘制
+ * */
+ var badgeText: String? = null,
+ /**重力*/
+ var badgeGravity: Int = Gravity.CENTER,
+ /**角标背景颜色*/
+ var badgeSolidColor: Int = Color.RED,
+ /**角标边框颜色*/
+ var badgeStrokeColor: Int = Color.TRANSPARENT,
+ /**角标边框宽度*/
+ var badgeStrokeWidth: Int = 0,
+
+ /**角标文本颜色*/
+ var badgeTextColor: Int = Color.WHITE,
+ /**角标文本字体大小*/
+ @Px
+ var badgeTextSize: Float = 12 * dp,
+ /**圆点状态时的半径大小*/
+ var badgeCircleRadius: Int = 4 * dpi,
+ /**圆角大小*/
+ var badgeRadius: Int = 10 * dpi,
+ /**额外偏移距离, 会根据[Gravity]自动取负值*/
+ var badgeOffsetX: Int = 0,
+ var badgeOffsetY: Int = 0,
+ var badgeCircleOffsetX: Int = 0,
+ var badgeCircleOffsetY: Int = 0,
+ /**圆点状态时无效*/
+ var badgePaddingLeft: Int = 4 * dpi,
+ var badgePaddingRight: Int = 4 * dpi,
+ var badgePaddingTop: Int = 0,
+ var badgePaddingBottom: Int = 0,
+
+ var badgeAnchorChildIndex: Int = -1,
+ var badgeIgnoreChildPadding: Boolean = true,
+
+ /**最小的高度大小, px. 大于0生效; 圆点时属性无效*/
+ var badgeMinHeight: Int = -2,
+
+ /**最小的宽度大小, px. 大于0生效; 圆点时属性无效;
+ * -1 表示使用使用计算出来的高度值*/
+ var badgeMinWidth: Int = -1
+)
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBorder.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBorder.kt
new file mode 100644
index 000000000..b1d4d6003
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabBorder.kt
@@ -0,0 +1,279 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.View
+import androidx.core.view.ViewCompat
+
+/**
+ * 边框绘制, 支持首尾圆角中间不圆角的样式
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/27
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslTabBorder : DslGradientDrawable() {
+
+ /**
+ * 是否要接管[itemView]背景的绘制
+ * [updateItemBackground]
+ * */
+ var borderDrawItemBackground: Boolean = true
+
+ /**是否保持每个[itemView]的圆角都一样, 否则首尾有圆角, 中间没有圆角*/
+ var borderKeepItemRadius: Boolean = false
+
+ var borderBackgroundDrawable: Drawable? = null
+
+ /**宽度补偿*/
+ var borderBackgroundWidthOffset: Int = 0
+
+ /**高度补偿*/
+ var borderBackgroundHeightOffset: Int = 0
+
+ /**强制指定选中item的背景颜色*/
+ var borderItemBackgroundSolidColor: Int? = null
+
+ /**当item不可选中时的背景绘制颜色
+ * [com.angcyo.tablayout.DslTabLayout.itemEnableSelector]
+ * [borderItemBackgroundSolidColor]*/
+ var borderItemBackgroundSolidDisableColor: Int? = null
+
+ /**强制指定选中item的背景渐变颜色*/
+ var borderItemBackgroundGradientColors: IntArray? = null
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ val typedArray =
+ context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+
+ val borderBackgroundColor =
+ typedArray.getColor(R.styleable.DslTabLayout_tab_border_solid_color, gradientSolidColor)
+
+ gradientStrokeColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_stroke_color,
+ gradientStrokeColor
+ )
+ gradientStrokeWidth = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_border_stroke_width,
+ 2 * dpi
+ )
+ val radiusSize =
+ typedArray.getDimensionPixelOffset(R.styleable.DslTabLayout_tab_border_radius_size, 0)
+
+ cornerRadius(radiusSize.toFloat())
+
+ originDrawable = typedArray.getDrawable(R.styleable.DslTabLayout_tab_border_drawable)
+
+ borderDrawItemBackground = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_border_draw_item_background,
+ borderDrawItemBackground
+ )
+
+ borderKeepItemRadius = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_border_keep_item_radius,
+ borderKeepItemRadius
+ )
+
+ borderBackgroundWidthOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_border_item_background_width_offset,
+ borderBackgroundWidthOffset
+ )
+
+ borderBackgroundHeightOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_border_item_background_height_offset,
+ borderBackgroundHeightOffset
+ )
+
+ //
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_border_item_background_solid_color)) {
+ borderItemBackgroundSolidColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_item_background_solid_color,
+ gradientStrokeColor
+ )
+ }
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_border_item_background_solid_disable_color)) {
+ borderItemBackgroundSolidDisableColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_item_background_solid_disable_color,
+ borderItemBackgroundSolidColor ?: gradientStrokeColor
+ )
+ }
+
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_border_item_background_gradient_start_color) ||
+ typedArray.hasValue(R.styleable.DslTabLayout_tab_border_item_background_gradient_end_color)
+ ) {
+ val startColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_item_background_gradient_start_color,
+ gradientStrokeColor
+ )
+ val endColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_item_background_gradient_end_color,
+ gradientStrokeColor
+ )
+ borderItemBackgroundGradientColors = intArrayOf(startColor, endColor)
+ }
+
+ typedArray.recycle()
+
+ if (originDrawable == null) {
+ //无自定义的drawable, 那么自绘.
+ borderBackgroundDrawable = DslGradientDrawable().configDrawable {
+ gradientSolidColor = borderBackgroundColor
+ gradientRadii = this@DslTabBorder.gradientRadii
+ }.originDrawable
+
+ updateOriginDrawable()
+ }
+ }
+
+ override fun draw(canvas: Canvas) {
+ super.draw(canvas)
+
+ originDrawable?.apply {
+ setBounds(
+ paddingLeft,
+ paddingBottom,
+ viewWidth - paddingRight,
+ viewHeight - paddingBottom
+ )
+ draw(canvas)
+ }
+ }
+
+ fun drawBorderBackground(canvas: Canvas) {
+ super.draw(canvas)
+
+ borderBackgroundDrawable?.apply {
+ setBounds(
+ paddingLeft,
+ paddingBottom,
+ viewWidth - paddingRight,
+ viewHeight - paddingBottom
+ )
+ draw(canvas)
+ }
+ }
+
+ var itemSelectBgDrawable: Drawable? = null
+ var itemDeselectBgDrawable: Drawable? = null
+
+ /**开启边框绘制后, [itemView]的背景也需要负责设置*/
+ open fun updateItemBackground(
+ tabLayout: DslTabLayout,
+ itemView: View,
+ index: Int,
+ select: Boolean
+ ) {
+
+ if (!borderDrawItemBackground) {
+ return
+ }
+
+ if (select) {
+
+ val isFirst = index == 0
+ val isLast = index == tabLayout.dslSelector.visibleViewList.size - 1
+
+ val drawable = DslGradientDrawable().configDrawable {
+ gradientWidthOffset = borderBackgroundWidthOffset
+ gradientHeightOffset = borderBackgroundHeightOffset
+
+ gradientSolidColor =
+ borderItemBackgroundSolidColor ?: this@DslTabBorder.gradientStrokeColor
+ if (!tabLayout.itemEnableSelector) {
+ if (borderItemBackgroundSolidDisableColor != null) {
+ gradientSolidColor = borderItemBackgroundSolidDisableColor!!
+ }
+ }
+
+ gradientColors = borderItemBackgroundGradientColors
+
+ if ((isFirst && isLast) || borderKeepItemRadius) {
+ //只有一个child
+ gradientRadii = this@DslTabBorder.gradientRadii
+ } else if (isFirst) {
+ if (tabLayout.isHorizontal()) {
+ if (tabLayout.isLayoutRtl) {
+ gradientRadii = floatArrayOf(
+ 0f,
+ 0f,
+ this@DslTabBorder.gradientRadii[2],
+ this@DslTabBorder.gradientRadii[3],
+ this@DslTabBorder.gradientRadii[4],
+ this@DslTabBorder.gradientRadii[5],
+ 0f,
+ 0f
+ )
+ } else {
+ gradientRadii = floatArrayOf(
+ this@DslTabBorder.gradientRadii[0],
+ this@DslTabBorder.gradientRadii[1],
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ this@DslTabBorder.gradientRadii[6],
+ this@DslTabBorder.gradientRadii[7]
+ )
+ }
+ } else {
+ gradientRadii = floatArrayOf(
+ this@DslTabBorder.gradientRadii[0],
+ this@DslTabBorder.gradientRadii[1],
+ this@DslTabBorder.gradientRadii[2],
+ this@DslTabBorder.gradientRadii[3],
+ 0f,
+ 0f,
+ 0f,
+ 0f
+ )
+ }
+ } else if (isLast) {
+ if (tabLayout.isHorizontal()) {
+ if (tabLayout.isLayoutRtl) {
+ gradientRadii = floatArrayOf(
+ this@DslTabBorder.gradientRadii[0],
+ this@DslTabBorder.gradientRadii[1],
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ this@DslTabBorder.gradientRadii[6],
+ this@DslTabBorder.gradientRadii[7]
+ )
+ } else {
+ gradientRadii = floatArrayOf(
+ 0f,
+ 0f,
+ this@DslTabBorder.gradientRadii[2],
+ this@DslTabBorder.gradientRadii[3],
+ this@DslTabBorder.gradientRadii[4],
+ this@DslTabBorder.gradientRadii[5],
+ 0f,
+ 0f
+ )
+ }
+ } else {
+ gradientRadii = floatArrayOf(
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ this@DslTabBorder.gradientRadii[4],
+ this@DslTabBorder.gradientRadii[5],
+ this@DslTabBorder.gradientRadii[6],
+ this@DslTabBorder.gradientRadii[7]
+ )
+ }
+ }
+ }
+
+ itemSelectBgDrawable = drawable
+
+ ViewCompat.setBackground(itemView, itemSelectBgDrawable)
+ } else {
+ ViewCompat.setBackground(itemView, itemDeselectBgDrawable)
+ }
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabDivider.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabDivider.kt
new file mode 100644
index 000000000..f0fe41c35
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabDivider.kt
@@ -0,0 +1,153 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Canvas
+import android.util.AttributeSet
+import android.widget.LinearLayout
+
+/**
+ * 垂直分割线
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/27
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslTabDivider : DslGradientDrawable() {
+
+ var dividerWidth = 2 * dpi
+ var dividerHeight = 2 * dpi
+ var dividerMarginLeft = 0
+ var dividerMarginRight = 0
+ var dividerMarginTop = 0
+ var dividerMarginBottom = 0
+
+ /**
+ * [LinearLayout.SHOW_DIVIDER_BEGINNING]
+ * [LinearLayout.SHOW_DIVIDER_MIDDLE]
+ * [LinearLayout.SHOW_DIVIDER_END]
+ * */
+ var dividerShowMode = LinearLayout.SHOW_DIVIDER_MIDDLE
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ super.initAttribute(context, attributeSet)
+ val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+
+ dividerWidth = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_width,
+ dividerWidth
+ )
+ dividerHeight = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_height,
+ dividerHeight
+ )
+ dividerMarginLeft = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_margin_left,
+ dividerMarginLeft
+ )
+ dividerMarginRight = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_margin_right,
+ dividerMarginRight
+ )
+ dividerMarginTop = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_margin_top,
+ dividerMarginTop
+ )
+ dividerMarginBottom = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_margin_bottom,
+ dividerMarginBottom
+ )
+
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_divider_solid_color)) {
+ gradientSolidColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_divider_solid_color,
+ gradientSolidColor
+ )
+ } else if (typedArray.hasValue(R.styleable.DslTabLayout_tab_border_stroke_color)) {
+ gradientSolidColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_border_stroke_color,
+ gradientSolidColor
+ )
+ } else {
+ gradientSolidColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_deselect_color,
+ gradientSolidColor
+ )
+ }
+
+ gradientStrokeColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_divider_stroke_color,
+ gradientStrokeColor
+ )
+ gradientStrokeWidth = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_stroke_width,
+ 0
+ )
+ val radiusSize =
+ typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_divider_radius_size,
+ 2 * dpi
+ )
+
+ cornerRadius(radiusSize.toFloat())
+
+ originDrawable = typedArray.getDrawable(R.styleable.DslTabLayout_tab_divider_drawable)
+
+ dividerShowMode =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_divider_show_mode, dividerShowMode)
+
+ typedArray.recycle()
+
+ if (originDrawable == null) {
+ //无自定义的drawable, 那么自绘.
+
+ updateOriginDrawable()
+ }
+ }
+
+ override fun draw(canvas: Canvas) {
+ super.draw(canvas)
+
+ originDrawable?.apply {
+ bounds = this@DslTabDivider.bounds
+ draw(canvas)
+ }
+ }
+
+ val _tabLayout: DslTabLayout?
+ get() = if (callback is DslTabLayout) callback as DslTabLayout else null
+
+ /**
+ * [childIndex]位置前面是否需要分割线
+ * */
+ open fun haveBeforeDivider(childIndex: Int, childCount: Int): Boolean {
+ val tabLayout = _tabLayout
+ if (tabLayout != null && tabLayout.isHorizontal() && tabLayout.isLayoutRtl) {
+ if (childIndex == 0) {
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_END != 0
+ }
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_MIDDLE != 0
+ }
+
+ if (childIndex == 0) {
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_BEGINNING != 0
+ }
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_MIDDLE != 0
+ }
+
+ /**
+ * [childIndex]位置后面是否需要分割线
+ * */
+ open fun haveAfterDivider(childIndex: Int, childCount: Int): Boolean {
+ val tabLayout = _tabLayout
+ if (tabLayout != null && tabLayout.isHorizontal() && tabLayout.isLayoutRtl) {
+ if (childIndex == childCount - 1) {
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_BEGINNING != 0
+ }
+ }
+
+ if (childIndex == childCount - 1) {
+ return dividerShowMode and LinearLayout.SHOW_DIVIDER_END != 0
+ }
+ return false
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabHighlight.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabHighlight.kt
new file mode 100644
index 000000000..4c21bbd56
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabHighlight.kt
@@ -0,0 +1,118 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.util.AttributeSet
+import android.view.ViewGroup
+
+/**
+ *
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2021/05/19
+ * Copyright (c) 2020 ShenZhen Wayto Ltd. All rights reserved.
+ */
+open class DslTabHighlight(val tabLayout: DslTabLayout) : DslGradientDrawable() {
+
+ /**需要绘制的Drawable*/
+ var highlightDrawable: Drawable? = null
+
+ /**宽度测量模式*/
+ var highlightWidth = ViewGroup.LayoutParams.MATCH_PARENT
+
+ /**高度测量模式*/
+ var highlightHeight = ViewGroup.LayoutParams.MATCH_PARENT
+
+ /**宽度补偿*/
+ var highlightWidthOffset = 0
+
+ /**高度补偿*/
+ var highlightHeightOffset = 0
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ //super.initAttribute(context, attributeSet)
+
+ val typedArray =
+ context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+ highlightDrawable = typedArray.getDrawable(R.styleable.DslTabLayout_tab_highlight_drawable)
+
+ highlightWidth = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_highlight_width,
+ highlightWidth
+ )
+ highlightHeight = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_highlight_height,
+ highlightHeight
+ )
+
+ highlightWidthOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_highlight_width_offset,
+ highlightWidthOffset
+ )
+ highlightHeightOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_highlight_height_offset,
+ highlightHeightOffset
+ )
+
+ typedArray.recycle()
+
+ if (highlightDrawable == null && isValidConfig()) {
+ updateOriginDrawable()
+ }
+ }
+
+ override fun updateOriginDrawable(): GradientDrawable? {
+ val drawable = super.updateOriginDrawable()
+ highlightDrawable = originDrawable
+ return drawable
+ }
+
+ override fun draw(canvas: Canvas) {
+ //super.draw(canvas)
+ val itemView = tabLayout.currentItemView
+ if (itemView != null) {
+ val lp = itemView.layoutParams
+
+ if (lp is DslTabLayout.LayoutParams) {
+ lp.highlightDrawable ?: highlightDrawable
+ } else {
+ highlightDrawable
+ }?.apply {
+
+ val drawWidth: Int = when (highlightWidth) {
+ ViewGroup.LayoutParams.MATCH_PARENT -> itemView.measuredWidth
+ ViewGroup.LayoutParams.WRAP_CONTENT -> intrinsicWidth
+ else -> highlightWidth
+ } + highlightWidthOffset
+
+ val drawHeight: Int = when (highlightHeight) {
+ ViewGroup.LayoutParams.MATCH_PARENT -> itemView.measuredHeight
+ ViewGroup.LayoutParams.WRAP_CONTENT -> intrinsicHeight
+ else -> highlightHeight
+ } + highlightHeightOffset
+
+ val centerX: Int = itemView.left + (itemView.right - itemView.left) / 2
+ val centerY: Int = itemView.top + (itemView.bottom - itemView.top) / 2
+
+ setBounds(
+ centerX - drawWidth / 2,
+ centerY - drawHeight / 2,
+ centerX + drawWidth / 2,
+ centerY + drawHeight / 2
+ )
+
+ draw(canvas)
+ canvas.save()
+ if (tabLayout.isHorizontal()) {
+ canvas.translate(itemView.left.toFloat(), 0f)
+ } else {
+ canvas.translate(0f, itemView.top.toFloat())
+ }
+ itemView.draw(canvas)
+ canvas.restore()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabIndicator.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabIndicator.kt
new file mode 100644
index 000000000..316ced0ad
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabIndicator.kt
@@ -0,0 +1,931 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.graphics.withSave
+import java.util.*
+import kotlin.math.absoluteValue
+import kotlin.math.max
+
+/**
+ * 指示器
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/25
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslTabIndicator(val tabLayout: DslTabLayout) : DslGradientDrawable() {
+
+ companion object {
+
+ /**非颜色值*/
+ const val NO_COLOR = -2
+
+ //---style---
+
+ /**不绘制指示器*/
+ const val INDICATOR_STYLE_NONE = 0
+
+ /**指示器绘制在[itemView]的顶部*/
+ const val INDICATOR_STYLE_TOP = 0x1
+
+ /**指示器绘制在[itemView]的底部*/
+ const val INDICATOR_STYLE_BOTTOM = 0x2
+
+ /**默认样式,指示器绘制在[itemView]的中心*/
+ const val INDICATOR_STYLE_CENTER = 0x4
+
+ /**前景绘制,
+ * 默认是背景绘制, 指示器绘制[itemView]的背部, [itemView] 请不要设置background, 否则可能看不见*/
+ const val INDICATOR_STYLE_FOREGROUND = 0x1000
+
+ //---gravity---
+
+ /**指示器重力在开始的位置(横向左边, 纵向上边)*/
+ const val INDICATOR_GRAVITY_START = 0x1
+
+ /**指示器重力在结束的位置(横向右边, 纵向下边)*/
+ const val INDICATOR_GRAVITY_END = 0x2
+
+ /**指示器重力在中间*/
+ const val INDICATOR_GRAVITY_CENTER = 0x4
+ }
+
+ /**指示器绘制的样式*/
+ var indicatorStyle = INDICATOR_STYLE_NONE //初始化
+
+ /**[indicatorStyle]*/
+ val _indicatorDrawStyle: Int
+ get() = indicatorStyle.remove(INDICATOR_STYLE_FOREGROUND)
+
+ /**优先将指示器显示在[DslTabLayout]的什么位置
+ * [INDICATOR_GRAVITY_START] 开始的位置
+ * [INDICATOR_GRAVITY_END] 结束的位置
+ * [INDICATOR_GRAVITY_CENTER] 中间的位置*/
+ var indicatorGravity = INDICATOR_GRAVITY_CENTER
+
+ /**
+ * 指示器在流向下一个位置时, 是否采用[Flow]流线的方式改变宽度
+ * */
+ var indicatorEnableFlow: Boolean = false
+
+ /**指示器闪现效果, 从当前位置直接跨越到目标位置*/
+ var indicatorEnableFlash: Boolean = false
+
+ /**使用clip的方式绘制闪现效果*/
+ var indicatorEnableFlashClip: Boolean = true
+
+ /**当目标和当前的索引差值<=此值时, [Flow]效果才有效*/
+ var indicatorFlowStep: Int = 1
+
+ /**指示器绘制实体*/
+ var indicatorDrawable: Drawable? = null
+ set(value) {
+ field = tintDrawableColor(value, indicatorColor)
+ }
+
+ /**过滤[indicatorDrawable]的颜色*/
+ var indicatorColor: Int = NO_COLOR
+ set(value) {
+ field = value
+ indicatorDrawable = indicatorDrawable
+ }
+
+ /**
+ * 指示器的宽度
+ * WRAP_CONTENT: [childView]内容的宽度,
+ * MATCH_PARENT: [childView]的宽度
+ * 40dp: 固定值
+ * */
+ var indicatorWidth = 0 //初始化
+
+ /**宽度补偿*/
+ var indicatorWidthOffset = 0
+
+ /**
+ * 指示器的高度
+ * WRAP_CONTENT: [childView]内容的高度,
+ * MATCH_PARENT: [childView]的高度
+ * 40dp: 固定值
+ * */
+ var indicatorHeight = 0 //初始化
+
+ /**高度补偿*/
+ var indicatorHeightOffset = 0
+
+ /**XY轴方向补偿*/
+ var indicatorXOffset = 0
+
+ /**会根据[indicatorStyle]自动取负值*/
+ var indicatorYOffset = 0
+
+ /**
+ * 宽高[WRAP_CONTENT]时, 内容view的定位索引
+ * */
+ var indicatorContentIndex = -1
+ var indicatorContentId = View.NO_ID
+
+ /**切换时是否需要动画的支持*/
+ var indicatorAnim = true
+
+ /**在获取锚点view的宽高时, 是否需要忽略对应的padding属性*/
+ var ignoreChildPadding: Boolean = true
+
+ init {
+ callback = tabLayout
+ }
+
+ override fun initAttribute(context: Context, attributeSet: AttributeSet?) {
+ val typedArray =
+ context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+
+ indicatorDrawable = typedArray.getDrawable(R.styleable.DslTabLayout_tab_indicator_drawable)
+ indicatorColor =
+ typedArray.getColor(R.styleable.DslTabLayout_tab_indicator_color, indicatorColor)
+ indicatorStyle = typedArray.getInt(
+ R.styleable.DslTabLayout_tab_indicator_style,
+ if (tabLayout.isHorizontal()) INDICATOR_STYLE_BOTTOM else INDICATOR_STYLE_TOP
+ )
+ indicatorGravity = typedArray.getInt(
+ R.styleable.DslTabLayout_tab_indicator_gravity,
+ indicatorGravity
+ )
+
+ //初始化指示器的高度和宽度
+ if (indicatorStyle.have(INDICATOR_STYLE_FOREGROUND)) {
+ //前景绘制
+ indicatorWidth = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_indicator_width,
+ if (tabLayout.isHorizontal()) ViewGroup.LayoutParams.MATCH_PARENT else 3 * dpi
+ )
+ indicatorHeight = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_indicator_height,
+ if (tabLayout.isHorizontal()) 3 * dpi else ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ indicatorXOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_x_offset,
+ if (tabLayout.isHorizontal()) 0 else 2 * dpi
+ )
+ indicatorYOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_y_offset,
+ if (tabLayout.isHorizontal()) 2 * dpi else 0
+ )
+ } else {
+ //背景绘制样式
+ if (tabLayout.isHorizontal()) {
+ indicatorWidth = ViewGroup.LayoutParams.MATCH_PARENT
+ indicatorHeight = ViewGroup.LayoutParams.MATCH_PARENT
+ } else {
+ indicatorHeight = ViewGroup.LayoutParams.MATCH_PARENT
+ indicatorWidth = ViewGroup.LayoutParams.MATCH_PARENT
+ }
+ indicatorWidth = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_indicator_width,
+ indicatorWidth
+ )
+ indicatorHeight = typedArray.getLayoutDimension(
+ R.styleable.DslTabLayout_tab_indicator_height,
+ indicatorHeight
+ )
+ indicatorXOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_x_offset,
+ indicatorXOffset
+ )
+ indicatorYOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_y_offset,
+ indicatorYOffset
+ )
+ }
+
+ ignoreChildPadding = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_indicator_ignore_child_padding,
+ !indicatorStyle.have(INDICATOR_STYLE_CENTER)
+ )
+
+ indicatorFlowStep =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_indicator_flow_step, indicatorFlowStep)
+ indicatorEnableFlow = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_indicator_enable_flow,
+ indicatorEnableFlow
+ )
+ indicatorEnableFlash = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_indicator_enable_flash,
+ indicatorEnableFlash
+ )
+ indicatorEnableFlashClip = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_indicator_enable_flash_clip,
+ indicatorEnableFlashClip
+ )
+
+ indicatorWidthOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_width_offset,
+ indicatorWidthOffset
+ )
+ indicatorHeightOffset = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_height_offset,
+ indicatorHeightOffset
+ )
+ indicatorContentIndex = typedArray.getInt(
+ R.styleable.DslTabLayout_tab_indicator_content_index,
+ indicatorContentIndex
+ )
+ indicatorContentId = typedArray.getResourceId(
+ R.styleable.DslTabLayout_tab_indicator_content_id,
+ indicatorContentId
+ )
+ indicatorAnim = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_indicator_anim,
+ indicatorAnim
+ )
+
+ //代码构建Drawable
+ gradientShape =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_indicator_shape, gradientShape)
+ gradientSolidColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_indicator_solid_color,
+ gradientSolidColor
+ )
+ gradientStrokeColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_indicator_stroke_color,
+ gradientStrokeColor
+ )
+ gradientStrokeWidth = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_stroke_width,
+ gradientStrokeWidth
+ )
+ gradientDashWidth = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_dash_width,
+ gradientDashWidth.toInt()
+ ).toFloat()
+ gradientDashGap = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_indicator_dash_gap,
+ gradientDashGap.toInt()
+ ).toFloat()
+
+ val gradientRadius =
+ typedArray.getDimensionPixelOffset(R.styleable.DslTabLayout_tab_indicator_radius, 0)
+ if (gradientRadius > 0) {
+ Arrays.fill(gradientRadii, gradientRadius.toFloat())
+ } else {
+ typedArray.getString(R.styleable.DslTabLayout_tab_indicator_radii)?.let {
+ _fillRadii(gradientRadii, it)
+ }
+ }
+
+ val gradientColors =
+ typedArray.getString(R.styleable.DslTabLayout_tab_indicator_gradient_colors)
+
+ this.gradientColors = if (gradientColors.isNullOrEmpty()) {
+ val startColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_indicator_gradient_start_color,
+ Color.TRANSPARENT
+ )
+ val endColor = typedArray.getColor(
+ R.styleable.DslTabLayout_tab_indicator_gradient_end_color,
+ Color.TRANSPARENT
+ )
+ if (startColor != endColor) {
+ intArrayOf(startColor, endColor)
+ } else {
+ this.gradientColors
+ }
+ } else {
+ _fillColor(gradientColors) ?: this.gradientColors
+ }
+ //...end
+
+ typedArray.recycle()
+
+ if (indicatorDrawable == null && isValidConfig()) {
+ updateOriginDrawable()
+ }
+ }
+
+ override fun updateOriginDrawable(): GradientDrawable? {
+ val drawable = super.updateOriginDrawable()
+ indicatorDrawable = originDrawable
+ return drawable
+ }
+
+ open fun tintDrawableColor(drawable: Drawable?, color: Int): Drawable? {
+ if (drawable == null || color == NO_COLOR) {
+ return drawable
+ }
+ return drawable.tintDrawableColor(color)
+ }
+
+ /**指示器需要参考的目标控件*/
+ open fun indicatorContentView(childView: View): View? {
+ val lp = childView.layoutParams as DslTabLayout.LayoutParams
+
+ val contentId =
+ if (lp.indicatorContentId != View.NO_ID) lp.indicatorContentId else indicatorContentId
+
+ if (contentId != View.NO_ID) {
+ return childView.findViewById(contentId)
+ }
+
+ //如果child强制指定了index, 就用指定的.
+ val contentIndex =
+ if (lp.indicatorContentIndex >= 0) lp.indicatorContentIndex else indicatorContentIndex
+
+ return if (contentIndex >= 0 && childView is ViewGroup && contentIndex in 0 until childView.childCount) {
+ //有指定
+ val contentChildView = childView.getChildAt(contentIndex)
+ contentChildView
+ } else {
+ //没有指定
+ null
+ }
+ }
+
+ /**根据指定[index]索引, 获取目标[View]*/
+ open fun targetChildView(
+ index: Int,
+ onChildView: (childView: View, contentChildView: View?) -> Unit
+ ) {
+ tabLayout.dslSelector.visibleViewList.getOrNull(index)?.also { childView ->
+ onChildView(childView, indicatorContentView(childView))
+ }
+ }
+
+ open fun getChildTargetPaddingLeft(childView: View): Int =
+ if (ignoreChildPadding) childView.paddingLeft else 0
+
+ open fun getChildTargetPaddingRight(childView: View): Int =
+ if (ignoreChildPadding) childView.paddingRight else 0
+
+ open fun getChildTargetPaddingTop(childView: View): Int =
+ if (ignoreChildPadding) childView.paddingTop else 0
+
+ open fun getChildTargetPaddingBottom(childView: View): Int =
+ if (ignoreChildPadding) childView.paddingBottom else 0
+
+ open fun getChildTargetWidth(childView: View): Int =
+ if (ignoreChildPadding) childView.viewDrawWidth else childView.measuredWidth
+
+ open fun getChildTargetHeight(childView: View): Int =
+ if (ignoreChildPadding) childView.viewDrawHeight else childView.measuredHeight
+
+ /**
+ * [childview]对应的中心x坐标
+ * */
+ open fun getChildTargetX(index: Int, gravity: Int = indicatorGravity): Int {
+
+ var result = if (index > 0) tabLayout.maxWidth else 0
+
+ targetChildView(index) { childView, contentChildView ->
+ result = if (contentChildView == null) {
+ when (gravity) {
+ INDICATOR_GRAVITY_START -> childView.left
+ INDICATOR_GRAVITY_END -> childView.right
+ else -> childView.left + getChildTargetPaddingLeft(childView) + getChildTargetWidth(
+ childView
+ ) / 2
+ }
+ } else {
+ when (gravity) {
+ INDICATOR_GRAVITY_START -> childView.left + contentChildView.left
+ INDICATOR_GRAVITY_END -> childView.left + contentChildView.right
+ else -> childView.left + contentChildView.left + getChildTargetPaddingLeft(
+ contentChildView
+ ) + getChildTargetWidth(
+ contentChildView
+ ) / 2
+ }
+ }
+ }
+
+ return result
+ }
+
+ open fun getChildTargetY(index: Int, gravity: Int = indicatorGravity): Int {
+
+ var result = if (index > 0) tabLayout.maxHeight else 0
+
+ targetChildView(index) { childView, contentChildView ->
+ result = if (contentChildView == null) {
+ when (gravity) {
+ INDICATOR_GRAVITY_START -> childView.top
+ INDICATOR_GRAVITY_END -> childView.bottom
+ else -> childView.top + getChildTargetPaddingTop(childView) + getChildTargetHeight(
+ childView
+ ) / 2
+ }
+ } else {
+ when (gravity) {
+ INDICATOR_GRAVITY_START -> childView.top + contentChildView.top
+ INDICATOR_GRAVITY_END -> childView.top + childView.bottom
+ else -> childView.top + contentChildView.top + getChildTargetPaddingTop(
+ contentChildView
+ ) + getChildTargetHeight(
+ contentChildView
+ ) / 2
+ }
+ }
+ }
+
+ return result
+ }
+
+ open fun getIndicatorDrawWidth(index: Int): Int {
+ var result = indicatorWidth
+
+ when (indicatorWidth) {
+ ViewGroup.LayoutParams.WRAP_CONTENT -> {
+ tabLayout.dslSelector.visibleViewList.getOrNull(index)?.also { childView ->
+ result = getChildTargetWidth(indicatorContentView(childView) ?: childView)
+ }
+ }
+ ViewGroup.LayoutParams.MATCH_PARENT -> {
+ tabLayout.dslSelector.visibleViewList.getOrNull(index)?.also { childView ->
+ result = childView.measuredWidth
+ }
+ }
+ }
+
+ return result + indicatorWidthOffset
+ }
+
+ open fun getIndicatorDrawHeight(index: Int): Int {
+ var result = indicatorHeight
+
+ when (indicatorHeight) {
+ ViewGroup.LayoutParams.WRAP_CONTENT -> {
+ tabLayout.dslSelector.visibleViewList.getOrNull(index)?.also { childView ->
+ result = getChildTargetHeight(indicatorContentView(childView) ?: childView)
+ }
+ }
+ ViewGroup.LayoutParams.MATCH_PARENT -> {
+ tabLayout.dslSelector.visibleViewList.getOrNull(index)?.also { childView ->
+ result = childView.measuredHeight
+ }
+ }
+ }
+
+ return result + indicatorHeightOffset
+ }
+
+ override fun draw(canvas: Canvas) {
+ //super.draw(canvas)
+ if (!isVisible || _indicatorDrawStyle == INDICATOR_STYLE_NONE || indicatorDrawable == null) {
+ //不绘制
+ return
+ }
+
+ if (tabLayout.isHorizontal()) {
+ drawHorizontal(canvas)
+ } else {
+ drawVertical(canvas)
+ }
+ }
+
+ fun drawHorizontal(canvas: Canvas) {
+ val childSize = tabLayout.dslSelector.visibleViewList.size
+
+ var currentIndex = currentIndex
+
+ if (_targetIndex in 0 until childSize) {
+ currentIndex = max(0, currentIndex)
+ }
+
+ if (currentIndex in 0 until childSize) {
+
+ } else {
+ //无效的index
+ return
+ }
+
+ //"绘制$currentIndex:$currentSelectIndex $positionOffset".logi()
+
+ val drawTargetX = getChildTargetX(currentIndex)
+ val drawWidth = getIndicatorDrawWidth(currentIndex)
+ val drawHeight = getIndicatorDrawHeight(currentIndex)
+
+ val drawLeft = drawTargetX - drawWidth / 2 + indicatorXOffset
+
+ //动画过程中的left
+ var animLeft = drawLeft
+ //width
+ var animWidth = drawWidth
+ //动画执行过程中, 高度额外变大的值
+ var animExHeight = 0
+
+ //end value
+ val nextDrawTargetX = getChildTargetX(_targetIndex)
+ val nextDrawWidth = getIndicatorDrawWidth(_targetIndex)
+ val nextDrawLeft = nextDrawTargetX - nextDrawWidth / 2 + indicatorXOffset
+
+ var animEndWidth = nextDrawWidth
+ var animEndLeft = nextDrawLeft
+
+ if (_targetIndex in 0 until childSize && _targetIndex != currentIndex) {
+
+ //动画过程参数计算变量
+ val animStartLeft = drawLeft
+ val animStartWidth = drawWidth
+
+ val animEndHeight = getIndicatorDrawHeight(_targetIndex)
+
+ if (indicatorEnableFlash) {
+ //闪现效果
+ animWidth = (animWidth * (1 - positionOffset)).toInt()
+ animEndWidth = (animEndWidth * positionOffset).toInt()
+
+ animLeft = drawTargetX - animWidth / 2 + indicatorXOffset
+ animEndLeft = nextDrawLeft
+ } else if (indicatorEnableFlow && (_targetIndex - currentIndex).absoluteValue <= indicatorFlowStep) {
+ //激活了流动效果
+
+ val flowEndWidth: Int
+ if (_targetIndex > currentIndex) {
+ flowEndWidth = animEndLeft - animStartLeft + animEndWidth
+
+ //目标在右边
+ animLeft = if (positionOffset >= 0.5) {
+ (animStartLeft + (animEndLeft - animStartLeft) * (positionOffset - 0.5) / 0.5f).toInt()
+ } else {
+ animStartLeft
+ }
+ } else {
+ flowEndWidth = animStartLeft - animEndLeft + animStartWidth
+
+ //目标在左边
+ animLeft = if (positionOffset >= 0.5) {
+ animEndLeft
+ } else {
+ (animStartLeft - (animStartLeft - animEndLeft) * positionOffset / 0.5f).toInt()
+ }
+ }
+
+ animWidth = if (positionOffset >= 0.5) {
+ (flowEndWidth - (flowEndWidth - animEndWidth) * (positionOffset - 0.5) / 0.5f).toInt()
+ } else {
+ (animStartWidth + (flowEndWidth - animStartWidth) * positionOffset / 0.5f).toInt()
+ }
+ } else {
+ //默认平移效果
+ if (_targetIndex > currentIndex) {
+ //目标在右边
+ animLeft =
+ (animStartLeft + (animEndLeft - animStartLeft) * positionOffset).toInt()
+ } else {
+ //目标在左边
+ animLeft =
+ (animStartLeft - (animStartLeft - animEndLeft) * positionOffset).toInt()
+ }
+
+ //动画过程中的宽度
+ animWidth =
+ (animStartWidth + (animEndWidth - animStartWidth) * positionOffset).toInt()
+ }
+
+ animExHeight = ((animEndHeight - drawHeight) * positionOffset).toInt()
+ }
+
+ //前景
+ val drawTop = when (_indicatorDrawStyle) {
+ //底部绘制
+ INDICATOR_STYLE_BOTTOM -> viewHeight - drawHeight - indicatorYOffset
+ //顶部绘制
+ INDICATOR_STYLE_TOP -> 0 + indicatorYOffset
+ //居中绘制
+ else -> paddingTop + viewDrawHeight / 2 - drawHeight / 2 + indicatorYOffset -
+ animExHeight +
+ (tabLayout._maxConvexHeight - _childConvexHeight(currentIndex)) / 2
+ }
+
+ indicatorDrawable?.apply {
+ if (indicatorEnableFlash) {
+ //flash
+ if (indicatorEnableFlashClip) {
+ drawIndicatorClipHorizontal(
+ this,
+ canvas,
+ drawLeft,
+ drawTop,
+ drawLeft + drawWidth,
+ drawTop + drawHeight + animExHeight,
+ animWidth,
+ 1 - positionOffset
+ )
+ } else {
+ drawIndicator(
+ this, canvas, animLeft,
+ drawTop,
+ animLeft + animWidth,
+ drawTop + drawHeight + animExHeight,
+ 1 - positionOffset
+ )
+ }
+
+ if (_targetIndex in 0 until childSize) {
+ if (indicatorEnableFlashClip) {
+ drawIndicatorClipHorizontal(
+ this,
+ canvas,
+ nextDrawLeft,
+ drawTop,
+ nextDrawLeft + nextDrawWidth,
+ drawTop + drawHeight + animExHeight,
+ animEndWidth,
+ positionOffset
+ )
+ } else {
+ drawIndicator(
+ this, canvas, animEndLeft,
+ drawTop,
+ animEndLeft + animEndWidth,
+ drawTop + drawHeight + animExHeight,
+ positionOffset
+ )
+ }
+ }
+ } else {
+ //normal
+ drawIndicator(
+ this, canvas, animLeft,
+ drawTop,
+ animLeft + animWidth,
+ drawTop + drawHeight + animExHeight,
+ 1 - positionOffset
+ )
+ }
+ }
+ }
+
+ fun drawIndicator(
+ indicator: Drawable,
+ canvas: Canvas,
+ l: Int,
+ t: Int,
+ r: Int,
+ b: Int,
+ offset: Float
+ ) {
+ indicator.apply {
+ if (this is ITabIndicatorDraw) {
+ setBounds(l, t, r, b)
+ onDrawTabIndicator(this@DslTabIndicator, canvas, offset)
+ } else {
+ val width = r - l
+ val height = b - t
+ setBounds(0, 0, width, height)
+ canvas.withSave {
+ translate(l.toFloat(), t.toFloat())
+ draw(canvas)
+ }
+ }
+ }
+ }
+
+ fun drawIndicatorClipHorizontal(
+ indicator: Drawable,
+ canvas: Canvas,
+ l: Int,
+ t: Int,
+ r: Int,
+ b: Int,
+ endWidth: Int,
+ offset: Float
+ ) {
+ indicator.apply {
+ canvas.save()
+ val dx = (r - l - endWidth) / 2
+ canvas.clipRect(l + dx, t, r - dx, b)
+ setBounds(l, t, r, b)
+ if (this is ITabIndicatorDraw) {
+ onDrawTabIndicator(this@DslTabIndicator, canvas, offset)
+ } else {
+ draw(canvas)
+ }
+ canvas.restore()
+ }
+ }
+
+ fun drawIndicatorClipVertical(
+ indicator: Drawable,
+ canvas: Canvas,
+ l: Int,
+ t: Int,
+ r: Int,
+ b: Int,
+ endHeight: Int,
+ offset: Float
+ ) {
+ indicator.apply {
+ canvas.save()
+ val dy = (b - t - endHeight) / 2
+ canvas.clipRect(l, t + dy, r, b - dy)
+ setBounds(l, t, r, b)
+ if (this is ITabIndicatorDraw) {
+ onDrawTabIndicator(this@DslTabIndicator, canvas, offset)
+ } else {
+ draw(canvas)
+ }
+ canvas.restore()
+ }
+ }
+
+ fun drawVertical(canvas: Canvas) {
+ val childSize = tabLayout.dslSelector.visibleViewList.size
+
+ var currentIndex = currentIndex
+
+ if (_targetIndex in 0 until childSize) {
+ currentIndex = max(0, currentIndex)
+ }
+
+ if (currentIndex in 0 until childSize) {
+
+ } else {
+ //无效的index
+ return
+ }
+
+ //"绘制$currentIndex:$currentSelectIndex $positionOffset".logi()
+
+ val drawTargetY = getChildTargetY(currentIndex)
+ val drawWidth = getIndicatorDrawWidth(currentIndex)
+ val drawHeight = getIndicatorDrawHeight(currentIndex)
+
+ val drawTop = drawTargetY - drawHeight / 2 + indicatorYOffset
+
+ //动画过程中的top
+ var animTop = drawTop
+ //height
+ var animHeight = drawHeight
+ //动画执行过程中, 宽度额外变大的值
+ var animExWidth = 0
+
+ //end value
+ val nextDrawTargetY = getChildTargetY(_targetIndex)
+ val nextDrawHeight = getIndicatorDrawHeight(_targetIndex)
+ val nextDrawTop = nextDrawTargetY - nextDrawHeight / 2 + indicatorYOffset
+
+ var animEndHeight = nextDrawHeight
+ var animEndTop = nextDrawTop
+
+ if (_targetIndex in 0 until childSize && _targetIndex != currentIndex) {
+
+ //动画过程参数计算变量
+ val animStartTop = drawTop
+ val animStartHeight = drawHeight
+
+ val animEndWidth = getIndicatorDrawWidth(_targetIndex)
+
+ if (indicatorEnableFlash) {
+ //闪现效果
+ animHeight = (animHeight * (1 - positionOffset)).toInt()
+ animEndHeight = (animEndHeight * positionOffset).toInt()
+
+ animTop = drawTargetY - animHeight / 2 + indicatorXOffset
+ animEndTop = nextDrawTargetY - animEndHeight / 2 + indicatorXOffset
+ } else if (indicatorEnableFlow && (_targetIndex - currentIndex).absoluteValue <= indicatorFlowStep) {
+ //激活了流动效果
+
+ val flowEndHeight: Int
+ if (_targetIndex > currentIndex) {
+ flowEndHeight = animEndTop - animStartTop + animEndHeight
+
+ //目标在下边
+ animTop = if (positionOffset >= 0.5) {
+ (animStartTop + (animEndTop - animStartTop) * (positionOffset - 0.5) / 0.5f).toInt()
+ } else {
+ animStartTop
+ }
+ } else {
+ flowEndHeight = animStartTop - animEndTop + animStartHeight
+
+ //目标在上边
+ animTop = if (positionOffset >= 0.5) {
+ animEndTop
+ } else {
+ (animStartTop - (animStartTop - animEndTop) * positionOffset / 0.5f).toInt()
+ }
+ }
+
+ animHeight = if (positionOffset >= 0.5) {
+ (flowEndHeight - (flowEndHeight - animEndHeight) * (positionOffset - 0.5) / 0.5f).toInt()
+ } else {
+ (animStartHeight + (flowEndHeight - animStartHeight) * positionOffset / 0.5f).toInt()
+ }
+ } else {
+ if (_targetIndex > currentIndex) {
+ //目标在下边
+ animTop = (animStartTop + (animEndTop - animStartTop) * positionOffset).toInt()
+ } else {
+ //目标在上边
+ animTop = (animStartTop - (animStartTop - animEndTop) * positionOffset).toInt()
+ }
+
+ //动画过程中的宽度
+ animHeight =
+ (animStartHeight + (animEndHeight - animStartHeight) * positionOffset).toInt()
+ }
+
+ animExWidth = ((animEndWidth - drawWidth) * positionOffset).toInt()
+ }
+
+ val drawLeft = when (_indicatorDrawStyle) {
+ INDICATOR_STYLE_BOTTOM -> {
+ //右边/底部绘制
+ viewWidth - drawWidth - indicatorXOffset
+ }
+ INDICATOR_STYLE_TOP -> {
+ //左边/顶部绘制
+ 0 + indicatorXOffset
+ }
+ else -> {
+ //居中绘制
+ paddingLeft + indicatorXOffset + (viewDrawWidth / 2 - drawWidth / 2) -
+ (tabLayout._maxConvexHeight - _childConvexHeight(currentIndex)) / 2
+ }
+ }
+
+ indicatorDrawable?.apply {
+ //flash
+ if (indicatorEnableFlash) {
+ if (indicatorEnableFlashClip) {
+ drawIndicatorClipVertical(
+ this, canvas, drawLeft,
+ drawTop,
+ drawLeft + drawWidth + animExWidth,
+ drawTop + drawHeight,
+ animHeight,
+ 1 - positionOffset
+ )
+ } else {
+ drawIndicator(
+ this, canvas, drawLeft,
+ animTop,
+ drawLeft + drawWidth + animExWidth,
+ animTop + animHeight,
+ 1 - positionOffset
+ )
+ }
+
+ if (_targetIndex in 0 until childSize) {
+ if (indicatorEnableFlashClip) {
+ drawIndicatorClipVertical(
+ this, canvas, drawLeft,
+ nextDrawTop,
+ drawLeft + drawWidth + animExWidth,
+ nextDrawTop + nextDrawHeight,
+ animEndHeight,
+ positionOffset
+ )
+ } else {
+ drawIndicator(
+ this, canvas, drawLeft,
+ animEndTop,
+ drawLeft + drawWidth + animExWidth,
+ animEndTop + animEndHeight,
+ positionOffset
+ )
+ }
+ }
+ } else {
+ drawIndicator(
+ this, canvas, drawLeft,
+ animTop,
+ drawLeft + drawWidth + animExWidth,
+ animTop + animHeight,
+ 1 - positionOffset
+ )
+ }
+ }
+ }
+
+ fun _childConvexHeight(index: Int): Int {
+ if (attachView is ViewGroup) {
+ ((attachView as ViewGroup).getChildAt(index).layoutParams as? DslTabLayout.LayoutParams)?.apply {
+ return layoutConvexHeight
+ }
+ }
+ return 0
+ }
+
+ /**
+ * 距离[_targetIndex]的偏移比例.[0->1]的过程
+ * */
+ var positionOffset: Float = 0f
+ set(value) {
+ field = value
+ invalidateSelf()
+ }
+
+ /**当前绘制的index*/
+ var currentIndex: Int = -1
+
+ /**滚动目标的index*/
+ var _targetIndex = -1
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayout.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayout.kt
new file mode 100644
index 000000000..b2c6050fe
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayout.kt
@@ -0,0 +1,2042 @@
+package com.angcyo.tablayout
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.os.Parcelable
+import android.util.AttributeSet
+import android.view.*
+import android.view.animation.LinearInterpolator
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import android.widget.OverScroller
+import android.widget.TextView
+import androidx.core.view.GestureDetectorCompat
+import androidx.core.view.GravityCompat
+import androidx.core.view.ViewCompat
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * https://github.com/angcyo/DslTabLayout
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/23
+ */
+
+open class DslTabLayout(
+ context: Context,
+ val attributeSet: AttributeSet? = null
+) : ViewGroup(context, attributeSet) {
+
+ /**在未指定[minHeight]的[wrap_content]情况下的高度*/
+ var itemDefaultHeight = 40 * dpi
+
+ /**item是否等宽*/
+ var itemIsEquWidth = false
+
+ /**item是否支持选择, 只限制点击事件, 不限制滚动事件*/
+ var itemEnableSelector = true
+
+ /**当子Item数量在此范围内时,开启等宽,此属性优先级最高
+ * [~3] 小于等于3个
+ * [3~] 大于等于3个
+ * [3~5] 3<= <=5
+ * */
+ var itemEquWidthCountRange: IntRange? = null
+
+ /**智能判断Item是否等宽.
+ * 如果所有子项, 未撑满tab时, 则开启等宽模式.此属性会覆盖[itemIsEquWidth]*/
+ var itemAutoEquWidth = false
+
+ /**在等宽的情况下, 指定item的宽度, 小于0, 平分*/
+ var itemWidth = -3
+
+ /**是否绘制指示器*/
+ var drawIndicator = true
+
+ /**指示器*/
+ var tabIndicator: DslTabIndicator = DslTabIndicator(this)
+ set(value) {
+ field = value
+ field.initAttribute(context, attributeSet)
+ }
+
+ /**指示器动画时长*/
+ var tabIndicatorAnimationDuration = 240L
+
+ /**默认选中位置*/
+ var tabDefaultIndex = 0
+
+ /**回调监听器和样式配置器*/
+ var tabLayoutConfig: DslTabLayoutConfig? = null
+ set(value) {
+ field = value
+
+ field?.initAttribute(context, attributeSet)
+ }
+
+ /**边框绘制*/
+ var tabBorder: DslTabBorder? = null
+ set(value) {
+ field = value
+ field?.callback = this
+ field?.initAttribute(context, attributeSet)
+ }
+ var drawBorder = false
+
+ /**垂直分割线*/
+ var tabDivider: DslTabDivider? = null
+ set(value) {
+ field = value
+ field?.callback = this
+ field?.initAttribute(context, attributeSet)
+ }
+ var drawDivider = false
+
+ /**未读数角标*/
+ var tabBadge: DslTabBadge? = null
+ set(value) {
+ field = value
+ field?.callback = this
+ field?.initAttribute(context, attributeSet)
+ }
+ var drawBadge = false
+
+ /**快速角标配置项, 方便使用者*/
+ val tabBadgeConfigMap = mutableMapOf()
+
+ /**角标绘制配置*/
+ var onTabBadgeConfig: (child: View, tabBadge: DslTabBadge, index: Int) -> TabBadgeConfig? =
+ { _, tabBadge, index ->
+ val badgeConfig = getBadgeConfig(index)
+ if (!isInEditMode) {
+ tabBadge.updateBadgeConfig(badgeConfig)
+ }
+ badgeConfig
+ }
+
+ /**是否绘制突出*/
+ var drawHighlight = false
+
+ /**选中突出提示*/
+ var tabHighlight: DslTabHighlight? = null
+ set(value) {
+ field = value
+ field?.callback = this
+ field?.initAttribute(context, attributeSet)
+ }
+
+ /**如果使用了高凸模式. 请使用这个属性设置背景色*/
+ var tabConvexBackgroundDrawable: Drawable? = null
+
+ /**是否激活滑动选择模式*/
+ var tabEnableSelectorMode = false
+
+ /**布局的方向*/
+ var orientation: Int = LinearLayout.HORIZONTAL
+
+ /**布局时, 滚动到居中是否需要动画*/
+ var layoutScrollAnim: Boolean = false
+
+ /**滚动动画的时长*/
+ var scrollAnimDuration = 250
+
+ //
+
+ //fling 速率阈值
+ var _minFlingVelocity = 0
+ var _maxFlingVelocity = 0
+
+ //scroll 阈值
+ var _touchSlop = 0
+
+ //临时变量
+ val _tempRect = Rect()
+
+ //childView选择器
+ val dslSelector: DslSelector by lazy {
+ DslSelector().install(this) {
+ onStyleItemView = { itemView, index, select ->
+ tabLayoutConfig?.onStyleItemView?.invoke(itemView, index, select)
+ }
+ onSelectItemView = { itemView, index, select, fromUser ->
+ tabLayoutConfig?.onSelectItemView?.invoke(itemView, index, select, fromUser)
+ ?: false
+ }
+ onSelectViewChange = { fromView, selectViewList, reselect, fromUser ->
+ tabLayoutConfig?.onSelectViewChange?.invoke(
+ fromView,
+ selectViewList,
+ reselect,
+ fromUser
+ )
+ }
+ onSelectIndexChange = { fromIndex, selectList, reselect, fromUser ->
+ if (tabLayoutConfig == null) {
+ "选择:[$fromIndex]->${selectList} reselect:$reselect fromUser:$fromUser".logi()
+ }
+
+ val toIndex = selectList.lastOrNull() ?: -1
+ _animateToItem(fromIndex, toIndex)
+
+ _scrollToTarget(toIndex, tabIndicator.indicatorAnim)
+ postInvalidate()
+
+ //如果设置[tabLayoutConfig?.onSelectIndexChange], 那么会覆盖[_viewPagerDelegate]的操作.
+ tabLayoutConfig?.onSelectIndexChange?.invoke(
+ fromIndex,
+ selectList,
+ reselect,
+ fromUser
+ ) ?: _viewPagerDelegate?.onSetCurrentItem(fromIndex, toIndex, reselect, fromUser)
+ }
+ }
+ }
+
+ init {
+ val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+ itemIsEquWidth =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_item_is_equ_width, itemIsEquWidth)
+ val maxEquWidthCount =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_item_equ_width_count, -1)
+ if (maxEquWidthCount >= 0) {
+ itemEquWidthCountRange = IntRange(maxEquWidthCount, Int.MAX_VALUE)
+ }
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_item_equ_width_count_range)) {
+ val equWidthCountRangeString =
+ typedArray.getString(R.styleable.DslTabLayout_tab_item_equ_width_count_range)
+ if (equWidthCountRangeString.isNullOrBlank()) {
+ itemEquWidthCountRange = null
+ } else {
+ val rangeList = equWidthCountRangeString.split("~")
+ if (rangeList.size() >= 2) {
+ val min = rangeList.getOrNull(0)?.toIntOrNull() ?: 0
+ val max = rangeList.getOrNull(1)?.toIntOrNull() ?: Int.MAX_VALUE
+ itemEquWidthCountRange = IntRange(min, max)
+ } else {
+ val min = rangeList.getOrNull(0)?.toIntOrNull() ?: Int.MAX_VALUE
+ itemEquWidthCountRange = IntRange(min, Int.MAX_VALUE)
+ }
+ }
+ }
+ itemAutoEquWidth = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_item_auto_equ_width,
+ itemAutoEquWidth
+ )
+ itemWidth =
+ typedArray.getDimensionPixelOffset(R.styleable.DslTabLayout_tab_item_width, itemWidth)
+ itemDefaultHeight = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_item_default_height,
+ itemDefaultHeight
+ )
+ tabDefaultIndex =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_default_index, tabDefaultIndex)
+
+ drawIndicator =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_draw_indicator, drawIndicator)
+ drawDivider =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_draw_divider, drawDivider)
+ drawBorder =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_draw_border, drawBorder)
+ drawBadge =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_draw_badge, drawBadge)
+ drawHighlight =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_draw_highlight, drawHighlight)
+
+ tabEnableSelectorMode =
+ typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_selector_mode,
+ tabEnableSelectorMode
+ )
+
+ tabConvexBackgroundDrawable =
+ typedArray.getDrawable(R.styleable.DslTabLayout_tab_convex_background)
+
+ orientation = typedArray.getInt(R.styleable.DslTabLayout_tab_orientation, orientation)
+
+ layoutScrollAnim =
+ typedArray.getBoolean(R.styleable.DslTabLayout_tab_layout_scroll_anim, layoutScrollAnim)
+ scrollAnimDuration =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_scroll_anim_duration, scrollAnimDuration)
+
+ //preview
+ if (isInEditMode) {
+ val layoutId =
+ typedArray.getResourceId(R.styleable.DslTabLayout_tab_preview_item_layout_id, -1)
+ val layoutCount =
+ typedArray.getInt(R.styleable.DslTabLayout_tab_preview_item_count, 3)
+ if (layoutId != -1) {
+ for (i in 0 until layoutCount) {
+ inflate(layoutId, true).let {
+ if (it is TextView) {
+ if (it.text.isNullOrEmpty()) {
+ it.text = "Item $i"
+ } else {
+ it.text = "${it.text}/$i"
+ }
+ }
+ }
+ }
+ }
+ }
+
+ typedArray.recycle()
+
+ val vc = ViewConfiguration.get(context)
+ _minFlingVelocity = vc.scaledMinimumFlingVelocity
+ _maxFlingVelocity = vc.scaledMaximumFlingVelocity
+ //_touchSlop = vc.scaledTouchSlop
+
+ if (drawIndicator) {
+ //直接初始化的变量, 不会触发set方法.
+ tabIndicator.initAttribute(context, attributeSet)
+ }
+
+ if (drawBorder) {
+ tabBorder = DslTabBorder()
+ }
+ if (drawDivider) {
+ tabDivider = DslTabDivider()
+ }
+ if (drawBadge) {
+ tabBadge = DslTabBadge()
+ }
+ if (drawHighlight) {
+ tabHighlight = DslTabHighlight(this)
+ }
+
+ //样式配置器
+ tabLayoutConfig = DslTabLayoutConfig(this)
+
+ //开启绘制
+ setWillNotDraw(false)
+ }
+
+ //
+
+ //
+
+ /**当前选中item的索引*/
+ val currentItemIndex: Int
+ get() = dslSelector.dslSelectIndex
+
+ /**当前选中的itemView*/
+ val currentItemView: View?
+ get() = dslSelector.visibleViewList.getOrNull(currentItemIndex)
+
+ /**设置tab的位置*/
+ fun setCurrentItem(index: Int, notify: Boolean = true, fromUser: Boolean = false) {
+ if (currentItemIndex == index) {
+ _scrollToTarget(index, tabIndicator.indicatorAnim)
+ return
+ }
+ dslSelector.selector(index, true, notify, fromUser)
+ }
+
+ /**关联[ViewPagerDelegate]*/
+ fun setupViewPager(viewPagerDelegate: ViewPagerDelegate) {
+ _viewPagerDelegate = viewPagerDelegate
+ }
+
+ /**配置一个新的[DslTabLayoutConfig]给[DslTabLayout]*/
+ fun setTabLayoutConfig(
+ config: DslTabLayoutConfig = DslTabLayoutConfig(this),
+ doIt: DslTabLayoutConfig.() -> Unit = {}
+ ) {
+ tabLayoutConfig = config
+ configTabLayoutConfig(doIt)
+ }
+
+ /**配置[DslTabLayoutConfig]*/
+ fun configTabLayoutConfig(config: DslTabLayoutConfig.() -> Unit = {}) {
+ if (tabLayoutConfig == null) {
+ tabLayoutConfig = DslTabLayoutConfig(this)
+ }
+ tabLayoutConfig?.config()
+ dslSelector.updateStyle()
+ }
+
+ /**观察index的改变回调*/
+ fun observeIndexChange(
+ config: DslTabLayoutConfig.() -> Unit = {},
+ action: (fromIndex: Int, toIndex: Int, reselect: Boolean, fromUser: Boolean) -> Unit
+ ) {
+ configTabLayoutConfig {
+ config()
+ onSelectIndexChange = { fromIndex, selectIndexList, reselect, fromUser ->
+ action(fromIndex, selectIndexList.firstOrNull() ?: -1, reselect, fromUser)
+ }
+ }
+ }
+
+ fun getBadgeConfig(index: Int): TabBadgeConfig {
+ return tabBadgeConfigMap.getOrElse(index) {
+ tabBadge?.defaultBadgeConfig?.copy() ?: TabBadgeConfig()
+ }
+ }
+
+ fun updateTabBadge(index: Int, badgeText: String?) {
+ updateTabBadge(index) {
+ this.badgeText = badgeText
+ }
+ }
+
+ /**更新角标*/
+ fun updateTabBadge(index: Int, config: TabBadgeConfig.() -> Unit) {
+ val badgeConfig = getBadgeConfig(index)
+ tabBadgeConfigMap[index] = badgeConfig
+ badgeConfig.config()
+ postInvalidate()
+ }
+
+ //
+
+ //
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ }
+
+ override fun onViewAdded(child: View?) {
+ super.onViewAdded(child)
+ updateTabLayout()
+ }
+
+ override fun onViewRemoved(child: View?) {
+ super.onViewRemoved(child)
+ updateTabLayout()
+ }
+
+ open fun updateTabLayout() {
+ dslSelector.updateVisibleList()
+ dslSelector.updateStyle()
+ dslSelector.updateClickListener()
+ }
+
+ override fun draw(canvas: Canvas) {
+ //Log.e("angcyo", "...draw...")
+
+ if (drawIndicator) {
+ tabIndicator.setBounds(0, 0, measuredWidth, measuredHeight)
+ }
+
+ //自定义的背景
+ tabConvexBackgroundDrawable?.apply {
+ if (isHorizontal()) {
+ setBounds(0, _maxConvexHeight, right - left, bottom - top)
+ } else {
+ setBounds(0, 0, measuredWidth - _maxConvexHeight, bottom - top)
+ }
+
+ if (scrollX or scrollY == 0) {
+ draw(canvas)
+ } else {
+ canvas.holdLocation {
+ draw(canvas)
+ }
+ }
+ }
+
+ super.draw(canvas)
+
+ //突出显示
+ if (drawHighlight) {
+ tabHighlight?.draw(canvas)
+ }
+
+ val visibleChildCount = dslSelector.visibleViewList.size
+
+ //绘制在child的上面
+ if (drawDivider) {
+ if (isHorizontal()) {
+ if (isLayoutRtl) {
+ var right = 0
+ tabDivider?.apply {
+ val top = paddingTop + dividerMarginTop
+ val bottom = measuredHeight - paddingBottom - dividerMarginBottom
+ dslSelector.visibleViewList.forEachIndexed { index, view ->
+
+ if (haveBeforeDivider(index, visibleChildCount)) {
+ right = view.right + dividerMarginLeft + dividerWidth
+ setBounds(right - dividerWidth, top, right, bottom)
+ draw(canvas)
+ }
+
+ if (haveAfterDivider(index, visibleChildCount)) {
+ right = view.right - view.measuredWidth - dividerMarginRight
+ setBounds(right - dividerWidth, top, right, bottom)
+ draw(canvas)
+ }
+
+ }
+ }
+ } else {
+ var left = 0
+ tabDivider?.apply {
+ val top = paddingTop + dividerMarginTop
+ val bottom = measuredHeight - paddingBottom - dividerMarginBottom
+ dslSelector.visibleViewList.forEachIndexed { index, view ->
+
+ if (haveBeforeDivider(index, visibleChildCount)) {
+ left = view.left - dividerMarginRight - dividerWidth
+ setBounds(left, top, left + dividerWidth, bottom)
+ draw(canvas)
+ }
+
+ if (haveAfterDivider(index, visibleChildCount)) {
+ left = view.right + dividerMarginLeft
+ setBounds(left, top, left + dividerWidth, bottom)
+ draw(canvas)
+ }
+
+ }
+ }
+ }
+ } else {
+ var top = 0
+ tabDivider?.apply {
+ val left = paddingStart + dividerMarginLeft
+ val right = measuredWidth - paddingEnd - dividerMarginRight
+ dslSelector.visibleViewList.forEachIndexed { index, view ->
+
+ if (haveBeforeDivider(index, visibleChildCount)) {
+ top = view.top - dividerMarginBottom - dividerHeight
+ setBounds(left, top, right, top + dividerHeight)
+ draw(canvas)
+ }
+
+ if (haveAfterDivider(index, visibleChildCount)) {
+ top = view.bottom + dividerMarginTop
+ setBounds(left, top, right, top + dividerHeight)
+ draw(canvas)
+ }
+ }
+ }
+ }
+ }
+ if (drawBorder) {
+ //边框不跟随滚动
+ canvas.holdLocation {
+ tabBorder?.draw(canvas)
+ }
+ }
+ if (drawIndicator && tabIndicator.indicatorStyle.have(DslTabIndicator.INDICATOR_STYLE_FOREGROUND)) {
+ //前景显示
+ tabIndicator.draw(canvas)
+ }
+ if (drawBadge) {
+ tabBadge?.apply {
+ dslSelector.visibleViewList.forEachIndexed { index, child ->
+ val badgeConfig = onTabBadgeConfig(child, this, index)
+
+ var left: Int
+ var top: Int
+ var right: Int
+ var bottom: Int
+
+ var anchorView: View = child
+
+ if (badgeConfig != null && badgeConfig.badgeAnchorChildIndex >= 0) {
+ anchorView =
+ child.getChildOrNull(badgeConfig.badgeAnchorChildIndex) ?: child
+
+ anchorView.getLocationInParent(this@DslTabLayout, _tempRect)
+
+ left = _tempRect.left
+ top = _tempRect.top
+ right = _tempRect.right
+ bottom = _tempRect.bottom
+ } else {
+ left = anchorView.left
+ top = anchorView.top
+ right = anchorView.right
+ bottom = anchorView.bottom
+ }
+
+ if (badgeConfig != null && badgeConfig.badgeIgnoreChildPadding) {
+ left += anchorView.paddingStart
+ top += anchorView.paddingTop
+ right -= anchorView.paddingEnd
+ bottom -= anchorView.paddingBottom
+ }
+
+ setBounds(left, top, right, bottom)
+
+ updateOriginDrawable()
+
+ if (isInEditMode) {
+ badgeText = if (index == visibleChildCount - 1) {
+ //预览中, 强制最后一个角标为圆点类型, 方便查看预览.
+ ""
+ } else {
+ xmlBadgeText
+ }
+ }
+
+ draw(canvas)
+ }
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ if (drawBorder) {
+ //边框不跟随滚动
+ canvas.holdLocation {
+ tabBorder?.drawBorderBackground(canvas)
+ }
+ }
+
+ //绘制在child的后面
+ if (drawIndicator && !tabIndicator.indicatorStyle.have(DslTabIndicator.INDICATOR_STYLE_FOREGROUND)) {
+ //背景绘制
+ tabIndicator.draw(canvas)
+ }
+ }
+
+ /**保持位置不变*/
+ fun Canvas.holdLocation(action: () -> Unit) {
+ translate(scrollX.toFloat(), scrollY.toFloat())
+ action()
+ translate(-scrollX.toFloat(), -scrollY.toFloat())
+ }
+
+ override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean {
+ return super.drawChild(canvas, child, drawingTime)
+ }
+
+ override fun verifyDrawable(who: Drawable): Boolean {
+ return super.verifyDrawable(who) ||
+ who == tabIndicator /*||
+ who == tabBorder ||
+ who == tabDivider ||
+ who == tabConvexBackgroundDrawable*/ /*||
+ who == tabBadge 防止循环绘制*/
+ }
+
+ //
+
+ //
+
+ //所有child的总宽度, 不包含parent的padding
+ var _childAllWidthSum = 0
+
+ //最大的凸起高度
+ var _maxConvexHeight = 0
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+
+ if (dslSelector.dslSelectIndex < 0) {
+ //还没有选中
+ setCurrentItem(tabDefaultIndex)
+ }
+
+ if (isHorizontal()) {
+ measureHorizontal(widthMeasureSpec, heightMeasureSpec)
+ } else {
+ measureVertical(widthMeasureSpec, heightMeasureSpec)
+ }
+ }
+
+ fun measureHorizontal(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ dslSelector.updateVisibleList()
+
+ val visibleChildList = dslSelector.visibleViewList
+ val visibleChildCount = visibleChildList.size
+
+ //控制最小大小
+ val tabMinHeight = if (suggestedMinimumHeight > 0) {
+ suggestedMinimumHeight
+ } else {
+ itemDefaultHeight
+ }
+
+ if (visibleChildCount == 0) {
+ setMeasuredDimension(
+ getDefaultSize(suggestedMinimumWidth, widthMeasureSpec),
+ getDefaultSize(tabMinHeight, heightMeasureSpec)
+ )
+ return
+ }
+
+ //super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ var widthSize = MeasureSpec.getSize(widthMeasureSpec)
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+ var heightSize = MeasureSpec.getSize(heightMeasureSpec)
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+
+ _maxConvexHeight = 0
+
+ var childWidthSpec: Int = -1
+
+ //记录child最大的height, 用来实现tabLayout wrap_content, 包括突出的大小
+ var childMaxHeight = tabMinHeight //child最大的高度
+
+ if (heightMode == MeasureSpec.UNSPECIFIED) {
+ if (heightSize == 0) {
+ heightSize = Int.MAX_VALUE
+ }
+ }
+
+ if (widthMode == MeasureSpec.UNSPECIFIED) {
+ if (widthSize == 0) {
+ widthSize = Int.MAX_VALUE
+ }
+ }
+
+ //分割线需要排除的宽度
+ val dividerWidthExclude =
+ if (drawDivider) tabDivider?.run { dividerWidth + dividerMarginLeft + dividerMarginRight }
+ ?: 0 else 0
+
+ //智能等宽判断
+ if (itemAutoEquWidth) {
+ var childMaxWidth = 0 //所有child宽度总和
+ visibleChildList.forEachIndexed { index, child ->
+ val lp: LayoutParams = child.layoutParams as LayoutParams
+ measureChild(child, widthMeasureSpec, heightMeasureSpec)
+ childMaxWidth += lp.marginStart + lp.marginEnd + child.measuredWidth
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+ childMaxWidth += dividerWidthExclude
+ }
+ if (tabDivider?.haveAfterDivider(index, visibleChildList.size) == true) {
+ childMaxWidth += dividerWidthExclude
+ }
+ }
+ }
+
+ itemIsEquWidth = childMaxWidth <= widthSize
+ }
+
+ itemEquWidthCountRange?.let {
+ itemIsEquWidth = it.contains(visibleChildCount)
+ }
+
+ //等宽时, child宽度的测量模式
+ val childEquWidthSpec = if (itemIsEquWidth) {
+ exactlyMeasure(
+ if (itemWidth > 0) {
+ itemWidth
+ } else {
+ var excludeWidth = paddingStart + paddingEnd
+ visibleChildList.forEachIndexed { index, child ->
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(
+ index,
+ visibleChildList.size
+ ) == true
+ ) {
+ excludeWidth += dividerWidthExclude
+ }
+ if (tabDivider?.haveAfterDivider(
+ index,
+ visibleChildList.size
+ ) == true
+ ) {
+ excludeWidth += dividerWidthExclude
+ }
+ }
+ val lp = child.layoutParams as LayoutParams
+ excludeWidth += lp.marginStart + lp.marginEnd
+ }
+ (widthSize - excludeWidth) / visibleChildCount
+ }
+ )
+ } else {
+ -1
+ }
+
+ //...end
+
+ _childAllWidthSum = 0
+
+ //没有设置weight属性的child宽度总和, 用于计算剩余空间
+ var allChildUsedWidth = 0
+
+ fun measureChild(childView: View, heightSpec: Int? = null) {
+ val lp = childView.layoutParams as LayoutParams
+
+ //child高度测量模式
+ var childHeightSpec: Int = -1
+
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ if (heightMode == MeasureSpec.EXACTLY) {
+ //固定高度
+ childHeightSpec =
+ exactlyMeasure(heightSize - paddingTop - paddingBottom - lp.topMargin - lp.bottomMargin)
+ } else {
+ if (widthHeight[1] > 0) {
+ heightSize = widthHeight[1]
+ childHeightSpec = exactlyMeasure(heightSize)
+ heightSize += paddingTop + paddingBottom
+ } else {
+ childHeightSpec = if (lp.height == ViewGroup.LayoutParams.MATCH_PARENT) {
+ exactlyMeasure(tabMinHeight)
+ } else {
+ atmostMeasure(Int.MAX_VALUE)
+ }
+ }
+ }
+
+ val childConvexHeight = lp.layoutConvexHeight
+
+ //...end
+
+ //计算宽度测量模式
+ childWidthSpec //no op
+
+ if (heightSpec != null) {
+ childView.measure(childWidthSpec, heightSpec)
+ } else {
+ childView.measure(childWidthSpec, childHeightSpec)
+ }
+ if (childConvexHeight > 0) {
+ _maxConvexHeight = max(_maxConvexHeight, childConvexHeight)
+ //需要凸起
+ val spec = exactlyMeasure(childView.measuredHeight + childConvexHeight)
+ childView.measure(childWidthSpec, spec)
+ }
+ childMaxHeight = max(childMaxHeight, childView.measuredHeight)
+ }
+
+ visibleChildList.forEachIndexed { index, childView ->
+ val lp = childView.layoutParams as LayoutParams
+ var childUsedWidth = 0
+ if (lp.weight < 0) {
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ //计算宽度测量模式
+ childWidthSpec = when {
+ itemIsEquWidth -> childEquWidthSpec
+ widthHeight[0] > 0 -> exactlyMeasure(widthHeight[0])
+ lp.width == ViewGroup.LayoutParams.MATCH_PARENT -> exactlyMeasure(widthSize - paddingStart - paddingEnd)
+ lp.width > 0 -> exactlyMeasure(lp.width)
+ else -> atmostMeasure(widthSize - paddingStart - paddingEnd)
+ }
+
+ measureChild(childView)
+
+ childUsedWidth = childView.measuredWidth + lp.marginStart + lp.marginEnd
+ } else {
+ childUsedWidth = lp.marginStart + lp.marginEnd
+ }
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+ childUsedWidth += dividerWidthExclude
+ }
+ if (tabDivider?.haveAfterDivider(index, visibleChildList.size) == true) {
+ childUsedWidth += dividerWidthExclude
+ }
+ }
+
+ childMaxHeight = max(childMaxHeight, childView.measuredHeight)
+ allChildUsedWidth += childUsedWidth
+ _childAllWidthSum += childUsedWidth
+ }
+
+ //剩余空间
+ val spaceSize = widthSize - allChildUsedWidth
+
+ //计算weight
+ visibleChildList.forEach { childView ->
+ val lp = childView.layoutParams as LayoutParams
+ if (lp.weight > 0) {
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ //计算宽度测量模式
+ childWidthSpec = when {
+ itemIsEquWidth -> childEquWidthSpec
+ spaceSize > 0 -> exactlyMeasure(spaceSize * lp.weight)
+ widthHeight[0] > 0 -> exactlyMeasure(allChildUsedWidth)
+ lp.width == ViewGroup.LayoutParams.MATCH_PARENT -> exactlyMeasure(widthSize - paddingStart - paddingEnd)
+ lp.width > 0 -> exactlyMeasure(lp.width)
+ else -> atmostMeasure(widthSize - paddingStart - paddingEnd)
+ }
+
+ measureChild(childView)
+
+ childMaxHeight = max(childMaxHeight, childView.measuredHeight)
+
+ //上面已经处理了分割线和margin的距离了
+ _childAllWidthSum += childView.measuredWidth
+ }
+ }
+ //...end
+
+ if (heightMode == MeasureSpec.AT_MOST) {
+ //wrap_content 情况下, 重新测量所有子view
+ val childHeightSpec = exactlyMeasure(
+ max(
+ childMaxHeight - _maxConvexHeight,
+ suggestedMinimumHeight - paddingTop - paddingBottom
+ )
+ )
+ visibleChildList.forEach { childView ->
+ measureChild(childView, childHeightSpec)
+ }
+ }
+
+ if (widthMode != MeasureSpec.EXACTLY) {
+ widthSize = min(_childAllWidthSum + paddingStart + paddingEnd, widthSize)
+ }
+
+ if (visibleChildList.isEmpty()) {
+ heightSize = if (suggestedMinimumHeight > 0) {
+ suggestedMinimumHeight
+ } else {
+ itemDefaultHeight
+ }
+ } else if (heightMode != MeasureSpec.EXACTLY) {
+ heightSize = max(
+ childMaxHeight - _maxConvexHeight + paddingTop + paddingBottom,
+ suggestedMinimumHeight
+ )
+ }
+
+ setMeasuredDimension(widthSize, heightSize + _maxConvexHeight)
+ }
+
+ fun measureVertical(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ dslSelector.updateVisibleList()
+
+ val visibleChildList = dslSelector.visibleViewList
+ val visibleChildCount = visibleChildList.size
+
+ if (visibleChildCount == 0) {
+ setMeasuredDimension(
+ getDefaultSize(
+ if (suggestedMinimumHeight > 0) {
+ suggestedMinimumHeight
+ } else {
+ itemDefaultHeight
+ }, widthMeasureSpec
+ ),
+ getDefaultSize(suggestedMinimumHeight, heightMeasureSpec)
+ )
+ return
+ }
+
+ //super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ var widthSize = MeasureSpec.getSize(widthMeasureSpec)
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+ var heightSize = MeasureSpec.getSize(heightMeasureSpec)
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+
+ _maxConvexHeight = 0
+
+ //child高度测量模式
+ var childHeightSpec: Int = -1
+ var childWidthSpec: Int = -1
+
+ if (heightMode == MeasureSpec.UNSPECIFIED) {
+ if (heightSize == 0) {
+ heightSize = Int.MAX_VALUE
+ }
+ }
+
+ if (widthMode == MeasureSpec.EXACTLY) {
+ //固定宽度
+ childWidthSpec = exactlyMeasure(widthSize - paddingStart - paddingEnd)
+ } else if (widthMode == MeasureSpec.UNSPECIFIED) {
+ if (widthSize == 0) {
+ widthSize = Int.MAX_VALUE
+ }
+ }
+
+ //分割线需要排除的宽度
+ val dividerHeightExclude =
+ if (drawDivider) tabDivider?.run { dividerHeight + dividerMarginTop + dividerMarginBottom }
+ ?: 0 else 0
+
+ //智能等宽判断
+ if (itemAutoEquWidth) {
+ var childMaxHeight = 0 //所有child高度总和
+ visibleChildList.forEachIndexed { index, child ->
+ val lp: LayoutParams = child.layoutParams as LayoutParams
+ measureChild(child, widthMeasureSpec, heightMeasureSpec)
+ childMaxHeight += lp.topMargin + lp.bottomMargin + child.measuredHeight
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+ childMaxHeight += dividerHeightExclude
+ }
+ if (tabDivider?.haveAfterDivider(index, visibleChildList.size) == true) {
+ childMaxHeight += dividerHeightExclude
+ }
+ }
+ }
+
+ itemIsEquWidth = childMaxHeight <= heightSize
+ }
+
+ itemEquWidthCountRange?.let {
+ itemIsEquWidth = it.contains(visibleChildCount)
+ }
+
+ //等宽时, child高度的测量模式
+ val childEquHeightSpec = if (itemIsEquWidth) {
+ exactlyMeasure(
+ if (itemWidth > 0) {
+ itemWidth
+ } else {
+ var excludeHeight = paddingTop + paddingBottom
+ visibleChildList.forEachIndexed { index, child ->
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true
+ ) {
+ excludeHeight += dividerHeightExclude
+ }
+ if (tabDivider?.haveAfterDivider(index, visibleChildList.size) == true
+ ) {
+ excludeHeight += dividerHeightExclude
+ }
+ }
+ val lp = child.layoutParams as LayoutParams
+ excludeHeight += lp.topMargin + lp.bottomMargin
+ }
+ (heightSize - excludeHeight) / visibleChildCount
+ }
+ )
+ } else {
+ -1
+ }
+
+ //...end
+
+ _childAllWidthSum = 0
+
+ var wrapContentWidth = false
+
+ //没有设置weight属性的child宽度总和, 用于计算剩余空间
+ var allChildUsedHeight = 0
+
+ fun measureChild(childView: View) {
+ val lp = childView.layoutParams as LayoutParams
+
+ //纵向布局, 不支持横向margin支持
+ lp.marginStart = 0
+ lp.marginEnd = 0
+
+ val childConvexHeight = lp.layoutConvexHeight
+ _maxConvexHeight = max(_maxConvexHeight, childConvexHeight)
+
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ //计算宽度测量模式
+ wrapContentWidth = false
+ if (childWidthSpec == -1) {
+ if (widthHeight[0] > 0) {
+ widthSize = widthHeight[0]
+ childWidthSpec = exactlyMeasure(widthSize)
+ widthSize += paddingStart + paddingEnd
+ }
+ }
+
+ if (childWidthSpec == -1) {
+ if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
+
+ widthSize = if (suggestedMinimumWidth > 0) {
+ suggestedMinimumWidth
+ } else {
+ itemDefaultHeight
+ }
+
+ childWidthSpec = exactlyMeasure(widthSize)
+
+ widthSize += paddingStart + paddingEnd
+ } else {
+ childWidthSpec = atmostMeasure(widthSize)
+ wrapContentWidth = true
+ }
+ }
+ //...end
+
+ //计算高度测量模式
+ childHeightSpec //no op
+
+ if (childConvexHeight > 0) {
+ //需要凸起
+ val childConvexWidthSpec = MeasureSpec.makeMeasureSpec(
+ MeasureSpec.getSize(childWidthSpec) + childConvexHeight,
+ MeasureSpec.getMode(childWidthSpec)
+ )
+ childView.measure(childConvexWidthSpec, childHeightSpec)
+ } else {
+ childView.measure(childWidthSpec, childHeightSpec)
+ }
+
+ if (wrapContentWidth) {
+ widthSize = childView.measuredWidth
+ childWidthSpec = exactlyMeasure(widthSize)
+ widthSize += paddingStart + paddingEnd
+ }
+ }
+
+ visibleChildList.forEachIndexed { index, childView ->
+ val lp = childView.layoutParams as LayoutParams
+ var childUsedHeight = 0
+ if (lp.weight < 0) {
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ //计算高度测量模式
+ childHeightSpec = when {
+ itemIsEquWidth -> childEquHeightSpec
+ widthHeight[1] > 0 -> exactlyMeasure(widthHeight[1])
+ lp.height == ViewGroup.LayoutParams.MATCH_PARENT -> exactlyMeasure(heightSize - paddingTop - paddingBottom)
+ lp.height > 0 -> exactlyMeasure(lp.height)
+ else -> atmostMeasure(heightSize - paddingTop - paddingBottom)
+ }
+
+ measureChild(childView)
+
+ childUsedHeight = childView.measuredHeight + lp.topMargin + lp.bottomMargin
+ } else {
+ childUsedHeight = lp.topMargin + lp.bottomMargin
+ }
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+ childUsedHeight += dividerHeightExclude
+ }
+ if (tabDivider?.haveAfterDivider(index, visibleChildList.size) == true) {
+ childUsedHeight += dividerHeightExclude
+ }
+ }
+
+ allChildUsedHeight += childUsedHeight
+ _childAllWidthSum += childUsedHeight
+ }
+
+ //剩余空间
+ val spaceSize = heightSize - allChildUsedHeight
+
+ //计算weight
+ visibleChildList.forEach { childView ->
+ val lp = childView.layoutParams as LayoutParams
+ if (lp.weight > 0) {
+ val widthHeight = calcLayoutWidthHeight(
+ lp.layoutWidth, lp.layoutHeight,
+ widthSize, heightSize, 0, 0
+ )
+
+ //计算高度测量模式
+ childHeightSpec = when {
+ itemIsEquWidth -> childEquHeightSpec
+ spaceSize > 0 -> exactlyMeasure(spaceSize * lp.weight)
+ widthHeight[1] > 0 -> exactlyMeasure(allChildUsedHeight)
+ lp.height == ViewGroup.LayoutParams.MATCH_PARENT -> exactlyMeasure(heightSize - paddingTop - paddingBottom)
+ lp.height > 0 -> exactlyMeasure(lp.height)
+ else -> atmostMeasure(heightSize - paddingTop - paddingBottom)
+ }
+
+ measureChild(childView)
+
+ //上面已经处理了分割线和margin的距离了
+ _childAllWidthSum += childView.measuredHeight
+ }
+ }
+ //...end
+
+ if (heightMode != MeasureSpec.EXACTLY) {
+ heightSize = min(_childAllWidthSum + paddingTop + paddingBottom, heightSize)
+ }
+
+ if (visibleChildList.isEmpty()) {
+ widthSize = if (suggestedMinimumWidth > 0) {
+ suggestedMinimumWidth
+ } else {
+ itemDefaultHeight
+ }
+ }
+
+ setMeasuredDimension(widthSize + _maxConvexHeight, heightSize)
+ }
+
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ if (isHorizontal()) {
+ layoutHorizontal(changed, l, t, r, b)
+ } else {
+ layoutVertical(changed, l, t, r, b)
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+
+ //check
+ restoreScroll()
+
+ if (dslSelector.dslSelectIndex < 0) {
+ //还没有选中
+ setCurrentItem(tabDefaultIndex)
+ } else {
+ if (_overScroller.isFinished) {
+ _scrollToTarget(dslSelector.dslSelectIndex, layoutScrollAnim)
+ }
+ }
+ }
+
+ val isLayoutRtl: Boolean
+ get() = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL
+
+ var _layoutDirection: Int = -1
+
+ //API 17
+ override fun onRtlPropertiesChanged(layoutDirection: Int) {
+ super.onRtlPropertiesChanged(layoutDirection)
+
+ if (layoutDirection != _layoutDirection) {
+ _layoutDirection = layoutDirection
+ if (orientation == LinearLayout.HORIZONTAL) {
+ updateTabLayout() //更新样式
+ requestLayout() //重新布局
+ }
+ }
+ }
+
+ fun layoutHorizontal(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ val isRtl = isLayoutRtl
+
+ var left = paddingStart
+ var right = measuredWidth - paddingEnd
+
+ var childBottom = measuredHeight - paddingBottom
+
+ val dividerExclude = if (drawDivider) tabDivider?.run {
+ dividerWidth + dividerMarginLeft + dividerMarginRight
+ } ?: 0 else 0
+
+ val visibleChildList = dslSelector.visibleViewList
+ visibleChildList.forEachIndexed { index, childView ->
+
+ val lp = childView.layoutParams as LayoutParams
+ val verticalGravity = lp.gravity and Gravity.VERTICAL_GRAVITY_MASK
+
+ if (isRtl) {
+ right -= lp.marginEnd
+ } else {
+ left += lp.marginStart
+ }
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+
+ if (isRtl) {
+ right -= dividerExclude
+ } else {
+ left += dividerExclude
+ }
+ }
+ }
+
+ childBottom = when (verticalGravity) {
+ Gravity.CENTER_VERTICAL -> measuredHeight - paddingBottom -
+ ((measuredHeight - paddingTop - paddingBottom - _maxConvexHeight) / 2 -
+ childView.measuredHeight / 2)
+
+ Gravity.BOTTOM -> measuredHeight - paddingBottom
+ else -> paddingTop + lp.topMargin + childView.measuredHeight
+ }
+
+ if (isRtl) {
+ childView.layout(
+ right - childView.measuredWidth,
+ childBottom - childView.measuredHeight,
+ right,
+ childBottom
+ )
+ right -= childView.measuredWidth + lp.marginStart
+ } else {
+ childView.layout(
+ left,
+ childBottom - childView.measuredHeight,
+ left + childView.measuredWidth,
+ childBottom
+ )
+ left += childView.measuredWidth + lp.marginEnd
+ }
+ }
+
+ //check
+ restoreScroll()
+
+ if (dslSelector.dslSelectIndex < 0) {
+ //还没有选中
+ setCurrentItem(tabDefaultIndex)
+ } else {
+ if (_overScroller.isFinished) {
+ _scrollToTarget(dslSelector.dslSelectIndex, layoutScrollAnim)
+ }
+ }
+ }
+
+ fun layoutVertical(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ var top = paddingTop
+ var childLeft = paddingStart
+
+ val dividerExclude =
+ if (drawDivider) tabDivider?.run { dividerHeight + dividerMarginTop + dividerMarginBottom }
+ ?: 0 else 0
+
+ val visibleChildList = dslSelector.visibleViewList
+ visibleChildList.forEachIndexed { index, childView ->
+
+ val lp = childView.layoutParams as LayoutParams
+ val layoutDirection = 0
+ val absoluteGravity = GravityCompat.getAbsoluteGravity(lp.gravity, layoutDirection)
+ val horizontalGravity = absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+
+ top += lp.topMargin
+
+ if (drawDivider) {
+ if (tabDivider?.haveBeforeDivider(index, visibleChildList.size) == true) {
+ top += dividerExclude
+ }
+ }
+
+ childLeft = when (horizontalGravity) {
+ Gravity.CENTER_HORIZONTAL -> paddingStart + ((measuredWidth - paddingStart - paddingEnd - _maxConvexHeight) / 2 -
+ childView.measuredWidth / 2)
+
+ Gravity.RIGHT -> measuredWidth - paddingRight - childView.measuredWidth - lp.rightMargin
+ else -> paddingLeft + lp.leftMargin
+ }
+
+ /*默认水平居中显示*/
+ childView.layout(
+ childLeft,
+ top,
+ childLeft + childView.measuredWidth,
+ top + childView.measuredHeight
+ )
+
+ top += childView.measuredHeight + lp.bottomMargin
+ }
+ }
+
+ /**是否是横向布局*/
+ fun isHorizontal() = orientation.isHorizontal()
+
+ //
+
+ //
+
+ override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams {
+ return LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER
+ )
+ }
+
+ override fun generateLayoutParams(attrs: AttributeSet?): ViewGroup.LayoutParams {
+ return LayoutParams(context, attrs)
+ }
+
+ override fun generateLayoutParams(p: ViewGroup.LayoutParams?): ViewGroup.LayoutParams {
+ return p?.run { LayoutParams(p) } ?: generateDefaultLayoutParams()
+ }
+
+ class LayoutParams : FrameLayout.LayoutParams {
+
+ /**
+ * 支持格式0.3pw 0.5ph, 表示[parent]的多少倍数
+ * */
+ var layoutWidth: String? = null
+ var layoutHeight: String? = null
+
+ /**凸出的高度*/
+ var layoutConvexHeight: Int = 0
+
+ /**
+ * 宽高[WRAP_CONTENT]时, 内容view的定位索引
+ * [TabIndicator.indicatorContentIndex]
+ * */
+ var indicatorContentIndex = -1
+ var indicatorContentId = View.NO_ID
+
+ /**[com.angcyo.tablayout.DslTabLayoutConfig.getOnGetTextStyleView]*/
+ var contentTextViewIndex = -1
+
+ /**[com.angcyo.tablayout.DslTabLayoutConfig.getTabTextViewId]*/
+ var contentTextViewId = View.NO_ID
+
+ /**[com.angcyo.tablayout.DslTabLayoutConfig.getOnGetIcoStyleView]*/
+ var contentIconViewIndex = -1
+
+ /**[com.angcyo.tablayout.DslTabLayoutConfig.getTabIconViewId]*/
+ var contentIconViewId = View.NO_ID
+
+ /**
+ * 剩余空间占比, 1f表示占满剩余空间, 0.5f表示使用剩余空间的0.5倍
+ * [android.widget.LinearLayout.LayoutParams.weight]*/
+ var weight: Float = -1f
+
+ /**突出需要绘制的Drawable
+ * [com.angcyo.tablayout.DslTabHighlight.highlightDrawable]*/
+ var highlightDrawable: Drawable? = null
+
+ constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {
+ val a = c.obtainStyledAttributes(attrs, R.styleable.DslTabLayout_Layout)
+ layoutWidth = a.getString(R.styleable.DslTabLayout_Layout_layout_tab_width)
+ layoutHeight = a.getString(R.styleable.DslTabLayout_Layout_layout_tab_height)
+ layoutConvexHeight =
+ a.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_Layout_layout_tab_convex_height,
+ layoutConvexHeight
+ )
+ indicatorContentIndex = a.getInt(
+ R.styleable.DslTabLayout_Layout_layout_tab_indicator_content_index,
+ indicatorContentIndex
+ )
+ indicatorContentId = a.getResourceId(
+ R.styleable.DslTabLayout_Layout_layout_tab_indicator_content_id,
+ indicatorContentId
+ )
+ weight = a.getFloat(R.styleable.DslTabLayout_Layout_layout_tab_weight, weight)
+ highlightDrawable =
+ a.getDrawable(R.styleable.DslTabLayout_Layout_layout_highlight_drawable)
+
+ contentTextViewIndex = a.getInt(
+ R.styleable.DslTabLayout_Layout_layout_tab_text_view_index,
+ contentTextViewIndex
+ )
+ contentIconViewIndex = a.getInt(
+ R.styleable.DslTabLayout_Layout_layout_tab_text_view_index,
+ contentIconViewIndex
+ )
+ contentTextViewId = a.getResourceId(
+ R.styleable.DslTabLayout_Layout_layout_tab_text_view_id,
+ contentTextViewId
+ )
+ contentIconViewId = a.getResourceId(
+ R.styleable.DslTabLayout_Layout_layout_tab_icon_view_id,
+ contentIconViewIndex
+ )
+
+ a.recycle()
+
+ if (gravity == UNSPECIFIED_GRAVITY) {
+ gravity = if (layoutConvexHeight > 0) {
+ Gravity.BOTTOM
+ } else {
+ Gravity.CENTER
+ }
+ }
+ }
+
+ constructor(source: ViewGroup.LayoutParams) : super(source) {
+ if (source is LayoutParams) {
+ this.layoutWidth = source.layoutWidth
+ this.layoutHeight = source.layoutHeight
+ this.layoutConvexHeight = source.layoutConvexHeight
+ this.weight = source.weight
+ this.highlightDrawable = source.highlightDrawable
+ }
+ }
+
+ constructor(width: Int, height: Int) : super(width, height)
+
+ constructor(width: Int, height: Int, gravity: Int) : super(width, height, gravity)
+ }
+
+ //
+
+ //
+
+ //滚动支持
+ val _overScroller: OverScroller by lazy {
+ OverScroller(context)
+ }
+
+ //手势检测
+ val _gestureDetector: GestureDetectorCompat by lazy {
+ GestureDetectorCompat(context, object : GestureDetector.SimpleOnGestureListener() {
+ override fun onFling(
+ e1: MotionEvent?,
+ e2: MotionEvent,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
+ if (isHorizontal()) {
+ val absX = abs(velocityX)
+ if (absX > _minFlingVelocity) {
+ onFlingChange(velocityX)
+ }
+ } else {
+ val absY = abs(velocityY)
+ if (absY > _minFlingVelocity) {
+ onFlingChange(velocityY)
+ }
+ }
+
+ return true
+ }
+
+ override fun onScroll(
+ e1: MotionEvent?,
+ e2: MotionEvent,
+ distanceX: Float,
+ distanceY: Float
+ ): Boolean {
+ var handle = false
+ if (isHorizontal()) {
+ val absX = abs(distanceX)
+ if (absX > _touchSlop) {
+ handle = onScrollChange(distanceX)
+ }
+ } else {
+ val absY = abs(distanceY)
+ if (absY > _touchSlop) {
+ handle = onScrollChange(distanceY)
+ }
+ }
+ return handle
+ }
+ })
+ }
+
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+ var intercept = false
+ if (needScroll) {
+ if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
+ _overScroller.abortAnimation()
+ _scrollAnimator.cancel()
+ }
+ if (isEnabled) {
+ intercept = super.onInterceptTouchEvent(ev) || _gestureDetector.onTouchEvent(ev)
+ }
+ } else {
+ if (isEnabled) {
+ intercept = super.onInterceptTouchEvent(ev)
+ }
+ }
+ return if (isEnabled) {
+ if (itemEnableSelector) {
+ intercept
+ } else {
+ true
+ }
+ } else {
+ false
+ }
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (isEnabled) {
+ if (needScroll) {
+ _gestureDetector.onTouchEvent(event)
+ if (event.actionMasked == MotionEvent.ACTION_CANCEL ||
+ event.actionMasked == MotionEvent.ACTION_UP
+ ) {
+ parent.requestDisallowInterceptTouchEvent(false)
+ } else if (event.actionMasked == MotionEvent.ACTION_DOWN) {
+ _overScroller.abortAnimation()
+ }
+ return true
+ } else {
+ return (isEnabled && super.onTouchEvent(event))
+ }
+ } else {
+ return false
+ }
+ }
+
+ /**是否需要滚动*/
+ val needScroll: Boolean
+ get() = if (tabEnableSelectorMode) true else {
+ if (isHorizontal()) {
+ if (isLayoutRtl) {
+ minScrollX < 0
+ } else {
+ maxScrollX > 0
+ }
+ } else {
+ maxScrollY > 0
+ }
+ }
+
+ /**[parent]宽度外的滚动距离*/
+ val maxScrollX: Int
+ get() = if (isLayoutRtl && isHorizontal()) {
+ if (tabEnableSelectorMode) viewDrawWidth / 2 else 0
+ } else {
+ max(
+ maxWidth - measuredWidth + if (tabEnableSelectorMode) viewDrawWidth / 2 else 0,
+ 0
+ )
+ }
+
+ val maxScrollY: Int
+ get() = max(
+ maxHeight - measuredHeight + if (tabEnableSelectorMode) viewDrawHeight / 2 else 0,
+ 0
+ )
+
+ /**最小滚动的值*/
+ val minScrollX: Int
+ get() = if (isLayoutRtl && isHorizontal()) {
+ min(
+ -(maxWidth - measuredWidth + if (tabEnableSelectorMode) viewDrawWidth / 2 else 0),
+ 0
+ )
+ } else {
+ if (tabEnableSelectorMode) -viewDrawWidth / 2 else 0
+ }
+
+ val minScrollY: Int
+ get() = if (tabEnableSelectorMode) -viewDrawHeight / 2 else 0
+
+ /**view最大的宽度*/
+ val maxWidth: Int
+ get() = _childAllWidthSum + paddingStart + paddingEnd
+
+ val maxHeight: Int
+ get() = _childAllWidthSum + paddingTop + paddingBottom
+
+ open fun onFlingChange(velocity: Float /*瞬时值*/) {
+ if (needScroll) {
+
+ //速率小于0 , 手指向左滑动
+ //速率大于0 , 手指向右滑动
+
+ if (tabEnableSelectorMode) {
+ if (isHorizontal() && isLayoutRtl) {
+ if (velocity < 0) {
+ setCurrentItem(dslSelector.dslSelectIndex - 1)
+ } else if (velocity > 0) {
+ setCurrentItem(dslSelector.dslSelectIndex + 1)
+ }
+ } else {
+ if (velocity < 0) {
+ setCurrentItem(dslSelector.dslSelectIndex + 1)
+ } else if (velocity > 0) {
+ setCurrentItem(dslSelector.dslSelectIndex - 1)
+ }
+ }
+ } else {
+ if (isHorizontal()) {
+ if (isLayoutRtl) {
+ startFling(-velocity.toInt(), minScrollX, 0)
+ } else {
+ startFling(-velocity.toInt(), 0, maxScrollX)
+ }
+ } else {
+ startFling(-velocity.toInt(), 0, maxHeight)
+ }
+ }
+ }
+ }
+
+ fun startFling(velocity: Int, min: Int, max: Int) {
+
+ fun velocity(velocity: Int): Int {
+ return if (velocity > 0) {
+ clamp(velocity, _minFlingVelocity, _maxFlingVelocity)
+ } else {
+ clamp(velocity, -_maxFlingVelocity, -_minFlingVelocity)
+ }
+ }
+
+ val v = velocity(velocity)
+
+ _overScroller.abortAnimation()
+
+ if (isHorizontal()) {
+ _overScroller.fling(
+ scrollX,
+ scrollY,
+ v,
+ 0,
+ min,
+ max,
+ 0,
+ 0,
+ measuredWidth,
+ 0
+ )
+ } else {
+ _overScroller.fling(
+ scrollX,
+ scrollY,
+ 0,
+ v,
+ 0,
+ 0,
+ min,
+ max,
+ 0,
+ measuredHeight
+ )
+ }
+ postInvalidate()
+ }
+
+ fun startScroll(dv: Int) {
+ _overScroller.abortAnimation()
+ if (isHorizontal()) {
+ _overScroller.startScroll(scrollX, scrollY, dv, 0, scrollAnimDuration)
+ } else {
+ _overScroller.startScroll(scrollX, scrollY, 0, dv, scrollAnimDuration)
+ }
+ ViewCompat.postInvalidateOnAnimation(this)
+ }
+
+ /**检查是否需要重置滚动的位置*/
+ fun restoreScroll() {
+ if (itemIsEquWidth || !needScroll) {
+ if (scrollX != 0 || scrollY != 0) {
+ scrollTo(0, 0)
+ }
+ }
+ }
+
+ open fun onScrollChange(distance: Float): Boolean {
+ if (needScroll) {
+
+ //distance小于0 , 手指向右滑动
+ //distance大于0 , 手指向左滑动
+
+ parent.requestDisallowInterceptTouchEvent(true)
+
+ if (tabEnableSelectorMode) {
+ //滑动选择模式下, 不响应scroll事件
+ } else {
+ if (isHorizontal()) {
+ scrollBy(distance.toInt(), 0)
+ } else {
+ scrollBy(0, distance.toInt())
+ }
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun scrollTo(x: Int, y: Int) {
+ if (isHorizontal()) {
+ when {
+ x > maxScrollX -> super.scrollTo(maxScrollX, 0)
+ x < minScrollX -> super.scrollTo(minScrollX, 0)
+ else -> super.scrollTo(x, 0)
+ }
+ } else {
+ when {
+ y > maxScrollY -> super.scrollTo(0, maxScrollY)
+ y < minScrollY -> super.scrollTo(0, minScrollY)
+ else -> super.scrollTo(0, y)
+ }
+ }
+ }
+
+ override fun computeScroll() {
+ if (_overScroller.computeScrollOffset()) {
+ scrollTo(_overScroller.currX, _overScroller.currY)
+ invalidate()
+ if (_overScroller.currX < minScrollX || _overScroller.currX > maxScrollX) {
+ _overScroller.abortAnimation()
+ }
+ }
+ }
+
+ fun _getViewTargetX(): Int {
+ return when (tabIndicator.indicatorGravity) {
+ DslTabIndicator.INDICATOR_GRAVITY_START -> paddingStart
+ DslTabIndicator.INDICATOR_GRAVITY_END -> measuredWidth - paddingEnd
+ else -> paddingStart + viewDrawWidth / 2
+ }
+ }
+
+ fun _getViewTargetY(): Int {
+ return when (tabIndicator.indicatorGravity) {
+ DslTabIndicator.INDICATOR_GRAVITY_START -> paddingTop
+ DslTabIndicator.INDICATOR_GRAVITY_END -> measuredHeight - paddingBottom
+ else -> paddingTop + viewDrawHeight / 2
+ }
+ }
+
+ /**将[index]位置显示在TabLayout的中心*/
+ fun _scrollToTarget(index: Int, scrollAnim: Boolean) {
+ if (!needScroll) {
+ return
+ }
+
+ dslSelector.visibleViewList.getOrNull(index)?.let {
+ if (!ViewCompat.isLaidOut(it)) {
+ //没有布局
+ return
+ }
+ }
+
+ val dv = if (isHorizontal()) {
+ val childTargetX = tabIndicator.getChildTargetX(index)
+ val viewDrawTargetX = _getViewTargetX()
+ when {
+ tabEnableSelectorMode -> {
+ val viewCenterX = measuredWidth / 2
+ childTargetX - viewCenterX - scrollX
+ }
+
+ isLayoutRtl -> {
+ if (childTargetX < viewDrawTargetX) {
+ childTargetX - viewDrawTargetX - scrollX
+ } else {
+ -scrollX
+ }
+ }
+
+ else -> {
+ if (childTargetX > viewDrawTargetX) {
+ childTargetX - viewDrawTargetX - scrollX
+ } else {
+ -scrollX
+ }
+ }
+ }
+ } else {
+ //竖向
+ val childTargetY = tabIndicator.getChildTargetY(index)
+ val viewDrawTargetY = _getViewTargetY()
+ when {
+ tabEnableSelectorMode -> {
+ val viewCenterY = measuredHeight / 2
+ childTargetY - viewCenterY - scrollY
+ }
+
+ childTargetY > viewDrawTargetY -> {
+ childTargetY - viewDrawTargetY - scrollY
+ }
+
+ else -> {
+ if (tabIndicator.indicatorGravity == DslTabIndicator.INDICATOR_GRAVITY_END &&
+ childTargetY < viewDrawTargetY
+ ) {
+ childTargetY - viewDrawTargetY - scrollY
+ } else {
+ -scrollY
+ }
+ }
+ }
+ }
+
+ if (isHorizontal()) {
+ if (isInEditMode || !scrollAnim) {
+ _overScroller.abortAnimation()
+ scrollBy(dv, 0)
+ } else {
+ startScroll(dv)
+ }
+ } else {
+ if (isInEditMode || !scrollAnim) {
+ _overScroller.abortAnimation()
+ scrollBy(0, dv)
+ } else {
+ startScroll(dv)
+ }
+ }
+ }
+
+ //
+
+ //
+
+ val _scrollAnimator: ValueAnimator by lazy {
+ ValueAnimator().apply {
+ interpolator = LinearInterpolator()
+ duration = tabIndicatorAnimationDuration
+ addUpdateListener {
+ _onAnimateValue(it.animatedValue as Float)
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationCancel(animation: Animator) {
+ _onAnimateValue(1f)
+ onAnimationEnd(animation)
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ _onAnimateEnd()
+ }
+ })
+ }
+ }
+
+ val isAnimatorStart: Boolean
+ get() = _scrollAnimator.isStarted
+
+ fun _animateToItem(fromIndex: Int, toIndex: Int) {
+ if (toIndex == fromIndex) {
+ return
+ }
+
+ //取消之前的动画
+ _scrollAnimator.cancel()
+
+ if (!tabIndicator.indicatorAnim) {
+ //不需要动画
+ _onAnimateEnd()
+ return
+ }
+
+ if (fromIndex < 0) {
+ //从一个不存在的位置, 到目标位置
+ tabIndicator.currentIndex = toIndex
+ } else {
+ tabIndicator.currentIndex = fromIndex
+ }
+ tabIndicator._targetIndex = toIndex
+
+ if (isInEditMode) {
+ tabIndicator.currentIndex = toIndex
+ return
+ }
+
+ if (tabIndicator.currentIndex == tabIndicator._targetIndex) {
+ return
+ }
+ //"_animateToItem ${tabIndicator.currentIndex} ${tabIndicator._targetIndex}".loge()
+ _scrollAnimator.setFloatValues(tabIndicator.positionOffset, 1f)
+ _scrollAnimator.start()
+ }
+
+ fun _onAnimateValue(value: Float) {
+ tabIndicator.positionOffset = value
+ tabLayoutConfig?.onPageIndexScrolled(
+ tabIndicator.currentIndex,
+ tabIndicator._targetIndex,
+ value
+ )
+ tabLayoutConfig?.let {
+ dslSelector.visibleViewList.apply {
+ val targetView = getOrNull(tabIndicator._targetIndex)
+ if (targetView != null) {
+ it.onPageViewScrolled(
+ getOrNull(tabIndicator.currentIndex),
+ targetView,
+ value
+ )
+ }
+ }
+ }
+ }
+
+ fun _onAnimateEnd() {
+ tabIndicator.currentIndex = dslSelector.dslSelectIndex
+ tabIndicator._targetIndex = tabIndicator.currentIndex
+ tabIndicator.positionOffset = 0f
+ //结束_viewPager的滚动动画, 系统没有直接结束的api, 固用此方法代替.
+ //_viewPager?.setCurrentItem(tabIndicator.currentIndex, false)
+ }
+
+ //
+
+ //
+
+ var _viewPagerDelegate: ViewPagerDelegate? = null
+ var _viewPagerScrollState = 0
+
+ fun onPageScrollStateChanged(state: Int) {
+ //"$state".logi()
+ _viewPagerScrollState = state
+ if (state == ViewPagerDelegate.SCROLL_STATE_IDLE) {
+ _onAnimateEnd()
+ dslSelector.updateStyle()
+ }
+ }
+
+ fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
+ if (isAnimatorStart) {
+ //动画已经开始了
+ return
+ }
+
+ val currentItem = _viewPagerDelegate?.onGetCurrentItem() ?: 0
+ //"$currentItem:$position $positionOffset $positionOffsetPixels state:$_viewPagerScrollState".logw()
+
+ if (position < currentItem) {
+ //Page 目标在左
+ if (_viewPagerScrollState == ViewPagerDelegate.SCROLL_STATE_DRAGGING) {
+ tabIndicator.currentIndex = position + 1
+ tabIndicator._targetIndex = position
+ }
+ _onAnimateValue(1 - positionOffset)
+ } else {
+ //Page 目标在右
+ if (_viewPagerScrollState == ViewPagerDelegate.SCROLL_STATE_DRAGGING) {
+ tabIndicator.currentIndex = position
+ tabIndicator._targetIndex = position + 1
+ }
+ _onAnimateValue(positionOffset)
+ }
+ }
+
+ fun onPageSelected(position: Int) {
+ setCurrentItem(position, true, false)
+ }
+
+ //
+
+ //
+
+ override fun onRestoreInstanceState(state: Parcelable?) {
+ if (state is Bundle) {
+ val oldState: Parcelable? = state.getParcelable("old")
+ super.onRestoreInstanceState(oldState)
+
+ tabDefaultIndex = state.getInt("defaultIndex", tabDefaultIndex)
+ val currentItemIndex = state.getInt("currentIndex", -1)
+ dslSelector.dslSelectIndex = -1
+ if (currentItemIndex > 0) {
+ setCurrentItem(currentItemIndex, true, false)
+ }
+ } else {
+ super.onRestoreInstanceState(state)
+ }
+ }
+
+ override fun onSaveInstanceState(): Parcelable? {
+ val state = super.onSaveInstanceState()
+ val bundle = Bundle()
+ bundle.putParcelable("old", state)
+ bundle.putInt("defaultIndex", tabDefaultIndex)
+ bundle.putInt("currentIndex", currentItemIndex)
+ return bundle
+ }
+
+ //
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayoutConfig.kt b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayoutConfig.kt
new file mode 100644
index 000000000..3d4a48dec
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/DslTabLayoutConfig.kt
@@ -0,0 +1,526 @@
+package com.angcyo.tablayout
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Typeface
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.annotation.IdRes
+import com.angcyo.tablayout.DslTabIndicator.Companion.NO_COLOR
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/26
+ * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
+ */
+open class DslTabLayoutConfig(val tabLayout: DslTabLayout) : DslSelectorConfig() {
+
+ /**是否开启文本颜色*/
+ var tabEnableTextColor = true
+ set(value) {
+ field = value
+ if (field) {
+ tabEnableIcoColor = true
+ }
+ }
+
+ /**是否开启颜色渐变效果*/
+ var tabEnableGradientColor = false
+ set(value) {
+ field = value
+ if (field) {
+ tabEnableIcoGradientColor = true
+ }
+ }
+
+ /**是否激活指示器的颜色渐变效果*/
+ var tabEnableIndicatorGradientColor = false
+
+ /**选中的文本颜色*/
+ var tabSelectColor: Int = Color.WHITE //Color.parseColor("#333333")
+
+ /**未选中的文本颜色*/
+ var tabDeselectColor: Int = Color.parseColor("#999999")
+
+ /**是否开启Bold, 文本加粗*/
+ var tabEnableTextBold = false
+
+ /**是否使用粗体字体的方式设置粗体, 否则使用[Paint.FAKE_BOLD_TEXT_FLAG]
+ * 需要先激活[tabEnableTextBold]*/
+ var tabUseTypefaceBold = false
+
+ /**是否开启图标颜色*/
+ var tabEnableIcoColor = true
+
+ /**是否开启图标颜色渐变效果*/
+ var tabEnableIcoGradientColor = false
+
+ /**选中的图标颜色*/
+ var tabIcoSelectColor: Int = NO_COLOR
+ get() {
+ return if (field == NO_COLOR) tabSelectColor else field
+ }
+
+ /**未选中的图标颜色*/
+ var tabIcoDeselectColor: Int = NO_COLOR
+ get() {
+ return if (field == NO_COLOR) tabDeselectColor else field
+ }
+
+ /**是否开启scale渐变效果*/
+ var tabEnableGradientScale = false
+
+ /**最小缩放的比例*/
+ var tabMinScale = 0.8f
+
+ /**最大缩放的比例*/
+ var tabMaxScale = 1.2f
+
+ /**是否开启字体大小渐变效果*/
+ var tabEnableGradientTextSize = true
+
+ /**tab中文本字体未选中时的字体大小, >0时激活*/
+ var tabTextMinSize = -1f
+
+ /**tab中文本字体选中时的字体大小, >0时激活*/
+ var tabTextMaxSize = -1f
+
+ /**渐变效果实现的回调*/
+ var tabGradientCallback = TabGradientCallback()
+
+ /**指定文本控件的id, 所有文本属性改变, 将会发生在这个控件上.
+ * 如果指定的控件不存在, 控件会降权至[ItemView]*/
+ @IdRes
+ var tabTextViewId: Int = View.NO_ID
+
+ /**指定图标控件的id*/
+ @IdRes
+ var tabIconViewId: Int = View.NO_ID
+
+ /**返回用于配置文本样式的控件*/
+ var onGetTextStyleView: (itemView: View, index: Int) -> TextView? = { itemView, _ ->
+ if (tabTextViewId == View.NO_ID) {
+ var tv: TextView? = if (itemView is TextView) itemView else null
+
+ if (tabLayout.tabIndicator.indicatorContentIndex != -1) {
+ itemView.getChildOrNull(tabLayout.tabIndicator.indicatorContentIndex)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+
+ if (tabLayout.tabIndicator.indicatorContentId != View.NO_ID) {
+ itemView.findViewById(tabLayout.tabIndicator.indicatorContentId)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+
+ val lp = itemView.layoutParams
+ if (lp is DslTabLayout.LayoutParams) {
+ if (lp.indicatorContentIndex != -1 && itemView is ViewGroup) {
+ itemView.getChildOrNull(lp.indicatorContentIndex)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+
+ if (lp.indicatorContentId != View.NO_ID) {
+ itemView.findViewById(lp.indicatorContentId)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+
+ if (lp.contentTextViewIndex != -1 && itemView is ViewGroup) {
+ itemView.getChildOrNull(lp.contentTextViewIndex)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+
+ if (lp.contentTextViewId != View.NO_ID) {
+ itemView.findViewById(lp.contentTextViewId)?.let {
+ if (it is TextView) {
+ tv = it
+ }
+ }
+ }
+ }
+ tv
+ } else {
+ itemView.findViewById(tabTextViewId)
+ }
+ }
+
+ /**返回用于配置ico样式的控件*/
+ var onGetIcoStyleView: (itemView: View, index: Int) -> View? = { itemView, _ ->
+ if (tabIconViewId == View.NO_ID) {
+ var iv: View? = itemView
+
+ if (tabLayout.tabIndicator.indicatorContentIndex != -1) {
+ itemView.getChildOrNull(tabLayout.tabIndicator.indicatorContentIndex)?.let {
+ iv = it
+ }
+ }
+
+ if (tabLayout.tabIndicator.indicatorContentId != View.NO_ID) {
+ itemView.findViewById(tabLayout.tabIndicator.indicatorContentId)?.let {
+ iv = it
+ }
+ }
+
+ val lp = itemView.layoutParams
+ if (lp is DslTabLayout.LayoutParams) {
+ if (lp.indicatorContentIndex != -1 && itemView is ViewGroup) {
+ iv = itemView.getChildOrNull(lp.indicatorContentIndex)
+ }
+
+ if (lp.indicatorContentId != View.NO_ID) {
+ itemView.findViewById(lp.indicatorContentId)?.let {
+ iv = it
+ }
+ }
+
+ if (lp.contentIconViewIndex != -1 && itemView is ViewGroup) {
+ iv = itemView.getChildOrNull(lp.contentIconViewIndex)
+ }
+
+ if (lp.contentIconViewId != View.NO_ID) {
+ itemView.findViewById(lp.contentIconViewId)?.let {
+ iv = it
+ }
+ }
+ }
+ iv
+ } else {
+ itemView.findViewById(tabIconViewId)
+ }
+ }
+
+ /**获取渐变结束时,指示器的颜色.*/
+ var onGetGradientIndicatorColor: (fromIndex: Int, toIndex: Int, positionOffset: Float) -> Int =
+ { fromIndex, toIndex, positionOffset ->
+ tabLayout.tabIndicator.indicatorColor
+ }
+
+ init {
+ onStyleItemView = { itemView, index, select ->
+ onUpdateItemStyle(itemView, index, select)
+ }
+ onSelectIndexChange = { fromIndex, selectIndexList, reselect, fromUser ->
+ val toIndex = selectIndexList.last()
+ tabLayout._viewPagerDelegate?.onSetCurrentItem(fromIndex, toIndex, reselect, fromUser)
+ }
+ }
+
+ /**xml属性读取*/
+ open fun initAttribute(context: Context, attributeSet: AttributeSet? = null) {
+ val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.DslTabLayout)
+
+ tabSelectColor =
+ typedArray.getColor(R.styleable.DslTabLayout_tab_select_color, tabSelectColor)
+ tabDeselectColor =
+ typedArray.getColor(
+ R.styleable.DslTabLayout_tab_deselect_color,
+ tabDeselectColor
+ )
+ tabIcoSelectColor =
+ typedArray.getColor(R.styleable.DslTabLayout_tab_ico_select_color, NO_COLOR)
+ tabIcoDeselectColor =
+ typedArray.getColor(R.styleable.DslTabLayout_tab_ico_deselect_color, NO_COLOR)
+
+ tabEnableTextColor = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_text_color,
+ tabEnableTextColor
+ )
+ tabEnableIndicatorGradientColor = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_indicator_gradient_color,
+ tabEnableIndicatorGradientColor
+ )
+ tabEnableGradientColor = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_gradient_color,
+ tabEnableGradientColor
+ )
+ tabEnableIcoColor = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_ico_color,
+ tabEnableIcoColor
+ )
+ tabEnableIcoGradientColor = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_ico_gradient_color,
+ tabEnableIcoGradientColor
+ )
+
+ tabEnableTextBold = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_text_bold,
+ tabEnableTextBold
+ )
+
+ tabUseTypefaceBold = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_use_typeface_bold,
+ tabUseTypefaceBold
+ )
+
+ tabEnableGradientScale = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_gradient_scale,
+ tabEnableGradientScale
+ )
+ tabMinScale = typedArray.getFloat(R.styleable.DslTabLayout_tab_min_scale, tabMinScale)
+ tabMaxScale = typedArray.getFloat(R.styleable.DslTabLayout_tab_max_scale, tabMaxScale)
+
+ tabEnableGradientTextSize = typedArray.getBoolean(
+ R.styleable.DslTabLayout_tab_enable_gradient_text_size,
+ tabEnableGradientTextSize
+ )
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_text_min_size)) {
+ tabTextMinSize = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_text_min_size,
+ tabTextMinSize.toInt()
+ ).toFloat()
+ }
+ if (typedArray.hasValue(R.styleable.DslTabLayout_tab_text_max_size)) {
+ tabTextMaxSize = typedArray.getDimensionPixelOffset(
+ R.styleable.DslTabLayout_tab_text_max_size,
+ tabTextMaxSize.toInt()
+ ).toFloat()
+ }
+
+ tabTextViewId =
+ typedArray.getResourceId(R.styleable.DslTabLayout_tab_text_view_id, tabTextViewId)
+ tabIconViewId =
+ typedArray.getResourceId(R.styleable.DslTabLayout_tab_icon_view_id, tabIconViewId)
+
+ typedArray.recycle()
+ }
+
+ /**更新item的样式*/
+ open fun onUpdateItemStyle(itemView: View, index: Int, select: Boolean) {
+ //"$itemView\n$index\n$select".logw()
+
+ (onGetTextStyleView(itemView, index))?.apply {
+ //文本加粗
+ paint?.apply {
+ if (tabEnableTextBold && select) {
+ //设置粗体
+ if (tabUseTypefaceBold) {
+ typeface = Typeface.defaultFromStyle(Typeface.BOLD)
+ } else {
+ flags = flags or Paint.FAKE_BOLD_TEXT_FLAG
+ isFakeBoldText = true
+ }
+ } else {
+ //取消粗体
+ if (tabUseTypefaceBold) {
+ typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
+ } else {
+ flags = flags and Paint.FAKE_BOLD_TEXT_FLAG.inv()
+ isFakeBoldText = false
+ }
+ }
+ }
+
+ if (tabEnableTextColor) {
+ //文本颜色
+ setTextColor(if (select) tabSelectColor else tabDeselectColor)
+ }
+
+ if (tabTextMaxSize > 0 || tabTextMinSize > 0) {
+ //文本字体大小
+ val minTextSize = min(tabTextMinSize, tabTextMaxSize)
+ val maxTextSize = max(tabTextMinSize, tabTextMaxSize)
+ setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ if (select) maxTextSize else minTextSize
+ )
+ }
+ }
+
+ if (tabEnableIcoColor) {
+ onGetIcoStyleView(itemView, index)?.apply {
+ _updateIcoColor(this, if (select) tabIcoSelectColor else tabIcoDeselectColor)
+ }
+ }
+
+ if (tabEnableGradientScale) {
+ itemView.scaleX = if (select) tabMaxScale else tabMinScale
+ itemView.scaleY = if (select) tabMaxScale else tabMinScale
+ }
+
+ if (tabLayout.drawBorder) {
+ tabLayout.tabBorder?.updateItemBackground(tabLayout, itemView, index, select)
+ }
+ }
+
+ /**
+ * [DslTabLayout]滚动时回调.
+ * */
+ open fun onPageIndexScrolled(fromIndex: Int, toIndex: Int, positionOffset: Float) {
+
+ }
+
+ /**
+ * [onPageIndexScrolled]
+ * */
+ open fun onPageViewScrolled(fromView: View?, toView: View, positionOffset: Float) {
+ //"$fromView\n$toView\n$positionOffset".logi()
+
+ if (fromView != toView) {
+
+ val fromIndex = tabLayout.tabIndicator.currentIndex
+ val toIndex = tabLayout.tabIndicator._targetIndex
+
+ if (tabEnableIndicatorGradientColor) {
+ val startColor = onGetGradientIndicatorColor(fromIndex, fromIndex, 0f)
+ val endColor = onGetGradientIndicatorColor(fromIndex, toIndex, positionOffset)
+
+ tabLayout.tabIndicator.indicatorColor =
+ evaluateColor(positionOffset, startColor, endColor)
+ }
+
+ if (tabEnableGradientColor) {
+ //文本渐变
+ fromView?.apply {
+ _gradientColor(
+ onGetTextStyleView(this, fromIndex),
+ tabSelectColor,
+ tabDeselectColor,
+ positionOffset
+ )
+ }
+ _gradientColor(
+ onGetTextStyleView(toView, toIndex),
+ tabDeselectColor,
+ tabSelectColor,
+ positionOffset
+ )
+ }
+
+ if (tabEnableIcoGradientColor) {
+ //图标渐变
+ fromView?.apply {
+ _gradientIcoColor(
+ onGetIcoStyleView(this, fromIndex),
+ tabIcoSelectColor,
+ tabIcoDeselectColor,
+ positionOffset
+ )
+ }
+
+ _gradientIcoColor(
+ onGetIcoStyleView(toView, toIndex),
+ tabIcoDeselectColor,
+ tabIcoSelectColor,
+ positionOffset
+ )
+ }
+
+ if (tabEnableGradientScale) {
+ //scale渐变
+ _gradientScale(fromView, tabMaxScale, tabMinScale, positionOffset)
+ _gradientScale(toView, tabMinScale, tabMaxScale, positionOffset)
+ }
+
+ if (tabEnableGradientTextSize &&
+ tabTextMaxSize > 0 &&
+ tabTextMinSize > 0 &&
+ tabTextMinSize != tabTextMaxSize
+ ) {
+
+ //文本字体大小渐变
+ _gradientTextSize(
+ fromView?.run { onGetTextStyleView(this, fromIndex) },
+ tabTextMaxSize,
+ tabTextMinSize,
+ positionOffset
+ )
+ _gradientTextSize(
+ onGetTextStyleView(toView, toIndex),
+ tabTextMinSize,
+ tabTextMaxSize,
+ positionOffset
+ )
+
+ if (toIndex == tabLayout.dslSelector.visibleViewList.lastIndex || toIndex == 0) {
+ tabLayout._scrollToTarget(toIndex, false)
+ }
+ }
+ }
+ }
+
+ open fun _gradientColor(view: View?, startColor: Int, endColor: Int, percent: Float) {
+ tabGradientCallback.onGradientColor(view, startColor, endColor, percent)
+ }
+
+ open fun _gradientIcoColor(view: View?, startColor: Int, endColor: Int, percent: Float) {
+ tabGradientCallback.onGradientIcoColor(view, startColor, endColor, percent)
+ }
+
+ open fun _gradientScale(view: View?, startScale: Float, endScale: Float, percent: Float) {
+ tabGradientCallback.onGradientScale(view, startScale, endScale, percent)
+ }
+
+ open fun _gradientTextSize(
+ view: TextView?,
+ startTextSize: Float,
+ endTextSize: Float,
+ percent: Float
+ ) {
+ tabGradientCallback.onGradientTextSize(view, startTextSize, endTextSize, percent)
+ }
+
+ open fun _updateIcoColor(view: View?, color: Int) {
+ tabGradientCallback.onUpdateIcoColor(view, color)
+ }
+}
+
+open class TabGradientCallback {
+
+ open fun onGradientColor(view: View?, startColor: Int, endColor: Int, percent: Float) {
+ (view as? TextView)?.apply {
+ setTextColor(evaluateColor(percent, startColor, endColor))
+ }
+ }
+
+ open fun onGradientIcoColor(view: View?, startColor: Int, endColor: Int, percent: Float) {
+ onUpdateIcoColor(view, evaluateColor(percent, startColor, endColor))
+ }
+
+ open fun onUpdateIcoColor(view: View?, color: Int) {
+ view?.tintDrawableColor(color)
+ }
+
+ open fun onGradientScale(view: View?, startScale: Float, endScale: Float, percent: Float) {
+ view?.apply {
+ (startScale + (endScale - startScale) * percent).let {
+ scaleX = it
+ scaleY = it
+ }
+ }
+ }
+
+ open fun onGradientTextSize(
+ view: TextView?,
+ startTextSize: Float,
+ endTextSize: Float,
+ percent: Float
+ ) {
+ view?.apply {
+ setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ (startTextSize + (endTextSize - startTextSize) * percent)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/ITabIndicatorDraw.kt b/TabLayout/src/main/java/com/angcyo/tablayout/ITabIndicatorDraw.kt
new file mode 100644
index 000000000..1b7f74926
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/ITabIndicatorDraw.kt
@@ -0,0 +1,22 @@
+package com.angcyo.tablayout
+
+import android.graphics.Canvas
+
+/**
+ * 用来实现[DslTabIndicator]的自绘
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2022/02/21
+ * Copyright (c) 2020 ShenZhen Wayto Ltd. All rights reserved.
+ */
+interface ITabIndicatorDraw {
+
+ /**绘制指示器
+ * [positionOffset] 页面偏移量*/
+ fun onDrawTabIndicator(
+ tabIndicator: DslTabIndicator,
+ canvas: Canvas,
+ positionOffset: Float
+ )
+
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/LibEx.kt b/TabLayout/src/main/java/com/angcyo/tablayout/LibEx.kt
new file mode 100644
index 000000000..2d040a90e
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/LibEx.kt
@@ -0,0 +1,334 @@
+package com.angcyo.tablayout
+
+import android.app.Activity
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.text.TextUtils
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.LayoutRes
+import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.math.MathUtils
+
+/**
+ *
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/11/23
+ */
+internal val dpi: Int
+ get() = dp.toInt()
+
+internal val dp: Float
+ get() = Resources.getSystem().displayMetrics.density
+
+internal val View.dpi: Int
+ get() = context.resources.displayMetrics.density.toInt()
+
+internal val View.screenWidth: Int
+ get() = context.resources.displayMetrics.widthPixels
+
+internal val View.screenHeight: Int
+ get() = context.resources.displayMetrics.heightPixels
+
+internal val View.viewDrawWidth: Int
+ get() = measuredWidth - paddingLeft - paddingRight
+
+internal val View.viewDrawHeight: Int
+ get() = measuredHeight - paddingTop - paddingBottom
+
+/**Match_Parent*/
+internal fun exactlyMeasure(size: Int): Int =
+ View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.EXACTLY)
+
+internal fun exactlyMeasure(size: Float): Int = exactlyMeasure(size.toInt())
+
+/**Wrap_Content*/
+internal fun atmostMeasure(size: Int): Int =
+ View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.AT_MOST)
+
+internal fun Int.have(value: Int): Boolean = if (this == 0 || value == 0) {
+ false
+} else if (this == 0 && value == 0) {
+ true
+} else {
+ ((this > 0 && value > 0) || (this < 0 && value < 0)) && this and value == value
+}
+
+internal fun Int.remove(value: Int): Int = this and value.inv()
+
+internal fun clamp(value: Float, min: Float, max: Float): Float {
+ if (value < min) {
+ return min
+ } else if (value > max) {
+ return max
+ }
+ return value
+}
+
+internal fun clamp(value: Int, min: Int, max: Int): Int {
+ if (value < min) {
+ return min
+ } else if (value > max) {
+ return max
+ }
+ return value
+}
+
+internal fun Any.logi() {
+ Log.i("DslTabLayout", "$this")
+}
+
+internal fun Any.logw() {
+ Log.w("DslTabLayout", "$this")
+}
+
+internal fun Any.loge() {
+ Log.e("DslTabLayout", "$this")
+}
+
+internal fun View.calcLayoutWidthHeight(
+ rLayoutWidth: String?, rLayoutHeight: String?,
+ parentWidth: Int, parentHeight: Int,
+ rLayoutWidthExclude: Int = 0, rLayoutHeightExclude: Int = 0
+): IntArray {
+ val size = intArrayOf(-1, -1)
+ if (TextUtils.isEmpty(rLayoutWidth) && TextUtils.isEmpty(rLayoutHeight)) {
+ return size
+ }
+ if (!TextUtils.isEmpty(rLayoutWidth)) {
+ if (rLayoutWidth!!.contains("sw", true)) {
+ val ratio = rLayoutWidth.replace("sw", "", true).toFloatOrNull()
+ ratio?.let {
+ size[0] = (ratio * (screenWidth - rLayoutWidthExclude)).toInt()
+ }
+ } else if (rLayoutWidth!!.contains("pw", true)) {
+ val ratio = rLayoutWidth.replace("pw", "", true).toFloatOrNull()
+ ratio?.let {
+ size[0] = (ratio * (parentWidth - rLayoutWidthExclude)).toInt()
+ }
+ }
+ }
+ if (!TextUtils.isEmpty(rLayoutHeight)) {
+ if (rLayoutHeight!!.contains("sh", true)) {
+ val ratio = rLayoutHeight.replace("sh", "", true).toFloatOrNull()
+ ratio?.let {
+ size[1] = (ratio * (screenHeight - rLayoutHeightExclude)).toInt()
+ }
+ } else if (rLayoutHeight!!.contains("ph", true)) {
+ val ratio = rLayoutHeight.replace("ph", "", true).toFloatOrNull()
+ ratio?.let {
+ size[1] = (ratio * (parentHeight - rLayoutHeightExclude)).toInt()
+ }
+ }
+ }
+ return size
+}
+
+internal fun evaluateColor(fraction: Float /*0-1*/, startColor: Int, endColor: Int): Int {
+ val fr = MathUtils.clamp(fraction, 0f, 1f)
+ val startA = startColor shr 24 and 0xff
+ val startR = startColor shr 16 and 0xff
+ val startG = startColor shr 8 and 0xff
+ val startB = startColor and 0xff
+ val endA = endColor shr 24 and 0xff
+ val endR = endColor shr 16 and 0xff
+ val endG = endColor shr 8 and 0xff
+ val endB = endColor and 0xff
+ return startA + (fr * (endA - startA)).toInt() shl 24 or
+ (startR + (fr * (endR - startR)).toInt() shl 16) or
+ (startG + (fr * (endG - startG)).toInt() shl 8) or
+ startB + (fr * (endB - startB)).toInt()
+}
+
+internal fun Drawable?.tintDrawableColor(color: Int): Drawable? {
+
+ if (this == null) {
+ return this
+ }
+
+ val wrappedDrawable =
+ DrawableCompat.wrap(this).mutate()
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ DrawableCompat.setTint(wrappedDrawable, color)
+ } else {
+ wrappedDrawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
+ }
+
+ return wrappedDrawable
+}
+
+internal fun View?.tintDrawableColor(color: Int) {
+ when (this) {
+ is TextView -> {
+ val drawables = arrayOfNulls(4)
+ compoundDrawables.forEachIndexed { index, drawable ->
+ drawables[index] = drawable?.tintDrawableColor(color)
+ }
+ setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3])
+ }
+ is ImageView -> {
+ setImageDrawable(drawable?.tintDrawableColor(color))
+ }
+ }
+}
+
+internal fun Paint?.textWidth(text: String?): Float {
+ if (TextUtils.isEmpty(text)) {
+ return 0f
+ }
+ return this?.run {
+ measureText(text)
+ } ?: 0f
+}
+
+internal fun Paint?.textHeight(): Float = this?.run { descent() - ascent() } ?: 0f
+
+internal fun View.getChildOrNull(index: Int): View? {
+ return if (this is ViewGroup) {
+ return if (index in 0 until childCount) {
+ getChildAt(index)
+ } else {
+ null
+ }
+ } else {
+ this
+ }
+}
+
+/**获取[View]在指定[parent]中的矩形坐标*/
+internal fun View.getLocationInParent(parentView: View? = null, result: Rect = Rect()): Rect {
+ val parent: View? = parentView ?: (parent as? View)
+
+ if (parent == null) {
+ getViewRect(result)
+ } else {
+ result.set(0, 0, 0, 0)
+ if (this != parent) {
+ fun doIt(view: View, parent: View, rect: Rect) {
+ val viewParent = view.parent
+ if (viewParent is View) {
+ rect.left += view.left
+ rect.top += view.top
+ if (viewParent != parent) {
+ doIt(viewParent, parent, rect)
+ }
+ }
+ }
+ doIt(this, parent, result)
+ }
+ result.right = result.left + this.measuredWidth
+ result.bottom = result.top + this.measuredHeight
+ }
+
+ return result
+}
+
+/**
+ * 获取View, 相对于手机屏幕的矩形
+ * */
+internal fun View.getViewRect(result: Rect = Rect()): Rect {
+ var offsetX = 0
+ var offsetY = 0
+
+ //横屏, 并且显示了虚拟导航栏的时候. 需要左边偏移
+ //只计算一次
+ (context as? Activity)?.let {
+ it.window.decorView.getGlobalVisibleRect(result)
+ if (result.width() > result.height()) {
+ //横屏了
+ offsetX = navBarHeight(it)
+ }
+ }
+
+ return getViewRect(offsetX, offsetY, result)
+}
+
+/**
+ * 获取View, 相对于手机屏幕的矩形, 带皮阿尼一
+ * */
+internal fun View.getViewRect(offsetX: Int, offsetY: Int, result: Rect = Rect()): Rect {
+ //可见位置的坐标, 超出屏幕的距离会被剃掉
+ //getGlobalVisibleRect(r)
+ val r2 = IntArray(2)
+ //val r3 = IntArray(2)
+ //相对于屏幕的坐标
+ getLocationOnScreen(r2)
+ //相对于窗口的坐标
+ //getLocationInWindow(r3)
+
+ val left = r2[0] + offsetX
+ val top = r2[1] + offsetY
+
+ result.set(left, top, left + measuredWidth, top + measuredHeight)
+ return result
+}
+
+
+/**
+ * 导航栏的高度(如果显示了)
+ */
+internal fun navBarHeight(context: Context): Int {
+ var result = 0
+
+ if (context is Activity) {
+ val decorRect = Rect()
+ val windowRect = Rect()
+
+ context.window.decorView.getGlobalVisibleRect(decorRect)
+ context.window.findViewById(Window.ID_ANDROID_CONTENT)
+ .getGlobalVisibleRect(windowRect)
+
+ if (decorRect.width() > decorRect.height()) {
+ //横屏
+ result = decorRect.width() - windowRect.width()
+ } else {
+ //竖屏
+ result = decorRect.bottom - windowRect.bottom
+ }
+ }
+
+ return result
+}
+
+fun Collection<*>?.size() = this?.size ?: 0
+
+/**判断2个列表中的数据是否改变过*/
+internal fun List?.isChange(other: List?): Boolean {
+ if (this.size() != other.size()) {
+ return true
+ }
+ this?.forEachIndexed { index, t ->
+ if (t != other?.getOrNull(index)) {
+ return true
+ }
+ }
+ return false
+}
+
+fun Int.isHorizontal() = this == LinearLayout.HORIZONTAL
+
+fun Int.isVertical() = this == LinearLayout.VERTICAL
+
+internal fun ViewGroup.inflate(@LayoutRes layoutId: Int, attachToRoot: Boolean = true): View {
+ if (layoutId == -1) {
+ return this
+ }
+ val rootView = LayoutInflater.from(context).inflate(layoutId, this, false)
+ if (attachToRoot) {
+ addView(rootView)
+ }
+ return rootView
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/java/com/angcyo/tablayout/ViewPagerDelegate.kt b/TabLayout/src/main/java/com/angcyo/tablayout/ViewPagerDelegate.kt
new file mode 100644
index 000000000..a40df8500
--- /dev/null
+++ b/TabLayout/src/main/java/com/angcyo/tablayout/ViewPagerDelegate.kt
@@ -0,0 +1,21 @@
+package com.angcyo.tablayout
+
+/**
+ * 不依赖ViewPager和ViewPager2
+ * Email:angcyo@126.com
+ * @author angcyo
+ * @date 2019/12/14
+ */
+interface ViewPagerDelegate {
+ companion object {
+ const val SCROLL_STATE_IDLE = 0
+ const val SCROLL_STATE_DRAGGING = 1
+ const val SCROLL_STATE_SETTLING = 2
+ }
+
+ /**获取当前页面索引*/
+ fun onGetCurrentItem(): Int
+
+ /**设置当前的页面*/
+ fun onSetCurrentItem(fromIndex: Int, toIndex: Int, reselect: Boolean, fromUser: Boolean)
+}
\ No newline at end of file
diff --git a/TabLayout/src/main/res/values/attr_dsl_tab_layout.xml b/TabLayout/src/main/res/values/attr_dsl_tab_layout.xml
new file mode 100644
index 000000000..423d215c8
--- /dev/null
+++ b/TabLayout/src/main/res/values/attr_dsl_tab_layout.xml
@@ -0,0 +1,299 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index fec68ed31..aa3a7f6cd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,6 +4,7 @@ apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.alibaba.arouter'
apply from: "../package_config.gradle"
+
android {
namespace "com.pandoralive.shayu"
/* applicationVariants.all { variant ->
@@ -215,9 +216,9 @@ android {
def server = ''
if (variant.name.startsWith('huawei')) {
channel = "华为"
- } else if (variant.name.startsWith('samsung')) {
+ } else if (variant.name.contains('samsung')) {
channel = "三星"
- } else if (variant.name.startsWith('google')) {
+ } else if (variant.name.contains('google')) {
channel = "谷歌"
} else {
channel = "链接"
@@ -311,11 +312,13 @@ android {
String tskReqStr = gradle.getStartParameter().getTaskRequests().args.toString()
println("处理ndk 版本 = " + tskReqStr)
def isLink = tskReqStr.contains("Link")
- if (isLink) {
+ if (isLink) {//移除32位so库可以有效降低包体大小,等需要时再弄
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+ //abiFilters "arm64-v8a", "x86_64"
println("打包ndk 链接")
} else {
abiFilters "armeabi-v7a", "arm64-v8a"
+ //abiFilters "arm64-v8a"
println("打包ndk其他")
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 1c250b06d..81d4288bb 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -315,3 +315,7 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.qiniu.**{*;}
-keep class com.qiniu.**{public ();}
-ignorewarnings
+
+-keep class com.qiniu.**{*;}
+-keep class com.qiniu.**{public ();}
+-ignorewarnings
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8054385d9..c0776bf39 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -97,6 +97,9 @@
+
+
+
PandoraLive
- assertk.Assert
\ No newline at end of file
diff --git a/app/tmp/full-r8-config.txt b/app/tmp/full-r8-config.txt
index d909c7e74..502664459 100644
--- a/app/tmp/full-r8-config.txt
+++ b/app/tmp/full-r8-config.txt
@@ -1,4 +1,4 @@
-# The proguard configuration file for the following section is C:\Users\58381\Documents\AndroidProject\pandorapan\app\build\intermediates\default_proguard_files\global\proguard-android.txt-8.3.1
+# The proguard configuration file for the following section is D:\android project\pandorapan\app\build\intermediates\default_proguard_files\global\proguard-android.txt-8.3.1
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
@@ -95,8 +95,8 @@
# These classes are duplicated between android.jar and core-lambda-stubs.jar.
-dontnote java.lang.invoke.**
-# End of content from C:\Users\58381\Documents\AndroidProject\pandorapan\app\build\intermediates\default_proguard_files\global\proguard-android.txt-8.3.1
-# The proguard configuration file for the following section is C:\Users\58381\Documents\AndroidProject\pandorapan\app\proguard-rules.pro
+# End of content from D:\android project\pandorapan\app\build\intermediates\default_proguard_files\global\proguard-android.txt-8.3.1
+# The proguard configuration file for the following section is D:\android project\pandorapan\app\proguard-rules.pro
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/macpro/Library/Android/sdk/tools/proguard/proguard-android.txt
@@ -415,8 +415,12 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.qiniu.**{public ();}
-ignorewarnings
-# End of content from C:\Users\58381\Documents\AndroidProject\pandorapan\app\proguard-rules.pro
-# The proguard configuration file for the following section is C:\Users\58381\Documents\AndroidProject\pandorapan\app\build\intermediates\aapt_proguard_file\link_onlineRelease\processLink_onlineReleaseResources\aapt_rules.txt
+-keep class com.qiniu.**{*;}
+-keep class com.qiniu.**{public ();}
+-ignorewarnings
+
+# End of content from D:\android project\pandorapan\app\proguard-rules.pro
+# The proguard configuration file for the following section is D:\android project\pandorapan\app\build\intermediates\aapt_proguard_file\google_onlineRelease\processGoogle_onlineReleaseResources\aapt_rules.txt
-keep class androidx.core.app.CoreComponentFactory { (); }
-keep class androidx.core.content.FileProvider { (); }
-keep class androidx.core.content.FileProvider4Utils { (); }
@@ -424,6 +428,7 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class androidx.room.MultiInstanceInvalidationService { (); }
-keep class androidx.startup.InitializationProvider { (); }
-keep class com.android.billingclient.api.ProxyBillingActivity { (); }
+-keep class com.android.billingclient.api.ProxyBillingActivityV2 { (); }
-keep class com.blankj.utilcode.util.MessengerUtils$ServerService { (); }
-keep class com.blankj.utilcode.util.UtilsFileProvider { (); }
-keep class com.blankj.utilcode.util.UtilsTransActivity { (); }
@@ -607,8 +612,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class io.rong.sight.player.SightPlayerActivity { (); }
-keep class io.rong.sight.record.SightRecordActivity { (); }
-keep class tech.sud.mgp.engine.hub.real.unity.activity.SudUnityPlayerActivity { (); }
--keep class android.opengl.GLSurfaceView { (android.content.Context, android.util.AttributeSet); }
-
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { (); }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { (); }
-keep class android.widget.Space { (android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.app.AlertController$RecycleListView { (android.content.Context, android.util.AttributeSet); }
@@ -687,6 +692,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.airbnb.lottie.LottieAnimationView { (android.content.Context, android.util.AttributeSet); }
+-keep class com.angcyo.tablayout.DslTabLayout { (android.content.Context, android.util.AttributeSet); }
+
-keep class com.blankj.utilcode.util.ToastUtils$UtilsMaxWidthRelativeLayout { (android.content.Context, android.util.AttributeSet); }
-keep class com.contrarywind.view.WheelView { (android.content.Context, android.util.AttributeSet); }
@@ -749,8 +756,6 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.google.android.material.timepicker.TimePickerView { (android.content.Context, android.util.AttributeSet); }
--keep class com.ksyun.media.player.KSYTextureView { (android.content.Context, android.util.AttributeSet); }
-
-keep class com.lxj.xpopup.widget.BlankView { (android.content.Context, android.util.AttributeSet); }
-keep class com.lxj.xpopup.widget.BubbleLayout { (android.content.Context, android.util.AttributeSet); }
@@ -925,6 +930,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.yunbao.common.views.AutoSplitTextView { (android.content.Context, android.util.AttributeSet); }
+-keep class com.yunbao.common.views.CustomEllipsizeTextView { (android.content.Context, android.util.AttributeSet); }
+
-keep class com.yunbao.common.views.CustomLayout { (android.content.Context, android.util.AttributeSet); }
-keep class com.yunbao.common.views.FlowLayout { (android.content.Context, android.util.AttributeSet); }
@@ -957,16 +964,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.yunbao.common.views.weight.VerticalViewPager { (android.content.Context, android.util.AttributeSet); }
--keep class com.yunbao.faceunity.checkbox.CheckBoxCompat { (android.content.Context, android.util.AttributeSet); }
-
--keep class com.yunbao.faceunity.checkbox.CheckGroup { (android.content.Context, android.util.AttributeSet); }
-
-keep class com.yunbao.faceunity.seekbar.DiscreteSeekBar { (android.content.Context, android.util.AttributeSet); }
--keep class com.yunbao.faceunity.widget.CircleImageView { (android.content.Context, android.util.AttributeSet); }
-
--keep class com.yunbao.faceunity.widget.TouchStateImageView { (android.content.Context, android.util.AttributeSet); }
-
-keep class com.yunbao.live.custom.FrameImageView { (android.content.Context, android.util.AttributeSet); }
-keep class com.yunbao.live.custom.GiftMarkView { (android.content.Context, android.util.AttributeSet); }
@@ -1041,6 +1040,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class io.rong.imkit.widget.RCMessageFrameLayout { (android.content.Context, android.util.AttributeSet); }
+-keep class io.rong.imkit.widget.RongEditText { (android.content.Context, android.util.AttributeSet); }
+
-keep class io.rong.imkit.widget.RongSwipeRefreshLayout { (android.content.Context, android.util.AttributeSet); }
-keep class io.rong.imkit.widget.RoundCornerLinearLayout { (android.content.Context, android.util.AttributeSet); }
@@ -1090,11 +1091,11 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keepclassmembers class * { *** videoEditClick(android.view.View); }
-# End of content from C:\Users\58381\Documents\AndroidProject\pandorapan\app\build\intermediates\aapt_proguard_file\link_onlineRelease\processLink_onlineReleaseResources\aapt_rules.txt
-# The proguard configuration file for the following section is C:\Users\58381\Documents\AndroidProject\pandorapan\lib_faceunity\build\intermediates\consumer_proguard_dir\link_onlineRelease\exportLink_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
+# End of content from D:\android project\pandorapan\app\build\intermediates\aapt_proguard_file\google_onlineRelease\processGoogle_onlineReleaseResources\aapt_rules.txt
+# The proguard configuration file for the following section is D:\android project\pandorapan\lib_faceunity\build\intermediates\consumer_proguard_dir\google_onlineRelease\exportGoogle_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
-# End of content from C:\Users\58381\Documents\AndroidProject\pandorapan\lib_faceunity\build\intermediates\consumer_proguard_dir\link_onlineRelease\exportLink_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\8d3e3177c15403546de73d87508067d6\transformed\jetified-XPopup-2.10.0\proguard.txt
+# End of content from D:\android project\pandorapan\lib_faceunity\build\intermediates\consumer_proguard_dir\google_onlineRelease\exportGoogle_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\8d3e3177c15403546de73d87508067d6\transformed\jetified-XPopup-2.10.0\proguard.txt
# Generated keep rule for Lifecycle observer adapter.
-if class com.lxj.xpopup.core.BasePopupView {
(...);
@@ -1103,8 +1104,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
(...);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\8d3e3177c15403546de73d87508067d6\transformed\jetified-XPopup-2.10.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a1df9a6aa192455030f7c9970b70e0e9\transformed\material-1.4.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\8d3e3177c15403546de73d87508067d6\transformed\jetified-XPopup-2.10.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\a1df9a6aa192455030f7c9970b70e0e9\transformed\material-1.4.0\proguard.txt
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1152,16 +1153,16 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a1df9a6aa192455030f7c9970b70e0e9\transformed\material-1.4.0\proguard.txt
-# The proguard configuration file for the following section is C:\Users\58381\Documents\AndroidProject\pandorapan\lib_google\build\intermediates\consumer_proguard_dir\link_onlineRelease\exportLink_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\a1df9a6aa192455030f7c9970b70e0e9\transformed\material-1.4.0\proguard.txt
+# The proguard configuration file for the following section is D:\android project\pandorapan\lib_google\build\intermediates\consumer_proguard_dir\google_onlineRelease\exportGoogle_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
-# End of content from C:\Users\58381\Documents\AndroidProject\pandorapan\lib_google\build\intermediates\consumer_proguard_dir\link_onlineRelease\exportLink_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\2929985d9627ba3bb45a0ebd18eaf9d3\transformed\jetified-linesdk-5.0.1\proguard.txt
+# End of content from D:\android project\pandorapan\lib_google\build\intermediates\consumer_proguard_dir\google_onlineRelease\exportGoogle_onlineReleaseConsumerProguardFiles\lib0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\2929985d9627ba3bb45a0ebd18eaf9d3\transformed\jetified-linesdk-5.0.1\proguard.txt
-keepattributes *Annotation*
-# End of content from C:\gradle-6.1.1\caches\transforms-3\2929985d9627ba3bb45a0ebd18eaf9d3\transformed\jetified-linesdk-5.0.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\6baa4e4ee96e21acbcf3a49ef89d9f1f\transformed\jetified-facebook-android-sdk-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\2929985d9627ba3bb45a0ebd18eaf9d3\transformed\jetified-linesdk-5.0.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\6baa4e4ee96e21acbcf3a49ef89d9f1f\transformed\jetified-facebook-android-sdk-15.2.0\proguard.txt
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
@@ -1201,8 +1202,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
public android.os.Bundle getSkuDetails(int, java.lang.String, java.lang.String, android.os.Bundle);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\6baa4e4ee96e21acbcf3a49ef89d9f1f\transformed\jetified-facebook-android-sdk-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\44135493e77410a01759fde38f8d0bd2\transformed\jetified-facebook-gamingservices-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\6baa4e4ee96e21acbcf3a49ef89d9f1f\transformed\jetified-facebook-android-sdk-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\44135493e77410a01759fde38f8d0bd2\transformed\jetified-facebook-gamingservices-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1243,8 +1244,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.gamingservices.GamingServices
-# End of content from C:\gradle-6.1.1\caches\transforms-3\44135493e77410a01759fde38f8d0bd2\transformed\jetified-facebook-gamingservices-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\c831739b6efc746f59d2a47471573f41\transformed\jetified-facebook-share-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\44135493e77410a01759fde38f8d0bd2\transformed\jetified-facebook-gamingservices-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\c831739b6efc746f59d2a47471573f41\transformed\jetified-facebook-share-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1285,8 +1286,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.share.Share
-# End of content from C:\gradle-6.1.1\caches\transforms-3\c831739b6efc746f59d2a47471573f41\transformed\jetified-facebook-share-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\3815d0ddf4b17772bdba730e93b11daf\transformed\jetified-facebook-login-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\c831739b6efc746f59d2a47471573f41\transformed\jetified-facebook-share-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\3815d0ddf4b17772bdba730e93b11daf\transformed\jetified-facebook-login-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1327,8 +1328,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.login.Login
-# End of content from C:\gradle-6.1.1\caches\transforms-3\3815d0ddf4b17772bdba730e93b11daf\transformed\jetified-facebook-login-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\43855db83adace9940918a3f6edcdc05\transformed\jetified-facebook-common-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\3815d0ddf4b17772bdba730e93b11daf\transformed\jetified-facebook-login-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\43855db83adace9940918a3f6edcdc05\transformed\jetified-facebook-common-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1369,12 +1370,12 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.common.Common
-# End of content from C:\gradle-6.1.1\caches\transforms-3\43855db83adace9940918a3f6edcdc05\transformed\jetified-facebook-common-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\7bbb003dbf2685697cd42cfb46e77b3f\transformed\jetified-subsampling-scale-image-view-androidx-3.10.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\43855db83adace9940918a3f6edcdc05\transformed\jetified-facebook-common-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\7bbb003dbf2685697cd42cfb46e77b3f\transformed\jetified-subsampling-scale-image-view-androidx-3.10.0\proguard.txt
-keep class com.davemorrissey.labs.subscaleview.** { *; }
-# End of content from C:\gradle-6.1.1\caches\transforms-3\7bbb003dbf2685697cd42cfb46e77b3f\transformed\jetified-subsampling-scale-image-view-androidx-3.10.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\0fdcb88552259c6c22dbd3bb46b31518\transformed\appcompat-1.3.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\7bbb003dbf2685697cd42cfb46e77b3f\transformed\jetified-subsampling-scale-image-view-androidx-3.10.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\0fdcb88552259c6c22dbd3bb46b31518\transformed\appcompat-1.3.1\proguard.txt
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1398,13 +1399,13 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\0fdcb88552259c6c22dbd3bb46b31518\transformed\appcompat-1.3.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\b8e86bdadf487d72a43cd430b3f9db16\transformed\jetified-tweet-ui-3.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\0fdcb88552259c6c22dbd3bb46b31518\transformed\appcompat-1.3.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\b8e86bdadf487d72a43cd430b3f9db16\transformed\jetified-tweet-ui-3.1.1\proguard.txt
#Picasso Proguard Config https://github.com/square/picasso
-dontwarn com.squareup.okhttp.**
-# End of content from C:\gradle-6.1.1\caches\transforms-3\b8e86bdadf487d72a43cd430b3f9db16\transformed\jetified-tweet-ui-3.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\2dd2f4200d3a68f4165485a3d207312d\transformed\coordinatorlayout-1.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\b8e86bdadf487d72a43cd430b3f9db16\transformed\jetified-tweet-ui-3.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\2dd2f4200d3a68f4165485a3d207312d\transformed\coordinatorlayout-1.2.0\proguard.txt
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1431,13 +1432,13 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
RuntimeVisibleParameterAnnotations,
RuntimeVisibleTypeAnnotations
-# End of content from C:\gradle-6.1.1\caches\transforms-3\2dd2f4200d3a68f4165485a3d207312d\transformed\coordinatorlayout-1.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\940a969ab3fccb91703d8a9245e2974b\transformed\jetified-x-1.3.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\2dd2f4200d3a68f4165485a3d207312d\transformed\coordinatorlayout-1.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\940a969ab3fccb91703d8a9245e2974b\transformed\jetified-x-1.3.2\proguard.txt
-keepclasseswithmembers class androidx.recyclerview.widget.RecyclerView$ViewHolder {
public final android.view.View *;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\940a969ab3fccb91703d8a9245e2974b\transformed\jetified-x-1.3.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e452872bf1c6c06c71776c88e0bd7b6a\transformed\jetified-exoplayer-ui-2.18.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\940a969ab3fccb91703d8a9245e2974b\transformed\jetified-x-1.3.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\e452872bf1c6c06c71776c88e0bd7b6a\transformed\jetified-exoplayer-ui-2.18.2\proguard.txt
# Proguard rules specific to the UI module.
# Constructor method accessed via reflection in StyledPlayerView
@@ -1478,8 +1479,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-dontwarn kotlin.annotations.jvm.**
-dontwarn javax.annotation.**
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e452872bf1c6c06c71776c88e0bd7b6a\transformed\jetified-exoplayer-ui-2.18.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e9de7db2640f13ae2ab2a585dfd19337\transformed\recyclerview-1.2.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\e452872bf1c6c06c71776c88e0bd7b6a\transformed\jetified-exoplayer-ui-2.18.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\e9de7db2640f13ae2ab2a585dfd19337\transformed\recyclerview-1.2.1\proguard.txt
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1505,8 +1506,11 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
public void suppressLayout(boolean);
public boolean isLayoutSuppressed();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e9de7db2640f13ae2ab2a585dfd19337\transformed\recyclerview-1.2.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\bb5ec4ef561b90312eb1ca52da1f144d\transformed\jetified-facebook-applinks-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\e9de7db2640f13ae2ab2a585dfd19337\transformed\recyclerview-1.2.1\proguard.txt
+# The proguard configuration file for the following section is D:\android project\pandorapan\TabLayout\build\intermediates\consumer_proguard_dir\release\exportReleaseConsumerProguardFiles\lib0\proguard.txt
+
+# End of content from D:\android project\pandorapan\TabLayout\build\intermediates\consumer_proguard_dir\release\exportReleaseConsumerProguardFiles\lib0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\bb5ec4ef561b90312eb1ca52da1f144d\transformed\jetified-facebook-applinks-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1547,8 +1551,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.applinks.AppLinks
-# End of content from C:\gradle-6.1.1\caches\transforms-3\bb5ec4ef561b90312eb1ca52da1f144d\transformed\jetified-facebook-applinks-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\88221c7028fd958b12579787bcf1d5e0\transformed\jetified-facebook-messenger-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\bb5ec4ef561b90312eb1ca52da1f144d\transformed\jetified-facebook-applinks-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\88221c7028fd958b12579787bcf1d5e0\transformed\jetified-facebook-messenger-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1593,8 +1597,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.facebook.messenger.Messenger
-# End of content from C:\gradle-6.1.1\caches\transforms-3\88221c7028fd958b12579787bcf1d5e0\transformed\jetified-facebook-messenger-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\d709769056a5279a71bbb18b41ee69d2\transformed\jetified-ui-1.0.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\88221c7028fd958b12579787bcf1d5e0\transformed\jetified-facebook-messenger-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\d709769056a5279a71bbb18b41ee69d2\transformed\jetified-ui-1.0.0\proguard.txt
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1623,16 +1627,16 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
android.view.View findViewByAccessibilityIdTraversal(int);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\d709769056a5279a71bbb18b41ee69d2\transformed\jetified-ui-1.0.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\3591196def6c89c6af74e7d30dfb6618\transformed\jetified-runtime-1.0.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\d709769056a5279a71bbb18b41ee69d2\transformed\jetified-ui-1.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\3591196def6c89c6af74e7d30dfb6618\transformed\jetified-runtime-1.0.0\proguard.txt
-assumenosideeffects public class androidx.compose.runtime.ComposerKt {
void sourceInformation(androidx.compose.runtime.Composer,java.lang.String);
void sourceInformationMarkerStart(androidx.compose.runtime.Composer,int,java.lang.String);
void sourceInformationMarkerEnd(androidx.compose.runtime.Composer);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\3591196def6c89c6af74e7d30dfb6618\transformed\jetified-runtime-1.0.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\7931210372c8927a076053831aae79b7\transformed\jetified-glide-transformations-3.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\3591196def6c89c6af74e7d30dfb6618\transformed\jetified-runtime-1.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\7931210372c8927a076053831aae79b7\transformed\jetified-glide-transformations-3.1.1\proguard.txt
-dontwarn jp.co.cyberagent.android.gpuimage.**
-keep public class * implements com.bumptech.glide.module.GlideModule
@@ -1642,8 +1646,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
public *;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\7931210372c8927a076053831aae79b7\transformed\jetified-glide-transformations-3.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a9e5e066cbda5595303140a83b7c357f\transformed\jetified-glide-4.12.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\7931210372c8927a076053831aae79b7\transformed\jetified-glide-transformations-3.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\a9e5e066cbda5595303140a83b7c357f\transformed\jetified-glide-4.12.0\proguard.txt
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
(...);
@@ -1659,8 +1663,44 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# Uncomment for DexGuard only
#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a9e5e066cbda5595303140a83b7c357f\transformed\jetified-glide-4.12.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\af9bdee4e01691bfa29595eaf6011f49\transformed\jetified-play-services-base-18.0.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\a9e5e066cbda5595303140a83b7c357f\transformed\jetified-glide-4.12.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\245cd6e28cb45ea53af06bd1902d8887\transformed\jetified-billing-7.0.0\proguard.txt
+# Keep the AIDL interface
+-keep class com.android.vending.billing.** { *; }
+
+-dontwarn javax.annotation.**
+-dontwarn org.checkerframework.**
+-dontwarn com.google.android.apps.common.proguard.UsedByReflection
+
+-keepnames class com.android.billingclient.api.ProxyBillingActivity
+-keepnames class com.android.billingclient.api.ProxyBillingActivityV2
+
+# Avoids Proguard warning at build time due to Protobuf use of sun.misc.Unsafe
+# and libcore.io.Memory which are available at runtime.
+-dontwarn libcore.io.Memory
+-dontwarn sun.misc.Unsafe
+
+
+# For Phenotype
+# An unused P/H transitive dependency: com.google.android.libraries.phenotype.registration.PhenotypeResourceReader is stripped out from all Granular normal deps and "can't find reference..." DepsVersionCompat test warning
+# is suppressed by ProGuard -dontwarn config.
+-dontwarn com.google.android.libraries.phenotype.registration.PhenotypeResourceReader
+-dontwarn com.google.android.apps.common.proguard.SideEffectFree
+
+# Uses reflection to determine if these classes are present and has a graceful
+# fallback if they aren't. The test failure it fixes appears to be caused by flogger.
+-dontwarn dalvik.system.VMStack
+-dontwarn com.google.common.flogger.backend.google.GooglePlatform
+-dontwarn com.google.common.flogger.backend.system.DefaultPlatform
+# We keep all fields for every generated proto file as the runtime uses
+# reflection over them that ProGuard cannot detect. Without this keep
+# rule, fields may be removed that would cause runtime failures.
+-keepclassmembers class * extends com.google.android.gms.internal.play_billing.zzcs {
+ ;
+}
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\245cd6e28cb45ea53af06bd1902d8887\transformed\jetified-billing-7.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\389aac78ceffe6f037f7624d2175f98b\transformed\jetified-play-services-base-18.3.0\proguard.txt
# b/35135904 Ensure that proguard will not strip the mResultGuardian.
-keepclassmembers class com.google.android.gms.common.api.internal.BasePendingResult {
com.google.android.gms.common.api.internal.BasePendingResult$ReleasableResultGuardian mResultGuardian;
@@ -1668,17 +1708,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-# End of content from C:\gradle-6.1.1\caches\transforms-3\af9bdee4e01691bfa29595eaf6011f49\transformed\jetified-play-services-base-18.0.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\53d8ae00710cb6dfde668ad5c2529a5c\transformed\jetified-play-services-measurement-21.1.1\proguard.txt
-# We keep all fields for every generated proto file as the runtime uses
-# reflection over them that ProGuard cannot detect. Without this keep
-# rule, fields may be removed that would cause runtime failures.
--keepclassmembers class * extends com.google.android.gms.internal.measurement.zzke {
- ;
-}
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\53d8ae00710cb6dfde668ad5c2529a5c\transformed\jetified-play-services-measurement-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\fdcd25b13ca01df0d64e21ab18452962\transformed\jetified-play-services-measurement-api-21.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\389aac78ceffe6f037f7624d2175f98b\transformed\jetified-play-services-base-18.3.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\fdcd25b13ca01df0d64e21ab18452962\transformed\jetified-play-services-measurement-api-21.1.1\proguard.txt
# Can be removed once we pull in a dependency on firebase-common that includes
# https://github.com/firebase/firebase-android-sdk/pull/1472/commits/856f1ca1151cdd88679bbc778892f23dfa34fc06#diff-a2ed34b5a38b4c6c686b09e54865eb48
-dontwarn com.google.auto.value.AutoValue
@@ -1691,27 +1722,18 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\fdcd25b13ca01df0d64e21ab18452962\transformed\jetified-play-services-measurement-api-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\d9a1fa15000998f069a9eb095ddd5d6c\transformed\jetified-play-services-measurement-sdk-21.1.1\proguard.txt
-# We keep all fields for every generated proto file as the runtime uses
-# reflection over them that ProGuard cannot detect. Without this keep
-# rule, fields may be removed that would cause runtime failures.
--keepclassmembers class * extends com.google.android.gms.internal.measurement.zzke {
- ;
-}
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\d9a1fa15000998f069a9eb095ddd5d6c\transformed\jetified-play-services-measurement-sdk-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\1b549d0d5a78f93d1b3cd259941d27d6\transformed\jetified-firebase-common-20.1.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\fdcd25b13ca01df0d64e21ab18452962\transformed\jetified-play-services-measurement-api-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\1b549d0d5a78f93d1b3cd259941d27d6\transformed\jetified-firebase-common-20.1.2\proguard.txt
-dontwarn com.google.firebase.platforminfo.KotlinDetector
-dontwarn com.google.auto.value.AutoValue
-dontwarn com.google.auto.value.AutoValue$Builder
-# End of content from C:\gradle-6.1.1\caches\transforms-3\1b549d0d5a78f93d1b3cd259941d27d6\transformed\jetified-firebase-common-20.1.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\4566a60c961a57d307c42a2fd5514004\transformed\jetified-play-services-tasks-18.0.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\1b549d0d5a78f93d1b3cd259941d27d6\transformed\jetified-firebase-common-20.1.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\1d73edc853ec5797eb8fbdbaf92a3a43\transformed\jetified-play-services-tasks-18.1.0\proguard.txt
-# End of content from C:\gradle-6.1.1\caches\transforms-3\4566a60c961a57d307c42a2fd5514004\transformed\jetified-play-services-tasks-18.0.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e3d5db4c204c05b688c67157d08d719e\transformed\jetified-play-services-measurement-impl-21.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\1d73edc853ec5797eb8fbdbaf92a3a43\transformed\jetified-play-services-tasks-18.1.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\53d8ae00710cb6dfde668ad5c2529a5c\transformed\jetified-play-services-measurement-21.1.1\proguard.txt
# We keep all fields for every generated proto file as the runtime uses
# reflection over them that ProGuard cannot detect. Without this keep
# rule, fields may be removed that would cause runtime failures.
@@ -1719,8 +1741,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e3d5db4c204c05b688c67157d08d719e\transformed\jetified-play-services-measurement-impl-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a14887389ea05f2c3a61b51470f02e11\transformed\jetified-play-services-measurement-sdk-api-21.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\53d8ae00710cb6dfde668ad5c2529a5c\transformed\jetified-play-services-measurement-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\d9a1fa15000998f069a9eb095ddd5d6c\transformed\jetified-play-services-measurement-sdk-21.1.1\proguard.txt
# We keep all fields for every generated proto file as the runtime uses
# reflection over them that ProGuard cannot detect. Without this keep
# rule, fields may be removed that would cause runtime failures.
@@ -1728,8 +1750,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a14887389ea05f2c3a61b51470f02e11\transformed\jetified-play-services-measurement-sdk-api-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a00f92aeac02d4041e8903bda4c31467\transformed\jetified-play-services-measurement-base-21.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\d9a1fa15000998f069a9eb095ddd5d6c\transformed\jetified-play-services-measurement-sdk-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\e3d5db4c204c05b688c67157d08d719e\transformed\jetified-play-services-measurement-impl-21.1.1\proguard.txt
# We keep all fields for every generated proto file as the runtime uses
# reflection over them that ProGuard cannot detect. Without this keep
# rule, fields may be removed that would cause runtime failures.
@@ -1737,8 +1759,26 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a00f92aeac02d4041e8903bda4c31467\transformed\jetified-play-services-measurement-base-21.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\98374b479c7a7c4245d90ea630585909\transformed\jetified-play-services-basement-18.1.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\e3d5db4c204c05b688c67157d08d719e\transformed\jetified-play-services-measurement-impl-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\a14887389ea05f2c3a61b51470f02e11\transformed\jetified-play-services-measurement-sdk-api-21.1.1\proguard.txt
+# We keep all fields for every generated proto file as the runtime uses
+# reflection over them that ProGuard cannot detect. Without this keep
+# rule, fields may be removed that would cause runtime failures.
+-keepclassmembers class * extends com.google.android.gms.internal.measurement.zzke {
+ ;
+}
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\a14887389ea05f2c3a61b51470f02e11\transformed\jetified-play-services-measurement-sdk-api-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\a00f92aeac02d4041e8903bda4c31467\transformed\jetified-play-services-measurement-base-21.1.1\proguard.txt
+# We keep all fields for every generated proto file as the runtime uses
+# reflection over them that ProGuard cannot detect. Without this keep
+# rule, fields may be removed that would cause runtime failures.
+-keepclassmembers class * extends com.google.android.gms.internal.measurement.zzke {
+ ;
+}
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\a00f92aeac02d4041e8903bda4c31467\transformed\jetified-play-services-measurement-base-21.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\6eda7df53f5a535e22df39c8e1d72650\transformed\jetified-play-services-basement-18.3.0\proguard.txt
# Needed when building against pre-Marshmallow SDK.
-dontwarn android.security.NetworkSecurityPolicy
@@ -1749,8 +1789,9 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-dontwarn sun.misc.Unsafe
-dontwarn libcore.io.Memory
-# Internal Google annotations for generating Proguard keep rules.
+# Annotations used during internal SDK shrinking.
-dontwarn com.google.android.apps.common.proguard.UsedBy*
+-dontwarn com.google.android.apps.common.proguard.SideEffectFree
# Annotations referenced by the SDK but whose definitions are contained in
# non-required dependencies.
@@ -1759,6 +1800,10 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-dontwarn com.google.errorprone.annotations.**
-dontwarn org.jspecify.nullness.NullMarked
+# Annotations no longer exist. Suppression prevents ProGuard failures in
+# SDKs which depend on earlier versions of play-services-basement.
+-dontwarn com.google.android.gms.common.util.VisibleForTesting
+
# Proguard flags for consumers of the Google Play services SDK
# https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project
@@ -1811,8 +1856,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-# End of content from C:\gradle-6.1.1\caches\transforms-3\98374b479c7a7c4245d90ea630585909\transformed\jetified-play-services-basement-18.1.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\8daf89c63ab14ea80f11dcfb9154f87e\transformed\fragment-1.5.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\6eda7df53f5a535e22df39c8e1d72650\transformed\jetified-play-services-basement-18.3.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\8daf89c63ab14ea80f11dcfb9154f87e\transformed\fragment-1.5.0\proguard.txt
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -1833,12 +1878,12 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
public ();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\8daf89c63ab14ea80f11dcfb9154f87e\transformed\fragment-1.5.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\b826addf48d922103bc9588ad90ee0e6\transformed\jetified-Common-4.1.11\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\8daf89c63ab14ea80f11dcfb9154f87e\transformed\fragment-1.5.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\b826addf48d922103bc9588ad90ee0e6\transformed\jetified-Common-4.1.11\proguard.txt
# 本库模块专用的混淆规则
-# End of content from C:\gradle-6.1.1\caches\transforms-3\b826addf48d922103bc9588ad90ee0e6\transformed\jetified-Common-4.1.11\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\cee8df21fdda9dd7e6106d8566e7a8de\transformed\jetified-facebook-core-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\b826addf48d922103bc9588ad90ee0e6\transformed\jetified-Common-4.1.11\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\cee8df21fdda9dd7e6106d8566e7a8de\transformed\jetified-facebook-core-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -1896,8 +1941,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
public ;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\cee8df21fdda9dd7e6106d8566e7a8de\transformed\jetified-facebook-core-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\570c85082e748d036cbe1ff0c9d5e429\transformed\lifecycle-viewmodel-2.5.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\cee8df21fdda9dd7e6106d8566e7a8de\transformed\jetified-facebook-core-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\570c85082e748d036cbe1ff0c9d5e429\transformed\lifecycle-viewmodel-2.5.0\proguard.txt
-keepclassmembers,allowobfuscation class * extends androidx.lifecycle.ViewModel {
();
}
@@ -1906,8 +1951,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
(android.app.Application);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\570c85082e748d036cbe1ff0c9d5e429\transformed\lifecycle-viewmodel-2.5.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\badee3548ba9b653d6517fdeb8829767\transformed\jetified-lifecycle-viewmodel-savedstate-2.5.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\570c85082e748d036cbe1ff0c9d5e429\transformed\lifecycle-viewmodel-2.5.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\badee3548ba9b653d6517fdeb8829767\transformed\jetified-lifecycle-viewmodel-savedstate-2.5.0\proguard.txt
-keepclassmembers,allowobfuscation class * extends androidx.lifecycle.ViewModel {
(androidx.lifecycle.SavedStateHandle);
}
@@ -1916,8 +1961,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
(android.app.Application,androidx.lifecycle.SavedStateHandle);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\badee3548ba9b653d6517fdeb8829767\transformed\jetified-lifecycle-viewmodel-savedstate-2.5.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\0e43e19966d3ba7fcce157667e087c7e\transformed\rules\lib\META-INF\com.android.tools\r8\coroutines.pro
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\badee3548ba9b653d6517fdeb8829767\transformed\jetified-lifecycle-viewmodel-savedstate-2.5.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\0e43e19966d3ba7fcce157667e087c7e\transformed\rules\lib\META-INF\com.android.tools\r8\coroutines.pro
# When editing this file, update the following files as well:
# - META-INF/proguard/coroutines.pro
# - META-INF/com.android.tools/proguard/coroutines.pro
@@ -1945,8 +1990,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# An annotation used for build tooling, won't be directly accessed.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-# End of content from C:\gradle-6.1.1\caches\transforms-3\0e43e19966d3ba7fcce157667e087c7e\transformed\rules\lib\META-INF\com.android.tools\r8\coroutines.pro
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\039aa78b17fc1889d62d4e8e7d7c1859\transformed\rules\lib\META-INF\com.android.tools\r8-from-1.6.0\coroutines.pro
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\0e43e19966d3ba7fcce157667e087c7e\transformed\rules\lib\META-INF\com.android.tools\r8\coroutines.pro
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\039aa78b17fc1889d62d4e8e7d7c1859\transformed\rules\lib\META-INF\com.android.tools\r8-from-1.6.0\coroutines.pro
# Allow R8 to optimize away the FastServiceLoader.
# Together with ServiceLoader optimization in R8
# this results in direct instantiation when loading Dispatchers.Main
@@ -1971,8 +2016,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
boolean getDEBUG() return false;
boolean getRECOVER_STACK_TRACES() return false;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\039aa78b17fc1889d62d4e8e7d7c1859\transformed\rules\lib\META-INF\com.android.tools\r8-from-1.6.0\coroutines.pro
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\33f970d366250728877e2f4671336331\transformed\jetified-twitter-core-3.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\039aa78b17fc1889d62d4e8e7d7c1859\transformed\rules\lib\META-INF\com.android.tools\r8-from-1.6.0\coroutines.pro
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\33f970d366250728877e2f4671336331\transformed\jetified-twitter-core-3.1.1\proguard.txt
#GSON
# Retain Annotations for model objects
-keepattributes *Annotation*
@@ -1996,8 +2041,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keepclasseswithmembers class * {
@retrofit2.http.* ;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\33f970d366250728877e2f4671336331\transformed\jetified-twitter-core-3.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\c77ecf57bcccb48a1c436095271858a9\transformed\rules\lib\META-INF\proguard\okhttp3.pro
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\33f970d366250728877e2f4671336331\transformed\jetified-twitter-core-3.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\c77ecf57bcccb48a1c436095271858a9\transformed\rules\lib\META-INF\proguard\okhttp3.pro
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
@@ -2010,16 +2055,16 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-# End of content from C:\gradle-6.1.1\caches\transforms-3\c77ecf57bcccb48a1c436095271858a9\transformed\rules\lib\META-INF\proguard\okhttp3.pro
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\ba2f6b8d754037d8f03e9dcac5bb54b5\transformed\rules\lib\META-INF\proguard\okio.pro
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\c77ecf57bcccb48a1c436095271858a9\transformed\rules\lib\META-INF\proguard\okhttp3.pro
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\ba2f6b8d754037d8f03e9dcac5bb54b5\transformed\rules\lib\META-INF\proguard\okio.pro
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
-# End of content from C:\gradle-6.1.1\caches\transforms-3\ba2f6b8d754037d8f03e9dcac5bb54b5\transformed\rules\lib\META-INF\proguard\okio.pro
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\acd3bab55cb4f819050ef57ea2e25987\transformed\jetified-beautysdk-202202241203\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\ba2f6b8d754037d8f03e9dcac5bb54b5\transformed\rules\lib\META-INF\proguard\okio.pro
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\acd3bab55cb4f819050ef57ea2e25987\transformed\jetified-beautysdk-202202241203\proguard.txt
-# End of content from C:\gradle-6.1.1\caches\transforms-3\acd3bab55cb4f819050ef57ea2e25987\transformed\jetified-beautysdk-202202241203\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\6905c56d188193f144e40adf093778f1\transformed\jetified-utilcode-1.30.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\acd3bab55cb4f819050ef57ea2e25987\transformed\jetified-beautysdk-202202241203\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\6905c56d188193f144e40adf093778f1\transformed\jetified-utilcode-1.30.0\proguard.txt
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in G:\Android_IDE\ADT\sdk/tools/proguard/proguard-android.txt
@@ -2048,8 +2093,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep @com.blankj.utilcode.util.ApiUtils$Api class *
-keepattributes *Annotation*
-# End of content from C:\gradle-6.1.1\caches\transforms-3\6905c56d188193f144e40adf093778f1\transformed\jetified-utilcode-1.30.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\b75b75d929caf1295aec25af1cc611a0\transformed\jetified-crash-1.0.8\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\6905c56d188193f144e40adf093778f1\transformed\jetified-utilcode-1.30.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\b75b75d929caf1295aec25af1cc611a0\transformed\jetified-crash-1.0.8\proguard.txt
-keep class cn.rongcloud.xcrash.NativeHandler {
native ;
void crashCallback(...);
@@ -2057,22 +2102,22 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
void traceCallbackBeforeDump(...);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\b75b75d929caf1295aec25af1cc611a0\transformed\jetified-crash-1.0.8\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a7d2b366ebb4fa695d83564a8f8d9b9e\transformed\jetified-roundedimageview-2.3.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\b75b75d929caf1295aec25af1cc611a0\transformed\jetified-crash-1.0.8\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\a7d2b366ebb4fa695d83564a8f8d9b9e\transformed\jetified-roundedimageview-2.3.0\proguard.txt
# Proguard configuration.
-dontwarn com.squareup.okhttp.**
# References to Picasso are okay if the consuming app doesn't use it
-dontwarn com.squareup.picasso.Transformation
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a7d2b366ebb4fa695d83564a8f8d9b9e\transformed\jetified-roundedimageview-2.3.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\54e4d6b7585273307d9c6823366d92b9\transformed\jetified-android-gif-drawable-1.2.23\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\a7d2b366ebb4fa695d83564a8f8d9b9e\transformed\jetified-roundedimageview-2.3.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\54e4d6b7585273307d9c6823366d92b9\transformed\jetified-android-gif-drawable-1.2.23\proguard.txt
-keep public class pl.droidsonroids.gif.GifIOException{(int, java.lang.String);}
#Prevents warnings for consumers not using AndroidX
-dontwarn androidx.annotation.**
-# End of content from C:\gradle-6.1.1\caches\transforms-3\54e4d6b7585273307d9c6823366d92b9\transformed\jetified-android-gif-drawable-1.2.23\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\11ff2b99188b7e7bf4e2771916717f0f\transformed\jetified-ShortcutBadger-1.1.22\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\54e4d6b7585273307d9c6823366d92b9\transformed\jetified-android-gif-drawable-1.2.23\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\11ff2b99188b7e7bf4e2771916717f0f\transformed\jetified-ShortcutBadger-1.1.22\proguard.txt
#https://github.com/leolin310148/ShortcutBadger/issues/46
-keep class me.leolin.shortcutbadger.impl.AdwHomeBadger { (...); }
-keep class me.leolin.shortcutbadger.impl.ApexHomeBadger { (...); }
@@ -2083,8 +2128,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class me.leolin.shortcutbadger.impl.SolidHomeBadger { (...); }
-keep class me.leolin.shortcutbadger.impl.SonyHomeBadger { (...); }
-keep class me.leolin.shortcutbadger.impl.XiaomiHomeBadger { (...); }
-# End of content from C:\gradle-6.1.1\caches\transforms-3\11ff2b99188b7e7bf4e2771916717f0f\transformed\jetified-ShortcutBadger-1.1.22\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\bf0366dad8fd25b42dec7a0b29d3ed94\transformed\jetified-EasyFloat-2.0.4\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\11ff2b99188b7e7bf4e2771916717f0f\transformed\jetified-ShortcutBadger-1.1.22\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\bf0366dad8fd25b42dec7a0b29d3ed94\transformed\jetified-EasyFloat-2.0.4\proguard.txt
# Add project specific ProGuard rules here.
# You can control the filterSet of applied configuration files using the
# proguardFiles setting in build.gradle.
@@ -2122,8 +2167,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# 保持反射不被混淆
-keepattributes EnclosingMethod
-# End of content from C:\gradle-6.1.1\caches\transforms-3\bf0366dad8fd25b42dec7a0b29d3ed94\transformed\jetified-EasyFloat-2.0.4\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\6dd79c19a3de7f7b4d3014c08d02f4ca\transformed\jetified-PagerGridLayoutManager-1.1.7\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\bf0366dad8fd25b42dec7a0b29d3ed94\transformed\jetified-EasyFloat-2.0.4\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\6dd79c19a3de7f7b4d3014c08d02f4ca\transformed\jetified-PagerGridLayoutManager-1.1.7\proguard.txt
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
@@ -2145,12 +2190,12 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-# End of content from C:\gradle-6.1.1\caches\transforms-3\6dd79c19a3de7f7b4d3014c08d02f4ca\transformed\jetified-PagerGridLayoutManager-1.1.7\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\adfc563cfaac18f99ab49176e8311139\transformed\jetified-WheelView-4.1.11\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\6dd79c19a3de7f7b4d3014c08d02f4ca\transformed\jetified-PagerGridLayoutManager-1.1.7\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\adfc563cfaac18f99ab49176e8311139\transformed\jetified-WheelView-4.1.11\proguard.txt
# 本库模块专用的混淆规则
-# End of content from C:\gradle-6.1.1\caches\transforms-3\adfc563cfaac18f99ab49176e8311139\transformed\jetified-WheelView-4.1.11\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\21d010a917a570a947ff266441748328\transformed\jetified-SudMGP-1.3.3.1158\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\adfc563cfaac18f99ab49176e8311139\transformed\jetified-WheelView-4.1.11\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\483c0844792efef20618064763675691\transformed\jetified-SudMGP-1.4.3.1201\proguard.txt
-keep class com.cocos.game.**{ *; }
-keep class tech.sud.runtime.**{ *; }
-keep class tech.sud.mgp.core.**{ *; }
@@ -2174,8 +2219,6 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-
-
-keep class tech.sud.runtime.launcherInterface.INativePlayer {
*;
}
@@ -2205,13 +2248,112 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
+
+
-keep class com.unity3d.** { *; }
-keep class tech.unity3d.** { *; }
-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+-keep class tech.sud.mgp.engine.hub.real.unity.activity.SudUnityPlayerActivity { *; }
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
-keep class bitter.jnibridge.* { *; }
-keep class com.unity3d.player.* { *; }
-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
@@ -2239,6 +2381,158 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+
+-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
+native ;
+}
+-keep public class com.tencent.aai.*
+-keep public class com.qq.wx.voice.*
+
+# SDK
+-keepclasseswithmembernames class com.tencent.aai.** { # 保持 native 方法不被混淆
+native ;
+}
+
+-keep public class com.tencent.aai.** {*;}
+-keep interface com.tencent.aai.audio.data.PcmAudioDataSource {
+ void start(); throws com.tencent.aai.exception.ClientException;
+}
+
+
+# SDK
+-keepclasseswithmembernames class com.tencent.aai.** { # 保持 native 方法不被混淆
+native ;
+}
+
+-keep public class com.tencent.aai.** {*;}
+-keep interface com.tencent.aai.audio.data.PcmAudioDataSource {
+ void start(); throws com.tencent.aai.exception.ClientException;
+}
+
+
+
+
+
@@ -2273,13 +2567,25 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
+
+
-keep class com.unity3d.** { *; }
-keep class tech.unity3d.** { *; }
-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+-keep class tech.sud.mgp.engine.hub.real.unity.activity.SudUnityPlayerActivity { *; }
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
-keep class bitter.jnibridge.* { *; }
-keep class com.unity3d.player.* { *; }
-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
@@ -2302,8 +2608,249 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-# End of content from C:\gradle-6.1.1\caches\transforms-3\21d010a917a570a947ff266441748328\transformed\jetified-SudMGP-1.3.3.1158\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\9bc6fb118e278279304d710763b86c85\transformed\jetified-SudASR-1.3.3.1158\proguard.txt
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+
+
+
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class com.unity3d.** { *; }
+-keep class tech.unity3d.** { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityMPPlayerActivity { *; }
+-keep class tech.sud.mgp.engine.hub.real.unitymp.service.SudUnityService { *; }
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+-keep class tech.sud.mgp.engine.hub.real.unity.running.UnityGameCustomCommandHandler { *; }
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+-keep class bitter.jnibridge.* { *; }
+-keep class com.unity3d.player.* { *; }
+-keep interface com.unity3d.player.IUnityPlayerLifecycleEvents { *; }
+-keep class org.fmod.* { *; }
+-keep class com.google.androidgamesdk.ChoreographerCallback { *; }
+-keep class com.google.androidgamesdk.SwappyDisplayManager { *; }
+-ignorewarnings
+
+
+
+
+
+
+-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
+native ;
+}
+-keep public class com.tencent.aai.*
+-keep public class com.qq.wx.voice.*
+
+# SDK
+-keepclasseswithmembernames class com.tencent.aai.** { # 保持 native 方法不被混淆
+native ;
+}
+
+-keep public class com.tencent.aai.** {*;}
+-keep interface com.tencent.aai.audio.data.PcmAudioDataSource {
+ void start(); throws com.tencent.aai.exception.ClientException;
+}
+
+
+# SDK
+-keepclasseswithmembernames class com.tencent.aai.** { # 保持 native 方法不被混淆
+native ;
+}
+
+-keep public class com.tencent.aai.** {*;}
+-keep interface com.tencent.aai.audio.data.PcmAudioDataSource {
+ void start(); throws com.tencent.aai.exception.ClientException;
+}
+
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\483c0844792efef20618064763675691\transformed\jetified-SudMGP-1.4.3.1201\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\9fef6e1dea59ce01cbe6739f12545786\transformed\jetified-SudASR-1.4.3.1201\proguard.txt
-keep class com.microsoft.cognitiveservices.** { *; }
-keep class tech.sud.mgp.asr.azure.** { *; }
@@ -2318,8 +2865,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
*** *Callback(long);
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\9bc6fb118e278279304d710763b86c85\transformed\jetified-SudASR-1.3.3.1158\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\d5594233d50b1d727f4630790ca89a13\transformed\jetified-core-8.7.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\9fef6e1dea59ce01cbe6739f12545786\transformed\jetified-SudASR-1.4.3.1201\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\d5594233d50b1d727f4630790ca89a13\transformed\jetified-core-8.7.0\proguard.txt
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
@@ -2346,8 +2893,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class com.faceunity.wrapper.faceunity {*;}
-keep class com.faceunity.wrapper.faceunity$RotatedImage {*;}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\d5594233d50b1d727f4630790ca89a13\transformed\jetified-core-8.7.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\526e7910eaa433763f36b642f34c1fee\transformed\jetified-exoplayer-core-2.18.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\d5594233d50b1d727f4630790ca89a13\transformed\jetified-core-8.7.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\526e7910eaa433763f36b642f34c1fee\transformed\jetified-exoplayer-core-2.18.2\proguard.txt
# Proguard rules specific to the core module.
# Constructors accessed via reflection in DefaultRenderersFactory
@@ -2404,8 +2951,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\526e7910eaa433763f36b642f34c1fee\transformed\jetified-exoplayer-core-2.18.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\2d16d937f787a1471d1fcefef8917ded\transformed\jetified-savedstate-1.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\526e7910eaa433763f36b642f34c1fee\transformed\jetified-exoplayer-core-2.18.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\2d16d937f787a1471d1fcefef8917ded\transformed\jetified-savedstate-1.2.0\proguard.txt
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -2424,8 +2971,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\2d16d937f787a1471d1fcefef8917ded\transformed\jetified-savedstate-1.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\f55e0290d55f2ec9dfa66384635c714c\transformed\transition-1.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\2d16d937f787a1471d1fcefef8917ded\transformed\jetified-savedstate-1.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\f55e0290d55f2ec9dfa66384635c714c\transformed\transition-1.2.0\proguard.txt
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -2445,8 +2992,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
androidx.transition.ChangeBounds$ViewBounds mViewBounds;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\f55e0290d55f2ec9dfa66384635c714c\transformed\transition-1.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\093cf4894c646f12adcf0608a8578513\transformed\vectordrawable-animated-1.1.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\f55e0290d55f2ec9dfa66384635c714c\transformed\transition-1.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\093cf4894c646f12adcf0608a8578513\transformed\vectordrawable-animated-1.1.0\proguard.txt
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -2467,8 +3014,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
*** get*();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\093cf4894c646f12adcf0608a8578513\transformed\vectordrawable-animated-1.1.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\3db9f5e64eaa2a61a80545d78dbfe4ed\transformed\jetified-facebook-bolts-15.2.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\093cf4894c646f12adcf0608a8578513\transformed\vectordrawable-animated-1.1.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\3db9f5e64eaa2a61a80545d78dbfe4ed\transformed\jetified-facebook-bolts-15.2.0\proguard.txt
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
@@ -2504,8 +3051,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
java.lang.Object readResolve();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\3db9f5e64eaa2a61a80545d78dbfe4ed\transformed\jetified-facebook-bolts-15.2.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\13795feba8dd8fc2e0266a202e40730e\transformed\media-1.6.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\3db9f5e64eaa2a61a80545d78dbfe4ed\transformed\jetified-facebook-bolts-15.2.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\13795feba8dd8fc2e0266a202e40730e\transformed\media-1.6.0\proguard.txt
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -2529,8 +3076,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class androidx.media.** implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\13795feba8dd8fc2e0266a202e40730e\transformed\media-1.6.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\4bf1220f49ce7953fbb445d1fb03d04a\transformed\core-1.8.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\13795feba8dd8fc2e0266a202e40730e\transformed\media-1.6.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\c6ec9c31a3362678dbcc66f2e9ea7260\transformed\core-1.10.1\proguard.txt
# Never inline methods, but allow shrinking and obfuscation.
-keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.view.ViewCompat$Api* {
;
@@ -2548,8 +3095,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
;
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\4bf1220f49ce7953fbb445d1fb03d04a\transformed\core-1.8.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\2c964f4aa7e08caf6a082be78fa332c4\transformed\lifecycle-runtime-2.5.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\c6ec9c31a3362678dbcc66f2e9ea7260\transformed\core-1.10.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\2c964f4aa7e08caf6a082be78fa332c4\transformed\lifecycle-runtime-2.5.0\proguard.txt
-keepattributes AnnotationDefault,
RuntimeVisibleAnnotations,
RuntimeVisibleParameterAnnotations,
@@ -2573,8 +3120,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# this rule is need to work properly when app is compiled with api 28, see b/142778206
# Also this rule prevents registerIn from being inlined.
-keepclassmembers class androidx.lifecycle.ReportFragment$LifecycleCallbacks { *; }
-# End of content from C:\gradle-6.1.1\caches\transforms-3\2c964f4aa7e08caf6a082be78fa332c4\transformed\lifecycle-runtime-2.5.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\4a3cce138aa30f2fd0df44bf999a62d2\transformed\jetified-exoplayer-datasource-2.18.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\2c964f4aa7e08caf6a082be78fa332c4\transformed\lifecycle-runtime-2.5.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\4a3cce138aa30f2fd0df44bf999a62d2\transformed\jetified-exoplayer-datasource-2.18.2\proguard.txt
# Proguard rules specific to the DataSource module.
# Constant folding for resource integers may mean that a resource passed to this method appears to be unused. Keep the method to prevent this from happening.
@@ -2588,8 +3135,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
();
}
-# End of content from C:\gradle-6.1.1\caches\transforms-3\4a3cce138aa30f2fd0df44bf999a62d2\transformed\jetified-exoplayer-datasource-2.18.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\cccc4dd1e5210aae5c702cc866696db2\transformed\jetified-exoplayer-extractor-2.18.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\4a3cce138aa30f2fd0df44bf999a62d2\transformed\jetified-exoplayer-datasource-2.18.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\cccc4dd1e5210aae5c702cc866696db2\transformed\jetified-exoplayer-extractor-2.18.2\proguard.txt
# Proguard rules specific to the extractor module.
# Methods accessed via reflection in DefaultExtractorsFactory
@@ -2607,8 +3154,8 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-dontwarn kotlin.annotations.jvm.**
-dontwarn javax.annotation.**
-# End of content from C:\gradle-6.1.1\caches\transforms-3\cccc4dd1e5210aae5c702cc866696db2\transformed\jetified-exoplayer-extractor-2.18.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\5bd9c5cbdf66400a7932d1da1691bac0\transformed\jetified-exoplayer-common-2.18.2\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\cccc4dd1e5210aae5c702cc866696db2\transformed\jetified-exoplayer-extractor-2.18.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\5bd9c5cbdf66400a7932d1da1691bac0\transformed\jetified-exoplayer-common-2.18.2\proguard.txt
# Proguard rules specific to the common module.
# Don't warn about checkerframework and Kotlin annotations
@@ -2632,20 +3179,30 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
# This is needed for ProGuard but not R8.
-keepclassmembernames class com.google.common.base.Function { *; }
-# End of content from C:\gradle-6.1.1\caches\transforms-3\5bd9c5cbdf66400a7932d1da1691bac0\transformed\jetified-exoplayer-common-2.18.2\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\25898cd92bff76be652caaeef3397500\transformed\versionedparcelable-1.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\5bd9c5cbdf66400a7932d1da1691bac0\transformed\jetified-exoplayer-common-2.18.2\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\25898cd92bff76be652caaeef3397500\transformed\versionedparcelable-1.1.1\proguard.txt
-keep class * implements androidx.versionedparcelable.VersionedParcelable
-keep public class android.support.**Parcelizer { *; }
-keep public class androidx.**Parcelizer { *; }
-keep public class androidx.versionedparcelable.ParcelImpl
-# End of content from C:\gradle-6.1.1\caches\transforms-3\25898cd92bff76be652caaeef3397500\transformed\versionedparcelable-1.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\8c49f53105b230fe43669879f576cab6\transformed\room-runtime-2.4.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\25898cd92bff76be652caaeef3397500\transformed\versionedparcelable-1.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\8c49f53105b230fe43669879f576cab6\transformed\room-runtime-2.4.0\proguard.txt
-keep class * extends androidx.room.RoomDatabase
-dontwarn androidx.room.paging.**
-# End of content from C:\gradle-6.1.1\caches\transforms-3\8c49f53105b230fe43669879f576cab6\transformed\room-runtime-2.4.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\48f6f745536202396d49c6664e656f00\transformed\jetified-startup-runtime-1.0.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\8c49f53105b230fe43669879f576cab6\transformed\room-runtime-2.4.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\c4bf50f4bef00295f739a61609b757c2\transformed\jetified-transport-backend-cct-3.1.8\proguard.txt
+-dontwarn com.google.auto.value.AutoValue
+-dontwarn com.google.auto.value.AutoValue$Builder
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\c4bf50f4bef00295f739a61609b757c2\transformed\jetified-transport-backend-cct-3.1.8\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\ad1f4a6564b34286db155b9a62614b62\transformed\jetified-transport-api-3.0.0\proguard.txt
+-dontwarn com.google.auto.value.AutoValue
+-dontwarn com.google.auto.value.AutoValue$Builder
+
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\ad1f4a6564b34286db155b9a62614b62\transformed\jetified-transport-api-3.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\48f6f745536202396d49c6664e656f00\transformed\jetified-startup-runtime-1.0.0\proguard.txt
# This Proguard rule ensures that ComponentInitializers are are neither shrunk nor obfuscated.
# This is because they are discovered and instantiated during application initialization.
-keep class * extends androidx.startup.Initializer {
@@ -2655,79 +3212,22 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-assumenosideeffects class androidx.startup.StartupLogger
-# End of content from C:\gradle-6.1.1\caches\transforms-3\48f6f745536202396d49c6664e656f00\transformed\jetified-startup-runtime-1.0.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\f137f81e3ba6bf4187612f01b8d596d6\transformed\jetified-transport-backend-cct-3.1.7\proguard.txt
--dontwarn com.google.auto.value.AutoValue
--dontwarn com.google.auto.value.AutoValue$Builder
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\f137f81e3ba6bf4187612f01b8d596d6\transformed\jetified-transport-backend-cct-3.1.7\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\ad1f4a6564b34286db155b9a62614b62\transformed\jetified-transport-api-3.0.0\proguard.txt
--dontwarn com.google.auto.value.AutoValue
--dontwarn com.google.auto.value.AutoValue$Builder
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\ad1f4a6564b34286db155b9a62614b62\transformed\jetified-transport-api-3.0.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e1bbd140b52a8e61bea52bf380947059\transformed\jetified-firebase-components-17.0.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\48f6f745536202396d49c6664e656f00\transformed\jetified-startup-runtime-1.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\e1bbd140b52a8e61bea52bf380947059\transformed\jetified-firebase-components-17.0.1\proguard.txt
-dontwarn com.google.firebase.components.Component$Instantiation
-dontwarn com.google.firebase.components.Component$ComponentType
-keep class * implements com.google.firebase.components.ComponentRegistrar
-keep,allowshrinking interface com.google.firebase.components.ComponentRegistrar
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e1bbd140b52a8e61bea52bf380947059\transformed\jetified-firebase-components-17.0.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\ff39e13547528b628eacff5bee8aa481\transformed\jetified-firebase-encoders-json-18.0.0\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\e1bbd140b52a8e61bea52bf380947059\transformed\jetified-firebase-components-17.0.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\ff39e13547528b628eacff5bee8aa481\transformed\jetified-firebase-encoders-json-18.0.0\proguard.txt
-# End of content from C:\gradle-6.1.1\caches\transforms-3\ff39e13547528b628eacff5bee8aa481\transformed\jetified-firebase-encoders-json-18.0.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\3b7d5c4af95619f43e4d0ea1cb1bf304\transformed\rules\lib\META-INF\proguard\androidx-annotations.pro
--keep,allowobfuscation @interface androidx.annotation.Keep
--keep @androidx.annotation.Keep class * {*;}
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\ff39e13547528b628eacff5bee8aa481\transformed\jetified-firebase-encoders-json-18.0.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\eb4fdf1a1abe4d45e8a1ea6c65e9f330\transformed\jetified-model-8.7.0\proguard.txt
--keepclasseswithmembers class * {
- @androidx.annotation.Keep ;
-}
-
--keepclasseswithmembers class * {
- @androidx.annotation.Keep ;
-}
-
--keepclasseswithmembers class * {
- @androidx.annotation.Keep (...);
-}
-
--keepclassmembers,allowobfuscation class * {
- @androidx.annotation.DoNotInline ;
-}
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\3b7d5c4af95619f43e4d0ea1cb1bf304\transformed\rules\lib\META-INF\proguard\androidx-annotations.pro
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e7e2a2183722056abf9bd4188272512b\transformed\jetified-annotation-experimental-1.1.0\proguard.txt
-# Copyright (C) 2020 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.
-
-# Ignore missing Kotlin meta-annotations so that this library can be used
-# without adding a compileOnly dependency on the Kotlin standard library.
--dontwarn kotlin.Deprecated
--dontwarn kotlin.Metadata
--dontwarn kotlin.ReplaceWith
--dontwarn kotlin.annotation.AnnotationRetention
--dontwarn kotlin.annotation.AnnotationTarget
--dontwarn kotlin.annotation.Retention
--dontwarn kotlin.annotation.Target
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e7e2a2183722056abf9bd4188272512b\transformed\jetified-annotation-experimental-1.1.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\eb4fdf1a1abe4d45e8a1ea6c65e9f330\transformed\jetified-model-8.7.0\proguard.txt
-
-# End of content from C:\gradle-6.1.1\caches\transforms-3\eb4fdf1a1abe4d45e8a1ea6c65e9f330\transformed\jetified-model-8.7.0\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\e4ea56c12de34fd26c2a84541f3aeb08\transformed\jetified-calligraphy3-3.1.1\proguard.txt
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\eb4fdf1a1abe4d45e8a1ea6c65e9f330\transformed\jetified-model-8.7.0\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\e4ea56c12de34fd26c2a84541f3aeb08\transformed\jetified-calligraphy3-3.1.1\proguard.txt
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Developer/android-sdk-osx/tools/proguard/proguard-android.txt
@@ -2749,17 +3249,28 @@ rx.internal.util.atomic.LinkedQueueNode* consumerNode;
-keep class io.github.inflationx.calligraphy3.* { *; }
-keep class io.github.inflationx.calligraphy3.*$* { *; }
-# End of content from C:\gradle-6.1.1\caches\transforms-3\e4ea56c12de34fd26c2a84541f3aeb08\transformed\jetified-calligraphy3-3.1.1\proguard.txt
-# The proguard configuration file for the following section is C:\gradle-6.1.1\caches\transforms-3\a358ff6705c32d8c6337aefd4316f1b9\transformed\jetified-billing-5.0.0\proguard.txt
-# Keep the AIDL interface
--keep class com.android.vending.billing.** { *; }
+# End of content from C:\Users\Administrator\.gradle\caches\transforms-3\e4ea56c12de34fd26c2a84541f3aeb08\transformed\jetified-calligraphy3-3.1.1\proguard.txt
+# The proguard configuration file for the following section is C:\Users\Administrator\.gradle\caches\transforms-3\6ee4aefc5377638487f62f6779665411\transformed\rules\lib\META-INF\proguard\androidx-annotations.pro
+-keep,allowobfuscation @interface androidx.annotation.Keep
+-keep @androidx.annotation.Keep class * {*;}
--dontwarn javax.annotation.**
--dontwarn org.checkerframework.**
--dontwarn com.google.android.apps.common.proguard.UsedByReflection
+-keepclasseswithmembers class * {
+ @androidx.annotation.Keep ;
+}
--keepnames class com.android.billingclient.api.ProxyBillingActivity
-# End of content from C:\gradle-6.1.1\caches\transforms-3\a358ff6705c32d8c6337aefd4316f1b9\transformed\jetified-billing-5.0.0\proguard.txt
+-keepclasseswithmembers class * {
+ @androidx.annotation.Keep ;
+}
+
+-keepclasseswithmembers class * {
+ @androidx.annotation.Keep (...);
+}
+
+-keepclassmembers,allowobfuscation class * {
+ @androidx.annotation.DoNotInline