{
+ 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/values-en/strings.xml b/Share/src/main/res/values-en/strings.xml
deleted file mode 100644
index 30573a84c..000000000
--- a/Share/src/main/res/values-en/strings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- 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..4c634d50f 100644
--- a/Share/src/main/res/values/strings.xml
+++ b/Share/src/main/res/values/strings.xml
@@ -1,3 +1,4 @@
+
ZWRrZnRUNlBlcHVxMXpsMzVmb2k6MTpjaQ
aq0eV4R1pqMK_AAeKRWnjPr7ErGMGgTPGgZJdm73WeRY-Kluws
@@ -22,4 +23,5 @@
分享成功
去聊聊
请选择好友
+
\ 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 @@
+
+
+
();}
+-ignorewarnings
+-keep class com.qiniu.**{*;}
+-keep class com.qiniu.**{public ();}
-ignorewarnings
\ No newline at end of file
diff --git a/common/src/main/assets/gift_live_naming_bg.svga b/common/src/main/assets/gift_live_naming_bg.svga
new file mode 100644
index 000000000..8f5b594ef
Binary files /dev/null and b/common/src/main/assets/gift_live_naming_bg.svga differ
diff --git a/common/src/main/assets/gift_live_naming_title_cn.svga b/common/src/main/assets/gift_live_naming_title_cn.svga
new file mode 100644
index 000000000..6cc2da491
Binary files /dev/null and b/common/src/main/assets/gift_live_naming_title_cn.svga differ
diff --git a/common/src/main/assets/gift_live_naming_title_en.svga b/common/src/main/assets/gift_live_naming_title_en.svga
new file mode 100644
index 000000000..548f31417
Binary files /dev/null and b/common/src/main/assets/gift_live_naming_title_en.svga differ
diff --git a/common/src/main/assets/gift_wall_gift_info_light.svga b/common/src/main/assets/gift_wall_gift_info_light.svga
new file mode 100644
index 000000000..6965e8c72
Binary files /dev/null and b/common/src/main/assets/gift_wall_gift_info_light.svga differ
diff --git a/common/src/main/assets/gift_wall_light_up.svga b/common/src/main/assets/gift_wall_light_up.svga
new file mode 100644
index 000000000..d62328461
Binary files /dev/null and b/common/src/main/assets/gift_wall_light_up.svga differ
diff --git a/common/src/main/java/com/yunbao/common/Constants.java b/common/src/main/java/com/yunbao/common/Constants.java
index 8fe6ee4db..775acb274 100644
--- a/common/src/main/java/com/yunbao/common/Constants.java
+++ b/common/src/main/java/com/yunbao/common/Constants.java
@@ -20,6 +20,7 @@ public class Constants {
public static final String AVATAR = "avatar";
public static final String SIGN = "sign";
public static final String TO_UID = "toUid";
+ public static final String TO_UNAME = "toUserName";
public static final String INTOINDEX = "intoIndex";
public static final String FROM_LIVE_ROOM = "fromLiveRoom";
public static final String TO_NAME = "toName";
@@ -150,6 +151,7 @@ public class Constants {
public static final String SOCKET_LIVE_DRPK_RANDOM = "LiveRandomPK";//随机PK
public static final String SOCKET_LEAVE_ROOM = "disconnect";//用户离开房间
public static final String SOCKET_LIVE_END = "StartEndLive";//主播关闭直播
+ public static final String SOCKET_LIVE_END_CLOSE = "StartEndLiveClose";//主播关闭直播
public static final String SOCKET_SYSTEM = "SystemNot";//系统消息
public static final String UP_USER_LIST = "upuserlist";//更新用戶列表
public static final String LIAN_MAI = "LivePKDRLM";//用户连麦
diff --git a/common/src/main/java/com/yunbao/common/activity/AbsActivity.java b/common/src/main/java/com/yunbao/common/activity/AbsActivity.java
index f4ac8a40b..1fd935eca 100644
--- a/common/src/main/java/com/yunbao/common/activity/AbsActivity.java
+++ b/common/src/main/java/com/yunbao/common/activity/AbsActivity.java
@@ -12,25 +12,30 @@ import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.view.DisplayCutout;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
+import com.yunbao.common.utils.DpUtil;
import com.yunbao.common.utils.MobclickAgent;
import com.yunbao.common.R;
import com.yunbao.common.glide.ImgLoader;
import com.yunbao.common.interfaces.LifeCycleListener;
import com.yunbao.common.manager.IMLoginManager;
import com.yunbao.common.utils.ClickUtil;
+import com.yunbao.common.utils.ToastUtil;
import java.util.ArrayList;
import java.util.List;
@@ -301,6 +306,25 @@ public abstract class AbsActivity extends AppCompatActivity {
return getCurrentNavigationBarHeight(((Activity) context));
}
+ public static int getNavigationStatusBarHeight(Context context) {
+ int notchHeight = 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ WindowInsets windowInsets = ((Activity) context).getWindow().getDecorView().getRootWindowInsets();
+ if (windowInsets != null) {
+ DisplayCutout displayCutout = windowInsets.getDisplayCutout();
+ if (displayCutout != null) {
+ notchHeight = displayCutout.getSafeInsetTop();
+ }
+ }
+ }
+ if (notchHeight != 0) {
+ return notchHeight;
+ }
+ Rect rect = new Rect();
+ ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+ return rect.top;
+ }
+
/**
* 全面屏(是否开启全面屏开关 0 关闭 1 开启)
*
diff --git a/common/src/main/java/com/yunbao/common/activity/WebViewActivity.java b/common/src/main/java/com/yunbao/common/activity/WebViewActivity.java
index e01cf045d..946591739 100644
--- a/common/src/main/java/com/yunbao/common/activity/WebViewActivity.java
+++ b/common/src/main/java/com/yunbao/common/activity/WebViewActivity.java
@@ -88,6 +88,7 @@ public class WebViewActivity extends AbsActivity {
@Override
public void setStatusBar() {
+ super.setStatusBar();
// getWindow().setStatusBarColor(Color.parseColor("#FFFFFF"));
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -147,8 +148,7 @@ public class WebViewActivity extends AbsActivity {
if (url.contains("for")) {
mWebView.loadUrl("javascript:goAnchorTab()");
}
-
-
+ view.loadUrl("javascript:setTop(" + DpUtil.dp2px(15) + ")");
if(url.startsWith(HtmlConfig.SHOP)){
//商店页不做动态变换
return;
diff --git a/common/src/main/java/com/yunbao/common/adapter/BaseAdapter.java b/common/src/main/java/com/yunbao/common/adapter/BaseAdapter.java
index e53971c5b..ba0cc148f 100644
--- a/common/src/main/java/com/yunbao/common/adapter/BaseAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/BaseAdapter.java
@@ -9,7 +9,7 @@ import java.util.HashMap;
import java.util.List;
public abstract class BaseAdapter extends RecyclerView.Adapter {
- private Context context;
+ public Context context;
public List data;
public BaseAdapter(Context context, List data) {
@@ -34,7 +34,7 @@ public abstract class BaseAdapter extends RecyclerView.Adapter extends RecyclerView.Adapter giftQuantityModels;
+ private Context mContext;
+ private OnItemClickListener onItemClickListener;
+
+ public GiftWallAchieveAdapter(List giftQuantityModels, Context context) {
+ this.giftQuantityModels = giftQuantityModels;
+ this.mContext = context;
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View robotSayHelloView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_gift_wall_achieve_item, parent, false);
+ return new GiftWallAchieveViewHolder(robotSayHelloView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ GiftWallAchieveViewHolder giftWallAchieveViewHolder = (GiftWallAchieveViewHolder) holder;
+ giftWallAchieveViewHolder.showData(giftQuantityModels.get(position));
+ }
+
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ this.onItemClickListener = onItemClickListener;
+ }
+
+ @Override
+ public int getItemCount() {
+ return giftQuantityModels.size();
+ }
+
+ class GiftWallAchieveViewHolder extends RecyclerView.ViewHolder {
+ private TextView achieveName;
+ private ImageView achieveImg;
+
+ private ImageView achieveImgLock;
+
+ public GiftWallAchieveViewHolder(@NonNull View itemView) {
+ super(itemView);
+ itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (onItemClickListener != null) {
+ onItemClickListener.onItemClick(getAdapterPosition());
+ }
+ }
+ });
+ achieveName = itemView.findViewById(R.id.achieveName);
+ achieveImg = itemView.findViewById(R.id.achieve_img);
+ achieveImgLock = itemView.findViewById(R.id.achieve_img_lock);
+ }
+
+ public void showData(UserMedalListModel quantityModel) {
+ achieveName.setText(quantityModel.getDressName());
+ ImgLoader.display(mContext, quantityModel.getDisplaySrc(), achieveImg);
+ achieveImgLock.setVisibility(quantityModel.getDressStatus().equals("1") ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ public interface OnItemClickListener {
+ void onItemClick(int position);
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/adapter/GiftWallGiftInfoListItemAdapter.java b/common/src/main/java/com/yunbao/common/adapter/GiftWallGiftInfoListItemAdapter.java
new file mode 100644
index 000000000..d49706220
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/adapter/GiftWallGiftInfoListItemAdapter.java
@@ -0,0 +1,159 @@
+package com.yunbao.common.adapter;
+
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallInfoBean;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.WordUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class GiftWallGiftInfoListItemAdapter extends RecyclerView.Adapter {
+ List data = new ArrayList<>();
+ boolean isAnchor;
+ int list_type = 1;
+ private boolean isLiveRoom;
+ private boolean isStar;
+ int giftStatus;
+ private String anchorName;
+ private String anchorAvatar;
+
+ public void setAnchorName(String anchorName) {
+ this.anchorName = anchorName;
+ }
+
+ public void setAnchorAvatar(String anchorAvatar) {
+ this.anchorAvatar = anchorAvatar;
+ }
+
+ public void setGiftStatus(int giftStatus) {
+ this.giftStatus = giftStatus;
+ }
+
+ public void setAnchor(boolean anchor) {
+ isAnchor = anchor;
+ }
+
+ public void setList_type(int list_type) {
+ this.list_type = list_type;
+ }
+
+ public void setLiveRoom(boolean liveRoom) {
+ isLiveRoom = liveRoom;
+ }
+
+ public void setStar(boolean star) {
+ isStar = star;
+ }
+
+ public void setData(List data) {
+ if (data == null) {
+ data = new ArrayList<>();
+ }
+ if (data.isEmpty()) {
+ GiftWallInfoBean.Data tmp = new GiftWallInfoBean.Data();
+ tmp.setId(-1);
+ data.add(tmp);
+ }
+ this.data = data;
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new VH(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dialog_gift_wall_gift_info, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ holder.setData(data.get(position), position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return data.size();
+ }
+
+ public class VH extends RecyclerView.ViewHolder {
+ TextView tv_rank, user_name, tv_rename, anchor_name;
+ RoundedImageView avatar, avatar2;
+
+ public VH(@NonNull View itemView) {
+ super(itemView);
+ tv_rank = itemView.findViewById(R.id.tv_rank);
+ user_name = itemView.findViewById(R.id.user_name);
+ tv_rename = itemView.findViewById(R.id.tv_rename);
+ avatar = itemView.findViewById(R.id.avatar);
+ avatar2 = itemView.findViewById(R.id.avatar2);
+ anchor_name = itemView.findViewById(R.id.item_anchor_name);
+ }
+
+ public void setData(GiftWallInfoBean.Data data, int position) {
+ user_name.setText("");
+ anchor_name.setText("");
+ tv_rank.setText("");
+ avatar.setVisibility(View.INVISIBLE);
+ avatar2.setVisibility(View.INVISIBLE);
+ if (data.getId() == -1) {
+ tv_rank.setText("");
+ tv_rename.setText("");
+ user_name.setTextColor(Color.parseColor("#A2A2A2"));
+ avatar.setVisibility(View.GONE);
+ if (list_type == 1) {
+ user_name.setText(WordUtil.getNewString(R.string.dialog_gift_wall_assistance_wait));
+ } else if (!isStar) {
+ user_name.setText(WordUtil.getNewString(R.string.dialog_gift_wall_classic_wait));
+ } else {
+ user_name.setText(WordUtil.getNewString(R.string.dialog_gift_wall_tab2_list_wait));
+ }
+ return;
+ }
+ anchor_name.setVisibility(View.GONE);
+ if (isStar && list_type == 2) {
+ avatar.setVisibility(View.VISIBLE);
+ ImgLoader.display(itemView.getContext(), data.getLive_avatar(), avatar);
+ anchor_name.setText(data.getLive_user_name());
+ if (data.getGift_hall_rank_hide() == 1 && !data.getUser_id().equals(IMLoginManager.get(itemView.getContext()).getUserInfo().getId() + "")) {
+ avatar2.setImageResource(R.mipmap.hide);
+ user_name.setText(WordUtil.getNewString(R.string.mystery_man));
+ } else {
+ ImgLoader.display(itemView.getContext(), data.getAvatar(), avatar2);
+ user_name.setText(data.getUser_name());
+ }
+ anchor_name.setVisibility(View.VISIBLE);
+ avatar2.setVisibility(View.VISIBLE);
+ } else {
+ avatar2.setVisibility(View.INVISIBLE);
+ anchor_name.setVisibility(View.GONE);
+ avatar.setVisibility(View.VISIBLE);
+ if (data.getGift_hall_rank_hide() == 1 && !data.getUser_id().equals(IMLoginManager.get(itemView.getContext()).getUserInfo().getId() + "")) {
+ avatar.setImageResource(R.mipmap.hide);
+ user_name.setText(WordUtil.getNewString(R.string.mystery_man));
+ } else {
+ ImgLoader.display(itemView.getContext(), data.getAvatar(), avatar);
+ user_name.setText(data.getUser_name());
+ }
+ }
+ user_name.setTextColor(Color.parseColor("#FFFFFF"));
+ tv_rank.setText(String.format(Locale.getDefault(), "%d", (position + 1)));
+ tv_rank.setTextColor(Color.parseColor("#FCC755"));
+ tv_rank.setTextSize(20);
+ tv_rename.setText(String.format(Locale.getDefault(), "%s", (data.getGift_hall_send_numForString())));
+ avatar.setVisibility(View.VISIBLE);
+ }
+
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab1List2Adapter.java b/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab1List2Adapter.java
new file mode 100644
index 000000000..66f55d9e7
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab1List2Adapter.java
@@ -0,0 +1,213 @@
+package com.yunbao.common.adapter;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.opensource.svgaplayer.SVGACallback;
+import com.opensource.svgaplayer.SVGADrawable;
+import com.opensource.svgaplayer.SVGAImageView;
+import com.opensource.svgaplayer.SVGAParser;
+import com.opensource.svgaplayer.SVGAVideoEntity;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallBean;
+import com.yunbao.common.dialog.GiftWallGiftInfoDialog;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.manager.base.ACache;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.SVGAViewUtils;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GiftWallMainTab1List2Adapter extends RecyclerView.Adapter {
+ Context mContext;
+ List list;
+ boolean isStar;
+ SVGAVideoEntity drawable;
+ String toUid;
+ String anchorId;
+ boolean isAnchor;
+ private boolean isLiveRoom;
+
+ public GiftWallMainTab1List2Adapter(Context mContext) {
+ this.mContext = mContext;
+ list = new ArrayList<>();
+ }
+
+ public void setToUid(String toUid) {
+ this.toUid = toUid;
+ }
+
+ public void setAnchor(boolean anchor) {
+ isAnchor = anchor;
+ }
+
+ public void setAnchorId(String anchorId) {
+ this.anchorId = anchorId;
+ }
+
+ public void setList(List list) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ this.list = list;
+ notifyDataSetChanged();
+ }
+
+ public void setDrawable(SVGAVideoEntity drawable) {
+ this.drawable = drawable;
+ }
+
+ public void setStar(boolean star) {
+ isStar = star;
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+
+ return new VH(LayoutInflater.from(mContext).inflate(R.layout.item_gift_wall_man_tab1_list_2, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ holder.setData(list.get(position), position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return list.size();
+ }
+
+ @Override
+ public void onViewAttachedToWindow(@NonNull VH holder) {
+ super.onViewAttachedToWindow(holder);
+ holder.giftBg.startAnimation();
+ }
+
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull VH holder) {
+ super.onViewDetachedFromWindow(holder);
+ holder.giftBg.stopAnimation();
+
+ }
+
+ public void setLiveRoom(boolean isLiveRoom) {
+ this.isLiveRoom = isLiveRoom;
+ }
+
+ public void addList(List gifts) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ int index = list.size() - 1;
+ list.addAll(gifts);
+ notifyItemRangeChanged(index, gifts.size());
+ }
+
+ public class VH extends RecyclerView.ViewHolder {
+ SVGAImageView giftBg;
+ ImageView gift_soles;
+ ImageView giftImage;
+ TextView gift_name;
+ TextView gift_status;
+ ProgressBar progressBar;
+
+ public VH(View itemView) {
+ super(itemView);
+ giftBg = itemView.findViewById(R.id.gift_bg);
+ gift_soles = itemView.findViewById(R.id.gift_soles);
+ giftImage = itemView.findViewById(R.id.gift);
+ gift_name = itemView.findViewById(R.id.gift_name);
+ gift_status = itemView.findViewById(R.id.gift_status);
+ progressBar = itemView.findViewById(R.id.progressBar);
+ }
+
+ @SuppressLint("DefaultLocale")
+ public void setData(GiftWallBean.Gift gift, int position) {
+ gift_name.setText(WordUtil.isNewZh() ? gift.getGift_name() : gift.getGift_name_en());
+ ImgLoader.display(itemView.getContext(), gift.getGift_icon(), giftImage, 40, 40);
+ giftBg.setClearsAfterDetached(false);
+ giftBg.setClearsAfterStop(false);
+ progressBar.setVisibility(View.GONE);
+ if (isAnchor) {
+ progressBar.setMax(gift.getIlluminate_num());
+ progressBar.setProgress(gift.getGift_hall_send_num());
+ }else{
+ progressBar.setMax(1);
+ }
+ progressBar.setVisibility(View.VISIBLE);
+ if (gift.getIlluminate_status() == 1) {
+ gift_status.setText(String.format("%s%s", WordUtil.getNewString(R.string.dialog_gift_wall_list_spinner_up), gift.getGift_hall_send_numForString()));
+ gift_status.setTextColor(Color.parseColor("#FFFFFF"));
+ gift_soles.setImageResource(getSolesrRes());
+ if (drawable != null) {
+ giftBg.post(() -> {
+ giftBg.setImageDrawable(new SVGADrawable(drawable));
+ giftBg.setLoops(0);
+ giftBg.startAnimation();
+ });
+ }
+ if(!isAnchor){
+ progressBar.setProgress(1);
+ }
+ } else {
+ if (isAnchor) {
+ gift_status.setText(String.format("%s %s/%s",
+ WordUtil.getNewString(R.string.dialog_gift_wall_list_spinner_down2),
+ gift.getGift_hall_send_numForString(),
+ gift.getIlluminate_num()
+ ));
+ } else {
+ progressBar.setProgress(0);
+ gift_status.setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_spinner_down));
+ }
+ gift_status.setTextColor(Color.parseColor("#01071A"));
+ gift_soles.setImageResource(getUnSolesrRes());
+ giftBg.setImageResource(R.mipmap.gift_wall_main_item_bg1);
+ }
+ ViewClicksAntiShake.clicksAntiShake(itemView, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ new GiftWallGiftInfoDialog(mContext, gift.getGift_id() + "", toUid, isAnchor)
+ .setFullWindows(!isLiveRoom)
+ .setLiveRoom(isLiveRoom)
+ .setAnchorId(anchorId)
+ .setStar(isStar)
+ .showDialog();
+ }
+ });
+ }
+
+ private int getSolesrRes() {
+ return isStar ? R.mipmap.gift_wall_main_item_select : R.mipmap.gift_wall_main_item_select1;
+ }
+
+ private int getUnSolesrRes() {
+ return isStar ? R.mipmap.gift_wall_main_item_unselect : R.mipmap.gift_wall_main_item_unselect1;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab2ListAdapter.java b/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab2ListAdapter.java
new file mode 100644
index 000000000..e43f7cf9d
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/adapter/GiftWallMainTab2ListAdapter.java
@@ -0,0 +1,271 @@
+package com.yunbao.common.adapter;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestBuilder;
+import com.bumptech.glide.load.DataSource;
+import com.bumptech.glide.load.DecodeFormat;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.engine.GlideException;
+import com.bumptech.glide.request.RequestListener;
+import com.bumptech.glide.request.target.Target;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.opensource.svgaplayer.SVGADrawable;
+import com.opensource.svgaplayer.SVGAImageView;
+import com.opensource.svgaplayer.SVGAVideoEntity;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallBean;
+import com.yunbao.common.bean.GiftWallTab2Bean;
+import com.yunbao.common.bean.JsWishBean;
+import com.yunbao.common.dialog.GiftWallGiftInfoDialog;
+import com.yunbao.common.dialog.GiftWallMainTab2ClassicInfoDialog;
+import com.yunbao.common.dialog.GiftWallTab2List2Dialog;
+import com.yunbao.common.event.ClosePopupDialogEvent;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.Bus;
+import com.yunbao.common.utils.StringUtil;
+import com.yunbao.common.utils.ToastUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class GiftWallMainTab2ListAdapter extends RecyclerView.Adapter {
+ Context mContext;
+ List list;
+ boolean isStar;
+ String toUid;
+ String anchorId;
+ boolean isAnchor;
+ private boolean isLiveRoom;
+ boolean isNowRank;
+
+ public GiftWallMainTab2ListAdapter(Context mContext) {
+ this.mContext = mContext;
+ list = new ArrayList<>();
+ }
+
+ public void setNowRank(boolean nowRank) {
+ isNowRank = nowRank;
+ }
+
+ public void setToUid(String toUid) {
+ this.toUid = toUid;
+ }
+
+ public void setAnchor(boolean anchor) {
+ isAnchor = anchor;
+ }
+
+ public void setAnchorId(String anchorId) {
+ this.anchorId = anchorId;
+ }
+
+ public void setList(List list) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ this.list = list;
+ notifyDataSetChanged();
+ }
+
+ public void addList(List gifts) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ int index = list.size() - 1;
+ list.addAll(gifts);
+ notifyItemRangeChanged(index, gifts.size());
+ }
+
+
+ public void setStar(boolean star) {
+ isStar = star;
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ if (isStar) {
+ return new VH(LayoutInflater.from(mContext).inflate(R.layout.item_gift_wall_man_tab2_list_1, parent, false));
+ }
+ return new VH(LayoutInflater.from(mContext).inflate(R.layout.item_gift_wall_man_tab2_list_2, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ holder.setData(list.get(position), position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return list.size();
+ }
+
+ @Override
+ public void onViewAttachedToWindow(@NonNull VH holder) {
+ super.onViewAttachedToWindow(holder);
+ }
+
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull VH holder) {
+ super.onViewDetachedFromWindow(holder);
+
+ }
+
+ public void setLiveRoom(boolean isLiveRoom) {
+ this.isLiveRoom = isLiveRoom;
+ }
+
+ public void clear() {
+ list.clear();
+ notifyDataSetChanged();
+ }
+
+ public class VH extends RecyclerView.ViewHolder {
+ ImageView gift;
+ TextView gift_name;
+ TextView gift_number;
+ RoundedImageView user1Avatar, user2Avatar;
+ TextView anchor_nickname;
+ TextView user_nickname;
+ TextView tv_wait;
+ View imageView8;
+
+ public VH(View itemView) {
+ super(itemView);
+
+ gift = itemView.findViewById(R.id.gift);
+ gift_name = itemView.findViewById(R.id.gift_name);
+ gift_number = itemView.findViewById(R.id.gift_number);
+ user1Avatar = itemView.findViewById(R.id.user1_avatar);
+ user2Avatar = itemView.findViewById(R.id.user2_avatar);
+ anchor_nickname = itemView.findViewById(R.id.anchor_nickname);
+ user_nickname = itemView.findViewById(R.id.user_nickname);
+ tv_wait = itemView.findViewById(R.id.tv_wait);
+ imageView8 = itemView.findViewById(R.id.imageView8);
+ }
+
+ @SuppressLint("DefaultLocale")
+ public void setData(GiftWallTab2Bean.Gift giftData, int position) {
+ gift_name.setText(WordUtil.isNewZh() ? giftData.getGiftName() : giftData.getGiftNameEn());
+ display(itemView.getContext(), giftData.getGiftIcon(), gift, -1,-1);
+ if (!StringUtil.isEmpty(giftData.getNamingLiveNicename(), giftData.getNamingUserNicename())) {
+ anchor_nickname.setVisibility(View.VISIBLE);
+ user_nickname.setVisibility(View.VISIBLE);
+ gift_number.setVisibility(View.VISIBLE);
+ user1Avatar.setVisibility(View.VISIBLE);
+ user2Avatar.setVisibility(View.VISIBLE);
+ imageView8.setVisibility(View.VISIBLE);
+ tv_wait.setVisibility(View.GONE);
+ gift_number.setText(String.format(Locale.getDefault(), "%d", giftData.getGiftHallSendNum()));
+ if (giftData.getNamingLiveActiveRankHide() == 1 && giftData.getNamingLiveId()!= IMLoginManager.get(mContext).getUserInfo().getId()) {
+ user1Avatar.setImageResource(R.mipmap.hide);
+ anchor_nickname.setText(WordUtil.getNewString(R.string.mystery_man));
+ } else {
+ display(mContext, giftData.getNamingLiveAvatar(), user1Avatar, 60, 60);
+ anchor_nickname.setText(giftData.getNamingLiveNicename());
+ }
+ if (giftData.getNamingUserActiveRankHide() == 1&& giftData.getNamingUserId()!= IMLoginManager.get(mContext).getUserInfo().getId()) {
+ user2Avatar.setImageResource(R.mipmap.hide);
+ user_nickname.setText(WordUtil.getNewString(R.string.mystery_man));
+ } else {
+ display(mContext, giftData.getNamingUserAvatar(), user2Avatar, 60, 60);
+ user_nickname.setText(giftData.getNamingUserNicename());
+ }
+ } else {
+ user1Avatar.setVisibility(View.GONE);
+ user2Avatar.setVisibility(View.GONE);
+ anchor_nickname.setVisibility(View.GONE);
+ user_nickname.setVisibility(View.GONE);
+ gift_number.setVisibility(View.GONE);
+ imageView8.setVisibility(View.GONE);
+ tv_wait.setVisibility(View.VISIBLE);
+ itemView.setOnClickListener(null);
+ }
+ ViewClicksAntiShake.clicksAntiShake(itemView, () -> {
+ if (isStar) {
+ if (isNowRank) {
+ if (StringUtil.isEmpty(giftData.getNamingLiveNicename(), giftData.getNamingUserNicename()) && isLiveRoom) {
+ Bus.get().post(new JsWishBean(giftData.getGiftId() + ""));
+ Bus.get().post(new ClosePopupDialogEvent());
+ } else {
+ new GiftWallGiftInfoDialog(mContext, giftData.getGiftId() + "", toUid, isAnchor)
+ .setFullWindows(!isLiveRoom)
+ .setAnchorId(anchorId)
+ .setTab2Enter(true)
+ .setLiveRoom(isLiveRoom)
+ .setStar(isStar)
+ .showDialog();
+ }
+ } else {
+ new GiftWallMainTab2ClassicInfoDialog(mContext, giftData, isAnchor).setFullWindows(!isLiveRoom).showDialog();
+ }
+ } else {
+ if (isNowRank) {
+ new GiftWallGiftInfoDialog(mContext, giftData.getGiftId() + "", toUid, isAnchor)
+ .setFullWindows(!isLiveRoom)
+ .setAnchorId(anchorId)
+ .setTab2Enter(true)
+ .setLiveRoom(isLiveRoom)
+ .setStar(isStar)
+ .showDialog();
+ } else {
+ new GiftWallTab2List2Dialog(mContext).setGift(giftData).showDialog();
+ }
+ }
+ });
+ }
+
+ void display(Context context, String url, ImageView imageView, int width, int height) {
+ imageView.post(new Runnable() {
+ @Override
+ public void run() {
+ RequestBuilder builder = Glide.with(context)
+ .load(url);
+
+ if (width != -1 && height != -1) {
+ builder = builder.override(width, height);
+ }
+ builder
+ .thumbnail(1.0f)
+ .format(DecodeFormat.PREFER_RGB_565)
+ .skipMemoryCache(true)
+ .addListener(new RequestListener() {
+ @Override
+ public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
+ imageView.setImageDrawable(null);
+ return false;
+ }
+
+ @Override
+ public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
+ return false;
+ }
+ })
+ .diskCacheStrategy(DiskCacheStrategy.ALL)
+ .into(imageView);
+ }
+ });
+
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/adapter/GiftWallTab2GiftInfoListItemAdapter.java b/common/src/main/java/com/yunbao/common/adapter/GiftWallTab2GiftInfoListItemAdapter.java
new file mode 100644
index 000000000..d988eac39
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/adapter/GiftWallTab2GiftInfoListItemAdapter.java
@@ -0,0 +1,91 @@
+package com.yunbao.common.adapter;
+
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallInfoBean;
+import com.yunbao.common.bean.GiftWallMainTab2ClassicInfoBean;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.utils.RouteUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class GiftWallTab2GiftInfoListItemAdapter extends RecyclerView.Adapter {
+ List data = new ArrayList<>();
+
+ public void setData(List data) {
+ if (data == null || data.isEmpty()) {
+ data = new ArrayList<>();
+ GiftWallMainTab2ClassicInfoBean.GiftData giftData=new GiftWallMainTab2ClassicInfoBean.GiftData();
+ giftData.setUserId("-1");
+ data.add(giftData);
+ }
+ this.data = data;
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new VH(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dialog_gift_wall_tab2_gift_info, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ holder.setData(data.get(position), position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return data.size();
+ }
+
+ public class VH extends RecyclerView.ViewHolder {
+ TextView tv_rank, user_name, tv_rename;
+ RoundedImageView avatar;
+
+ public VH(@NonNull View itemView) {
+ super(itemView);
+ tv_rank = itemView.findViewById(R.id.tv_rank);
+ user_name = itemView.findViewById(R.id.user_name);
+ tv_rename = itemView.findViewById(R.id.tv_rename);
+ avatar = itemView.findViewById(R.id.avatar);
+ }
+
+ public void setData(GiftWallMainTab2ClassicInfoBean.GiftData data, int position) {
+ tv_rank.setText(String.format(Locale.getDefault(), "%d", (position + 4)));
+ tv_rank.setTextColor(Color.parseColor("#FCC755"));
+ tv_rank.setTextSize(20);
+ tv_rename.setText(String.format(Locale.getDefault(), "%s", (data.getGiftHallSendNumForString())));
+ avatar.setVisibility(View.VISIBLE);
+ if (data.getActiveRankHide() == 1) {
+ user_name.setText(WordUtil.getNewString(R.string.mystery_man));
+ avatar.setImageResource(R.mipmap.hide);
+ } else {
+ user_name.setText(data.getUserName());
+ ImgLoader.display(itemView.getContext(), data.getAvatar(), avatar);
+ }
+ ViewClicksAntiShake.clicksAntiShake(avatar, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ if(data.getActiveRankHide()==0){
+ RouteUtil.forwardUserHome(itemView.getContext(), String.valueOf(data.getUserId()), 0);
+ }
+ }
+ });
+ }
+
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/adapter/InteractionGamesAdapter.java b/common/src/main/java/com/yunbao/common/adapter/InteractionGamesAdapter.java
index bbbc9e328..1143372ba 100644
--- a/common/src/main/java/com/yunbao/common/adapter/InteractionGamesAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/InteractionGamesAdapter.java
@@ -13,6 +13,7 @@ import com.yunbao.common.R;
import com.yunbao.common.bean.CustomSidebarChildModel;
import com.yunbao.common.event.CustomDrawerPopupEvent;
import com.yunbao.common.utils.Bus;
+import com.yunbao.common.utils.SpUtil;
import com.yunbao.common.views.InteractionGamesChildViewHolder;
import java.util.ArrayList;
@@ -36,7 +37,7 @@ public class InteractionGamesAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View runGamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_role_fun_games_child_view3, parent, false);
- return new InteractionGamesChildViewHolder(runGamesView);
+ return new InteractionGamesChildViewHolder(runGamesView,mContext);
}
@Override
@@ -51,6 +52,9 @@ public class InteractionGamesAdapter extends RecyclerView.Adapter {
if (activityID != 0) {
Bus.get().post(new CustomDrawerPopupEvent()
.setDisMiss(true).setInteractionID(activityID).setInteraction(true).setChild(srcChild));
+ if(model.getSudGameIsNew().equals("1")){
+ SpUtil.getInstance().setLiveGameId(model.getId());
+ }
}
diff --git a/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleFunGamesAdapter.java b/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleFunGamesAdapter.java
index 54c1f1c45..077196417 100644
--- a/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleFunGamesAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleFunGamesAdapter.java
@@ -31,11 +31,16 @@ public class LiveNewRoleFunGamesAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View runGamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_role_fun_games_child_view, parent, false);
- return new NewRoleFunGamesChildViewHolder(runGamesView,showRed);
+ return new NewRoleFunGamesChildViewHolder(runGamesView,showRed,mContext);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams((int)
+ (mContext.getResources().getDisplayMetrics().widthPixels / 4.5),
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ holder.itemView.setLayoutParams(layoutParams);
+
NewRoleFunGamesChildViewHolder childViewHolder = (NewRoleFunGamesChildViewHolder) holder;
childViewHolder.setData(child.get(position), rigts);
}
diff --git a/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleInteractionGamesAdapter.java b/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleInteractionGamesAdapter.java
index 3d17bf60e..7950a02ca 100644
--- a/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleInteractionGamesAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/LiveNewRoleInteractionGamesAdapter.java
@@ -11,11 +11,11 @@ import androidx.recyclerview.widget.RecyclerView;
import com.yunbao.common.R;
import com.yunbao.common.bean.CustomSidebarChildModel;
-import com.yunbao.common.event.CustomDrawerPopupEvent;
import com.yunbao.common.event.LiveNewRoleEvent;
import com.yunbao.common.event.NewRoleCustomDrawerPopupEvent;
import com.yunbao.common.utils.Bus;
-import com.yunbao.common.views.InteractionGamesChildViewHolder;
+import com.yunbao.common.utils.SpUtil;
+import com.yunbao.common.views.InteractionGamesChildBottomViewHolder;
import java.util.ArrayList;
import java.util.List;
@@ -34,14 +34,14 @@ public class LiveNewRoleInteractionGamesAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View runGamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_role_fun_games_child_view3, parent, false);
- return new InteractionGamesChildViewHolder(runGamesView);
+ return new InteractionGamesChildBottomViewHolder(runGamesView,mContext);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
- InteractionGamesChildViewHolder childViewHolder = (InteractionGamesChildViewHolder) holder;
+ InteractionGamesChildBottomViewHolder childViewHolder = (InteractionGamesChildBottomViewHolder) holder;
childViewHolder.setData(child.get(position), rigts);
- childViewHolder.setItemViewClicks(new InteractionGamesChildViewHolder.InteractionGamesCallBack() {
+ childViewHolder.setItemViewClicks(new InteractionGamesChildBottomViewHolder.InteractionGamesCallBack() {
@Override
public void onItemViewClicks(CustomSidebarChildModel model, boolean rigts) {
@@ -52,6 +52,9 @@ public class LiveNewRoleInteractionGamesAdapter extends RecyclerView.Adapter {
.setInteractionID(activityID)
.setChild(child)
.setInteraction(true));
+ if(model.getSudGameIsNew().equals("1")){
+ SpUtil.getInstance().setLiveGameId(model.getId());
+ }
}
@@ -60,12 +63,14 @@ public class LiveNewRoleInteractionGamesAdapter extends RecyclerView.Adapter {
});
}
+
@Override
public int getItemCount() {
return child.size();
}
public void updateData(List mChild) {
+
child.clear();
/* if (mChild.size() > 8) {
for (int i = 0; i < 8; i++) {
diff --git a/common/src/main/java/com/yunbao/common/adapter/LiveNewRolerPopupAdapter.java b/common/src/main/java/com/yunbao/common/adapter/LiveNewRolerPopupAdapter.java
index ef0105714..91f5e4ca7 100644
--- a/common/src/main/java/com/yunbao/common/adapter/LiveNewRolerPopupAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/LiveNewRolerPopupAdapter.java
@@ -39,13 +39,14 @@ public class LiveNewRolerPopupAdapter extends RecyclerView.Adapter {
switch (viewType) {
case FUN_GAMES:
View runGamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_new_roler_fun_games_view, parent, false);
- return new LiveNewRoleFunGamesViewHolder(runGamesView);
+ return new LiveNewRoleFunGamesViewHolder(runGamesView,mContext);
case RIGHTS_INTERESTS:
+ //特权
View rightsInterestsView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_roler_ights_interests, parent, false);
- return new LiveNewRoleRigtsInterestsViewHolder(rightsInterestsView,showRed);
+ return new LiveNewRoleRigtsInterestsViewHolder(rightsInterestsView,showRed,mContext);
default:
View gamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_role_interaction_games_view, parent, false);
- return new LiveNewRoleInteractionGamesViewHolder(gamesView);
+ return new LiveNewRoleInteractionGamesViewHolder(gamesView,mContext);
}
}
diff --git a/common/src/main/java/com/yunbao/common/adapter/NewRoleFunGamesAdapter.java b/common/src/main/java/com/yunbao/common/adapter/NewRoleFunGamesAdapter.java
index d473abe0b..9f5e5aaad 100644
--- a/common/src/main/java/com/yunbao/common/adapter/NewRoleFunGamesAdapter.java
+++ b/common/src/main/java/com/yunbao/common/adapter/NewRoleFunGamesAdapter.java
@@ -30,11 +30,15 @@ public class NewRoleFunGamesAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View runGamesView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_live_new_role_fun_games_child_view2, parent, false);
- return new NewRoleFunGamesChildViewHolder(runGamesView,false);
+ return new NewRoleFunGamesChildViewHolder(runGamesView,false,mContext);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams((int)
+ (mContext.getResources().getDisplayMetrics().widthPixels / 4.5),
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ holder.itemView.setLayoutParams(layoutParams);
NewRoleFunGamesChildViewHolder childViewHolder = (NewRoleFunGamesChildViewHolder) holder;
childViewHolder.setData(child.get(position), rigts);
}
diff --git a/common/src/main/java/com/yunbao/common/adapter/SudGameAdapter.java b/common/src/main/java/com/yunbao/common/adapter/SudGameAdapter.java
new file mode 100644
index 000000000..fa2341323
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/adapter/SudGameAdapter.java
@@ -0,0 +1,70 @@
+package com.yunbao.common.adapter;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.view.View;
+
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.appcompat.widget.AppCompatTextView;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.SudSettleBean;
+import com.yunbao.common.glide.ImgLoader;
+
+import java.util.List;
+
+public class SudGameAdapter extends BaseAdapter {
+ public SudGameAdapter(Context context, List data) {
+ super(context, data);
+ }
+
+ private AppCompatImageView sub_rank_image;
+ private RoundedImageView sub_head;
+ private AppCompatTextView sub_rank_text,sub_name,sub_score;
+
+ @SuppressLint("SetTextI18n")
+ @Override
+ public void convert(BaseAdapter.BaseViewHolder holder, SudSettleBean item) {
+ sub_rank_image = (AppCompatImageView) holder.getView(R.id.sub_rank_image);
+ sub_rank_text = (AppCompatTextView) holder.getView(R.id.sub_rank_text);
+ sub_head = (RoundedImageView) holder.getView(R.id.sub_head);
+ sub_name = (AppCompatTextView) holder.getView(R.id.sub_name);
+ sub_score = (AppCompatTextView) holder.getView(R.id.sub_score);
+
+ switch (item.getRank()){
+ case 1:
+ sub_rank_text.setVisibility(View.GONE);
+ sub_rank_image.setVisibility(View.VISIBLE);
+ sub_rank_image.setImageResource(R.mipmap.sub_1);
+ break;
+ case 2:
+ sub_rank_text.setVisibility(View.GONE);
+ sub_rank_image.setVisibility(View.VISIBLE);
+ sub_rank_image.setImageResource(R.mipmap.sub_2);
+ break;
+ case 3:
+ sub_rank_text.setVisibility(View.GONE);
+ sub_rank_image.setVisibility(View.VISIBLE);
+ sub_rank_image.setImageResource(R.mipmap.sub_3);
+ break;
+ default:
+ sub_rank_text.setVisibility(View.VISIBLE);
+ sub_rank_image.setVisibility(View.GONE);
+ sub_rank_text.setText(String.valueOf(item.getRank()));
+ break;
+ }
+
+ ImgLoader.display(context, item.getAvatar_url(),sub_head);
+ sub_name.setText(item.getNick_name());
+ if (item.getWin_num()>0){
+ sub_score.setText("+"+item.getWin_num());
+ }else {
+ sub_score.setText(String.valueOf(item.getWin_num()));
+ }
+ }
+
+ @Override
+ public int getItemLayoutId() {
+ return R.layout.view_sub_rank;
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/BanDownLiveEvent.java b/common/src/main/java/com/yunbao/common/bean/BanDownLiveEvent.java
new file mode 100644
index 000000000..53d9a72db
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/BanDownLiveEvent.java
@@ -0,0 +1,47 @@
+package com.yunbao.common.bean;
+
+public class BanDownLiveEvent extends BaseModel{
+ private String reason,reasonContent,content,timer;
+
+ public BanDownLiveEvent() {
+ }
+
+ public BanDownLiveEvent(String reason, String reasonContent, String content, String timer) {
+ this.reason = reason;
+ this.reasonContent = reasonContent;
+ this.content = content;
+ this.timer = timer;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
+ public String getReasonContent() {
+ return reasonContent;
+ }
+
+ public void setReasonContent(String reasonContent) {
+ this.reasonContent = reasonContent;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getTimer() {
+ return timer;
+ }
+
+ public void setTimer(String timer) {
+ this.timer = timer;
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/CheckLiveModel.java b/common/src/main/java/com/yunbao/common/bean/CheckLiveModel.java
index 4b4f7ca30..2d7d00c3e 100644
--- a/common/src/main/java/com/yunbao/common/bean/CheckLiveModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/CheckLiveModel.java
@@ -2,7 +2,6 @@ package com.yunbao.common.bean;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
-import com.yunbao.common.BuildConfig;
public class CheckLiveModel extends BaseModel {
diff --git a/common/src/main/java/com/yunbao/common/bean/ConfigBean.java b/common/src/main/java/com/yunbao/common/bean/ConfigBean.java
index ec6d14242..497026ce5 100644
--- a/common/src/main/java/com/yunbao/common/bean/ConfigBean.java
+++ b/common/src/main/java/com/yunbao/common/bean/ConfigBean.java
@@ -2,7 +2,6 @@ package com.yunbao.common.bean;
import com.alibaba.fastjson.annotation.JSONField;
import com.google.gson.annotations.SerializedName;
-import com.yunbao.common.BuildConfig;
import com.yunbao.common.utils.StringUtil;
import java.util.Arrays;
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftNamingInfoModel.java b/common/src/main/java/com/yunbao/common/bean/GiftNamingInfoModel.java
index 1c238d98a..c8dd2d111 100644
--- a/common/src/main/java/com/yunbao/common/bean/GiftNamingInfoModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/GiftNamingInfoModel.java
@@ -1,5 +1,8 @@
package com.yunbao.common.bean;
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.annotation.JSONField;
import com.google.gson.annotations.SerializedName;
public class GiftNamingInfoModel extends BaseModel {
@@ -44,9 +47,9 @@ public class GiftNamingInfoModel extends BaseModel {
private String giftStartTime;
@SerializedName("gift_end_time")
private String giftEndTime;
- @SerializedName("naming_liveuid")
+ @SerializedName("naming_live_id")
private String namingLiveuid;
- @SerializedName("naming_uid")
+ @SerializedName("naming_user_id")
private String namingUid;
@SerializedName("naming_live_name")
private String namingLiveName;
@@ -68,6 +71,28 @@ public class GiftNamingInfoModel extends BaseModel {
private String namingLiveCoin;
@SerializedName("isweek")
private String isweek;
+ @JSONField(name = "naming_user_gift_hall_rank_hide")
+ @SerializedName("naming_user_gift_hall_rank_hide")
+ private int naming_user_gift_hall_rank_hide;
+ @JSONField(name = "naming_live_gift_hall_rank_hide")
+ @SerializedName("naming_live_gift_hall_rank_hide")
+ private int naming_live_gift_hall_rank_hide;
+
+ public int getNaming_user_gift_hall_rank_hide() {
+ return naming_user_gift_hall_rank_hide;
+ }
+
+ public void setNaming_user_gift_hall_rank_hide(int naming_user_gift_hall_rank_hide) {
+ this.naming_user_gift_hall_rank_hide = naming_user_gift_hall_rank_hide;
+ }
+
+ public int getNaming_live_gift_hall_rank_hide() {
+ return naming_live_gift_hall_rank_hide;
+ }
+
+ public void setNaming_live_gift_hall_rank_hide(int naming_live_gift_hall_rank_hide) {
+ this.naming_live_gift_hall_rank_hide = naming_live_gift_hall_rank_hide;
+ }
public String getId() {
return id;
@@ -304,6 +329,10 @@ public class GiftNamingInfoModel extends BaseModel {
}
public String getNamingStatus() {
+ //后端反馈 namingStatus 已经无效了,需要判断冠名主播id和冠名用户id是否为0
+ if(TextUtils.equals(namingLiveuid,"0")||TextUtils.equals(namingUid,"0")){
+ return "0";
+ }
return namingStatus;
}
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftWallBean.java b/common/src/main/java/com/yunbao/common/bean/GiftWallBean.java
new file mode 100644
index 000000000..69f0a459e
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/GiftWallBean.java
@@ -0,0 +1,261 @@
+package com.yunbao.common.bean;
+
+import com.yunbao.common.utils.StringUtil;
+
+import java.util.List;
+
+public class GiftWallBean extends BaseModel {
+ private IlluminateData illuminate_data;
+ private int gift_hall_rank_hide;
+
+
+ public GiftWallBean() {
+ }
+
+ public IlluminateData getIlluminate_data() {
+ return illuminate_data;
+ }
+
+ public void setIlluminate_data(IlluminateData illuminate_data) {
+ this.illuminate_data = illuminate_data;
+ }
+
+ public int getGift_hall_rank_hide() {
+ return gift_hall_rank_hide;
+ }
+
+ public void setGift_hall_rank_hide(int gift_hall_rank_hide) {
+ this.gift_hall_rank_hide = gift_hall_rank_hide;
+ }
+
+ public static class IlluminateData {
+ private List week_star_data;
+ private List gift_data;
+ private int week_gift_illuminate_num;
+ private int week_star_gift_num;
+ private int gift_illuminate_num;
+ private int gift_num;
+ private String gift_hall_start_date;
+ private String gift_hall_end_date;
+
+
+ public IlluminateData() {
+ }
+
+ public String getGift_hall_start_date() {
+ if (!StringUtil.isEmpty("gift_hall_start_date")) {
+ gift_hall_start_date = gift_hall_start_date.replace("-", "/");
+ }
+ return gift_hall_start_date;
+ }
+
+ public void setGift_hall_start_date(String gift_hall_start_date) {
+ this.gift_hall_start_date = gift_hall_start_date;
+ }
+
+ public String getGift_hall_end_date() {
+ if (!StringUtil.isEmpty("gift_hall_end_date")) {
+ gift_hall_end_date = gift_hall_end_date.replace("-", "/");
+ }
+ return gift_hall_end_date;
+ }
+
+ public void setGift_hall_end_date(String gift_hall_end_date) {
+ this.gift_hall_end_date = gift_hall_end_date;
+ }
+
+ public List getWeek_star_data() {
+ return week_star_data;
+ }
+
+ public void setWeek_star_data(List week_star_data) {
+ this.week_star_data = week_star_data;
+ }
+
+ public List getGift_data() {
+ return gift_data;
+ }
+
+ public void setGift_data(List gift_data) {
+ this.gift_data = gift_data;
+ }
+
+ public int getWeek_gift_illuminate_num() {
+ return week_gift_illuminate_num;
+ }
+
+ public void setWeek_gift_illuminate_num(int week_gift_illuminate_num) {
+ this.week_gift_illuminate_num = week_gift_illuminate_num;
+ }
+
+ public int getWeek_star_gift_num() {
+ return week_star_gift_num;
+ }
+
+ public void setWeek_star_gift_num(int week_star_gift_num) {
+ this.week_star_gift_num = week_star_gift_num;
+ }
+
+ public int getGift_illuminate_num() {
+ return gift_illuminate_num;
+ }
+
+ public void setGift_illuminate_num(int gift_illuminate_num) {
+ this.gift_illuminate_num = gift_illuminate_num;
+ }
+
+ public int getGift_num() {
+ return gift_num;
+ }
+
+ public void setGift_num(int gift_num) {
+ this.gift_num = gift_num;
+ }
+ }
+
+ public static class Gift {
+ private int gift_id;
+ private int sendtype;
+ private String gift_name;
+ private long need_coin; // 注意:这里可能需要更改为long类型,因为666666超过了int的最大值
+ private String gift_icon;
+ private int week_start_level;
+ private int illuminate_num;
+ private int gift_hall_type;
+ private String gift_name_en;
+ private String gift_hall_start; // 使用Java 8的LocalDate来处理日期
+ private String gift_hall_end;
+ private int gift_hall_send_num;
+ private int illuminate_status;
+ private long needcoin_total;
+
+ public Gift() {
+ }
+
+ public String getGift_hall_start() {
+ if (!StringUtil.isEmpty(gift_hall_start)) {
+ gift_hall_start = gift_hall_start.replace("-", "/");
+ }
+ return gift_hall_start;
+ }
+
+ public String getGift_hall_end() {
+ if (!StringUtil.isEmpty(gift_hall_end)) {
+ gift_hall_end = gift_hall_end.replace("-", "/");
+ }
+ return gift_hall_end;
+ }
+
+ public int getGift_id() {
+ return gift_id;
+ }
+
+ public void setGift_id(int gift_id) {
+ this.gift_id = gift_id;
+ }
+
+ public int getSendtype() {
+ return sendtype;
+ }
+
+ public void setSendtype(int sendtype) {
+ this.sendtype = sendtype;
+ }
+
+ public String getGift_name() {
+ return gift_name;
+ }
+
+ public void setGift_name(String gift_name) {
+ this.gift_name = gift_name;
+ }
+
+ public long getNeed_coin() {
+ return need_coin;
+ }
+
+ public void setNeed_coin(long need_coin) {
+ this.need_coin = need_coin;
+ }
+
+ public String getGift_icon() {
+ return gift_icon;
+ }
+
+ public void setGift_icon(String gift_icon) {
+ this.gift_icon = gift_icon;
+ }
+
+ public int getWeek_start_level() {
+ return week_start_level;
+ }
+
+ public void setWeek_start_level(int week_start_level) {
+ this.week_start_level = week_start_level;
+ }
+
+ public int getIlluminate_num() {
+ return illuminate_num;
+ }
+
+ public void setIlluminate_num(int illuminate_num) {
+ this.illuminate_num = illuminate_num;
+ }
+
+ public int getGift_hall_type() {
+ return gift_hall_type;
+ }
+
+ public void setGift_hall_type(int gift_hall_type) {
+ this.gift_hall_type = gift_hall_type;
+ }
+
+ public String getGift_name_en() {
+ return gift_name_en;
+ }
+
+ public void setGift_name_en(String gift_name_en) {
+ this.gift_name_en = gift_name_en;
+ }
+
+ public void setGift_hall_start(String gift_hall_start) {
+ this.gift_hall_start = gift_hall_start;
+ }
+
+
+ public void setGift_hall_end(String gift_hall_end) {
+ this.gift_hall_end = gift_hall_end;
+ }
+
+ public int getGift_hall_send_num() {
+ return gift_hall_send_num;
+ }
+
+ public String getGift_hall_send_numForString() {
+ if (gift_hall_send_num > 999) {
+ return "999+";
+ }
+ return gift_hall_send_num + "";
+ }
+
+ public void setGift_hall_send_num(int gift_hall_send_num) {
+ this.gift_hall_send_num = gift_hall_send_num;
+ }
+
+ public int getIlluminate_status() {
+ return illuminate_status;
+ }
+
+ public void setIlluminate_status(int illuminate_status) {
+ this.illuminate_status = illuminate_status;
+ }
+
+ public long getNeedcoin_total() {
+ return needcoin_total;
+ }
+
+ public void setNeedcoin_total(long needcoin_total) {
+ this.needcoin_total = needcoin_total;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftWallForUserBean.java b/common/src/main/java/com/yunbao/common/bean/GiftWallForUserBean.java
new file mode 100644
index 000000000..efe70ed51
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/GiftWallForUserBean.java
@@ -0,0 +1,114 @@
+package com.yunbao.common.bean;
+
+import java.util.List;
+
+public class GiftWallForUserBean extends BaseModel {
+ private List illuminate_data;
+ private int active_rank_hide;
+
+ public GiftWallForUserBean() {
+ }
+
+ public List getIlluminate_data() {
+ return illuminate_data;
+ }
+
+ public void setIlluminate_data(List illuminate_data) {
+ this.illuminate_data = illuminate_data;
+ }
+
+ public int getActive_rank_hide() {
+ return active_rank_hide;
+ }
+
+ public void setActive_rank_hide(int active_rank_hide) {
+ this.active_rank_hide = active_rank_hide;
+ }
+
+ public static class Gift {
+ private String giftname;
+ private String giftname_en;
+ private String gifticon;
+ private int needcoin;
+ private int needcoin_total;
+ private int gift_hall_send_num;
+ private int illuminate_status;
+ private int gift_id;
+ private int id;
+
+ public Gift() {
+ }
+
+ public String getGiftname() {
+ return giftname;
+ }
+
+ public void setGiftname(String giftname) {
+ this.giftname = giftname;
+ }
+
+ public String getGiftname_en() {
+ return giftname_en;
+ }
+
+ public void setGiftname_en(String giftname_en) {
+ this.giftname_en = giftname_en;
+ }
+
+ public String getGifticon() {
+ return gifticon;
+ }
+
+ public void setGifticon(String gifticon) {
+ this.gifticon = gifticon;
+ }
+
+ public int getNeedcoin() {
+ return needcoin;
+ }
+
+ public void setNeedcoin(int needcoin) {
+ this.needcoin = needcoin;
+ }
+
+ public int getNeedcoin_total() {
+ return needcoin_total;
+ }
+
+ public void setNeedcoin_total(int needcoin_total) {
+ this.needcoin_total = needcoin_total;
+ }
+
+ public int getGift_hall_send_num() {
+ return gift_hall_send_num;
+ }
+
+ public void setGift_hall_send_num(int gift_hall_send_num) {
+ this.gift_hall_send_num = gift_hall_send_num;
+ }
+
+ public int getIlluminate_status() {
+ return illuminate_status;
+ }
+
+ public void setIlluminate_status(int illuminate_status) {
+ this.illuminate_status = illuminate_status;
+ }
+
+ public int getGift_id() {
+ return gift_id;
+ }
+
+ public void setGift_id(int gift_id) {
+ this.gift_id = gift_id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftWallInfoBean.java b/common/src/main/java/com/yunbao/common/bean/GiftWallInfoBean.java
new file mode 100644
index 000000000..4a5ea34ab
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/GiftWallInfoBean.java
@@ -0,0 +1,331 @@
+package com.yunbao.common.bean;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.google.gson.annotations.SerializedName;
+import com.yunbao.common.utils.StringUtil;
+
+import java.util.List;
+
+public class GiftWallInfoBean extends BaseModel {
+ @SerializedName("gift_info")
+ private GiftInfo gift_info;
+ @SerializedName("data")
+ private List data;
+ @SerializedName("is_me")
+ private int is_me;
+
+ // 一般情况下,我们会添加getter和setter方法,但根据你的要求,这里省略
+
+
+ @JSONField(name = "gift_info")
+ public GiftInfo getGift_info() {
+ return gift_info;
+ }
+
+ @JSONField(name = "gift_info")
+ public void setGift_info(GiftInfo gift_info) {
+ this.gift_info = gift_info;
+ }
+
+ @JSONField(name = "data")
+ public List getData() {
+ /* if (data == null || data.isEmpty()) {
+ data = new ArrayList<>();
+ for (int i = 0; i < 20; i++) {
+ Data item = new Data();
+ item.setId(i);
+ item.setActive_rank_hide(i % 4 == 0 ? 0 : 1);
+ item.setUser_name("用户:" + i);
+ item.setGift_hall_send_num(RandomUtil.nextInt(100000));
+ item.setAvatar("https://downs.yaoulive.com/manfive.png");
+ data.add(item);
+ }
+ }*/
+ return data;
+ }
+
+ @JSONField(name = "data")
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public int getIs_me() {
+ return is_me;
+ }
+
+ public void setIs_me(int is_me) {
+ this.is_me = is_me;
+ }
+
+ // 嵌套类:GiftInfo
+ public static class GiftInfo {
+ @SerializedName("gift_name")
+ private String giftname;
+ @SerializedName("gift_name_en")
+ private String giftname_en;
+ @SerializedName("gift_icon")
+ private String gifticon;
+ @SerializedName("need_coin")
+ private int needcoin;
+ @SerializedName("needcoin_total")
+ private String needcoin_total;
+ @SerializedName("gift_hall_send_num")
+ private String gift_hall_send_num;
+ @SerializedName("illuminate_num")
+ private int illuminate_num;
+ @SerializedName("illuminate_status")
+ private int illuminate_status;
+ @SerializedName("gift_id")
+ private int gift_id;
+ @SerializedName("id")
+ private int id;
+ @SerializedName("gift_hall_start_date")
+ private String gift_hall_start; // 使用Java 8的LocalDate来处理日期
+ @SerializedName("gift_hall_end_date")
+ private String gift_hall_end;
+ @SerializedName("user_gift_hall_send_num")
+ private int user_gift_hall_send_num;
+ @SerializedName("gift_status")
+ private int gift_status;
+ @SerializedName("sendtype")
+ private int sendtype;//0默认钻石购买,1金币购买
+
+ public int getSendtype() {
+ return sendtype;
+ }
+
+ public void setSendtype(int sendtype) {
+ this.sendtype = sendtype;
+ }
+
+ public int getGift_status() {
+ return gift_status;
+ }
+
+ public void setGift_status(int gift_status) {
+ this.gift_status = gift_status;
+ }
+
+ public int getUser_gift_hall_send_num() {
+ return user_gift_hall_send_num;
+ }
+
+ public void setUser_gift_hall_send_num(int user_gift_hall_send_num) {
+ this.user_gift_hall_send_num = user_gift_hall_send_num;
+ }
+
+ @JSONField(name = "gift_hall_start_date")
+ public void setGift_hall_start(String gift_hall_start) {
+ this.gift_hall_start = gift_hall_start;
+ }
+ @JSONField(name = "gift_hall_start_date")
+ public String getGift_hall_start() {
+ if(!StringUtil.isEmpty(gift_hall_start)){
+ gift_hall_start=gift_hall_start.replace("-","/");
+ }
+ return gift_hall_start;
+ }
+ @JSONField(name = "gift_hall_end_date")
+ public String getGift_hall_end() {
+ if(!StringUtil.isEmpty(gift_hall_end)){
+ gift_hall_end=gift_hall_end.replace("-","/");
+ }
+ return gift_hall_end;
+ }
+
+ public void setGift_hall_end(String gift_hall_end) {
+ this.gift_hall_end = gift_hall_end;
+ }
+
+ // 同样地,这里省略getter和setter方法
+
+ public String getGiftname() {
+ return giftname;
+ }
+
+ public void setGiftname(String giftname) {
+ this.giftname = giftname;
+ }
+
+ public String getGiftname_en() {
+ return giftname_en;
+ }
+
+ public void setGiftname_en(String giftname_en) {
+ this.giftname_en = giftname_en;
+ }
+
+ public String getGifticon() {
+ return gifticon;
+ }
+
+ public void setGifticon(String gifticon) {
+ this.gifticon = gifticon;
+ }
+
+ public int getNeedcoin() {
+ return needcoin;
+ }
+
+ public void setNeedcoin(int needcoin) {
+ this.needcoin = needcoin;
+ }
+
+ public String getNeedcoin_total() {
+ return needcoin_total;
+ }
+
+ public void setNeedcoin_total(String needcoin_total) {
+ this.needcoin_total = needcoin_total;
+ }
+
+ public int getIlluminate_num() {
+ return illuminate_num;
+ }
+
+ public void setIlluminate_num(int illuminate_num) {
+ this.illuminate_num = illuminate_num;
+ }
+
+ public String getGift_hall_send_num() {
+ if (StringUtil.isEmpty(gift_hall_send_num)) {
+ gift_hall_send_num = "0";
+ }
+ return gift_hall_send_num;
+ }
+
+ public void setGift_hall_send_num(String gift_hall_send_num) {
+ this.gift_hall_send_num = gift_hall_send_num;
+ }
+
+ public int getIlluminate_status() {
+ return illuminate_status;
+ }
+
+ public void setIlluminate_status(int illuminate_status) {
+ this.illuminate_status = illuminate_status;
+ }
+
+ public int getGift_id() {
+ return gift_id;
+ }
+
+ public void setGift_id(int gift_id) {
+ this.gift_id = gift_id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+ }
+
+ // 嵌套类:Data
+ public static class Data {
+ private int gift_hall_send_num;
+ private String user_name;
+ private String avatar;
+ String user_id;
+ private int id;
+ private int gift_hall_rank_hide;
+ private String create_time;
+ private String live_id;
+ private String live_user_name;
+ private String live_avatar;
+
+
+ // 同样地,这里省略getter和setter方法
+
+ public String getUser_id() {
+ if(StringUtil.isEmpty(user_id)){
+ return "0";
+ }
+ return user_id;
+ }
+
+ public void setUser_id(String user_id) {
+ this.user_id = user_id;
+ }
+
+ public String getLive_id() {
+ return live_id;
+ }
+
+ public void setLive_id(String live_id) {
+ this.live_id = live_id;
+ }
+
+ public String getLive_user_name() {
+ return live_user_name;
+ }
+
+ public void setLive_user_name(String live_user_name) {
+ this.live_user_name = live_user_name;
+ }
+
+ public String getLive_avatar() {
+ return live_avatar;
+ }
+
+ public void setLive_avatar(String live_avatar) {
+ this.live_avatar = live_avatar;
+ }
+
+ public int getGift_hall_send_num() {
+ return gift_hall_send_num;
+ }
+ public String getGift_hall_send_numForString() {
+ if(gift_hall_send_num>999999){
+ return "999999+";
+ }else{
+ return String.valueOf(gift_hall_send_num);
+ }
+ }
+ public void setGift_hall_send_num(int gift_hall_send_num) {
+ this.gift_hall_send_num = gift_hall_send_num;
+ }
+
+ public String getUser_name() {
+ return user_name;
+ }
+
+ public void setUser_name(String user_name) {
+ this.user_name = user_name;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getGift_hall_rank_hide() {
+ return gift_hall_rank_hide;
+ }
+
+ public void setGift_hall_rank_hide(int gift_hall_rank_hide) {
+ this.gift_hall_rank_hide = gift_hall_rank_hide;
+ }
+
+ public String getCreate_time() {
+ return create_time;
+ }
+
+ public void setCreate_time(String create_time) {
+ this.create_time = create_time;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftWallMainTab2ClassicInfoBean.java b/common/src/main/java/com/yunbao/common/bean/GiftWallMainTab2ClassicInfoBean.java
new file mode 100644
index 000000000..8c1c0e580
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/GiftWallMainTab2ClassicInfoBean.java
@@ -0,0 +1,448 @@
+package com.yunbao.common.bean;
+
+import com.google.gson.annotations.SerializedName;
+import com.yunbao.common.utils.StringUtil;
+
+import java.util.List;
+
+public class GiftWallMainTab2ClassicInfoBean extends BaseModel{
+ @SerializedName("gift_info")
+ private GiftInfo giftInfo;
+
+ @SerializedName("data")
+ private List data;
+
+ @SerializedName("is_me")
+ private int isMe;
+
+ // 如果需要,可以添加无参构造器、getter和setter(这里省略)
+
+ public GiftInfo getGiftInfo() {
+ return giftInfo;
+ }
+
+ public void setGiftInfo(GiftInfo giftInfo) {
+ this.giftInfo = giftInfo;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public int getIsMe() {
+ return isMe;
+ }
+
+ public void setIsMe(int isMe) {
+ this.isMe = isMe;
+ }
+
+ // 内部类:GiftInfo
+ public static class GiftInfo {
+
+ @SerializedName("gift_id")
+ private int giftId;
+
+ @SerializedName("sendtype")
+ private int sendType;
+
+ @SerializedName("gift_name")
+ private String giftName;
+
+ @SerializedName("need_coin")
+ private int needCoin;
+
+ @SerializedName("gift_icon")
+ private String giftIcon;
+
+ @SerializedName("week_star_level")
+ private int weekStarLevel;
+
+ @SerializedName("illuminate_num")
+ private int illuminateNum;
+
+ @SerializedName("gift_hall_type")
+ private int giftHallType;
+
+ @SerializedName("gift_name_en")
+ private String giftNameEn;
+
+ @SerializedName("gift_hall_start")
+ private String giftHallStart;
+
+ @SerializedName("gift_hall_end")
+ private String giftHallEnd;
+
+ @SerializedName("gift_hall_start_date")
+ private String giftHallStartDate;
+
+ @SerializedName("gift_hall_end_date")
+ private String giftHallEndDate;
+
+ @SerializedName("user_gift_hall_send_num")
+ private int userGiftHallSendNum;
+
+ @SerializedName("needcoin_total")
+ private int needcoinTotal;
+
+ @SerializedName("gift_hall_send_num")
+ private int giftHallSendNum;
+
+ @SerializedName("illuminate_status")
+ private int illuminateStatus;
+
+ @SerializedName("naming_live_id")
+ private int namingLiveId;
+
+ @SerializedName("naming_live_nicename")
+ private String namingLiveNicename;
+
+ @SerializedName("naming_live_avatar")
+ private String namingLiveAvatar;
+
+ @SerializedName("naming_live_gift_hall_rank_hide")
+ private int namingLiveActiveRankHide;
+
+ @SerializedName("naming_user_id")
+ private int namingUserId;
+
+ @SerializedName("naming_user_nicename")
+ private String namingUserNicename;
+
+ @SerializedName("naming_user_avatar")
+ private String namingUserAvatar;
+
+ @SerializedName("naming_user_gift_hall_rank_hide")
+ private int namingUserActiveRankHide;
+
+ // 如果需要,可以添加无参构造器、getter和setter(这里省略)
+
+ public int getGiftId() {
+ return giftId;
+ }
+
+ public void setGiftId(int giftId) {
+ this.giftId = giftId;
+ }
+
+ public int getSendType() {
+ return sendType;
+ }
+
+ public void setSendType(int sendType) {
+ this.sendType = sendType;
+ }
+
+ public String getGiftName() {
+ return giftName;
+ }
+
+ public void setGiftName(String giftName) {
+ this.giftName = giftName;
+ }
+
+ public int getNeedCoin() {
+ return needCoin;
+ }
+
+ public void setNeedCoin(int needCoin) {
+ this.needCoin = needCoin;
+ }
+
+ public String getGiftIcon() {
+ return giftIcon;
+ }
+
+ public void setGiftIcon(String giftIcon) {
+ this.giftIcon = giftIcon;
+ }
+
+ public int getWeekStarLevel() {
+ return weekStarLevel;
+ }
+
+ public void setWeekStarLevel(int weekStarLevel) {
+ this.weekStarLevel = weekStarLevel;
+ }
+
+ public int getIlluminateNum() {
+ return illuminateNum;
+ }
+
+ public void setIlluminateNum(int illuminateNum) {
+ this.illuminateNum = illuminateNum;
+ }
+
+ public int getGiftHallType() {
+ return giftHallType;
+ }
+
+ public void setGiftHallType(int giftHallType) {
+ this.giftHallType = giftHallType;
+ }
+
+ public String getGiftNameEn() {
+ return giftNameEn;
+ }
+
+ public void setGiftNameEn(String giftNameEn) {
+ this.giftNameEn = giftNameEn;
+ }
+
+ public String getGiftHallStart() {
+ return giftHallStart;
+ }
+
+ public void setGiftHallStart(String giftHallStart) {
+ this.giftHallStart = giftHallStart;
+ }
+
+ public String getGiftHallEnd() {
+ return giftHallEnd;
+ }
+
+ public void setGiftHallEnd(String giftHallEnd) {
+ this.giftHallEnd = giftHallEnd;
+ }
+
+ public String getGiftHallStartDate() {
+ return giftHallStartDate;
+ }
+
+ public void setGiftHallStartDate(String giftHallStartDate) {
+ this.giftHallStartDate = giftHallStartDate;
+ }
+
+ public String getGiftHallEndDate() {
+ return giftHallEndDate;
+ }
+
+ public void setGiftHallEndDate(String giftHallEndDate) {
+ this.giftHallEndDate = giftHallEndDate;
+ }
+
+ public int getUserGiftHallSendNum() {
+ return userGiftHallSendNum;
+ }
+
+ public void setUserGiftHallSendNum(int userGiftHallSendNum) {
+ this.userGiftHallSendNum = userGiftHallSendNum;
+ }
+
+ public int getNeedcoinTotal() {
+ return needcoinTotal;
+ }
+
+ public void setNeedcoinTotal(int needcoinTotal) {
+ this.needcoinTotal = needcoinTotal;
+ }
+
+ public int getGiftHallSendNum() {
+ return giftHallSendNum;
+ }
+
+ public void setGiftHallSendNum(int giftHallSendNum) {
+ this.giftHallSendNum = giftHallSendNum;
+ }
+
+ public int getIlluminateStatus() {
+ return illuminateStatus;
+ }
+
+ public void setIlluminateStatus(int illuminateStatus) {
+ this.illuminateStatus = illuminateStatus;
+ }
+
+ public int getNamingLiveId() {
+ return namingLiveId;
+ }
+
+ public void setNamingLiveId(int namingLiveId) {
+ this.namingLiveId = namingLiveId;
+ }
+
+ public String getNamingLiveNicename() {
+ return namingLiveNicename;
+ }
+
+ public void setNamingLiveNicename(String namingLiveNicename) {
+ this.namingLiveNicename = namingLiveNicename;
+ }
+
+ public String getNamingLiveAvatar() {
+ return namingLiveAvatar;
+ }
+
+ public void setNamingLiveAvatar(String namingLiveAvatar) {
+ this.namingLiveAvatar = namingLiveAvatar;
+ }
+
+ public int getNamingLiveActiveRankHide() {
+ return namingLiveActiveRankHide;
+ }
+
+ public void setNamingLiveActiveRankHide(int namingLiveActiveRankHide) {
+ this.namingLiveActiveRankHide = namingLiveActiveRankHide;
+ }
+
+ public int getNamingUserId() {
+ return namingUserId;
+ }
+
+ public void setNamingUserId(int namingUserId) {
+ this.namingUserId = namingUserId;
+ }
+
+ public String getNamingUserNicename() {
+ return namingUserNicename;
+ }
+
+ public void setNamingUserNicename(String namingUserNicename) {
+ this.namingUserNicename = namingUserNicename;
+ }
+
+ public String getNamingUserAvatar() {
+ return namingUserAvatar;
+ }
+
+ public void setNamingUserAvatar(String namingUserAvatar) {
+ this.namingUserAvatar = namingUserAvatar;
+ }
+
+ public int getNamingUserActiveRankHide() {
+ return namingUserActiveRankHide;
+ }
+
+ public void setNamingUserActiveRankHide(int namingUserActiveRankHide) {
+ this.namingUserActiveRankHide = namingUserActiveRankHide;
+ }
+ }
+
+ // 内部类:GiftData
+ public static class GiftData {
+
+ @SerializedName("gift_hall_send_num")
+ private int giftHallSendNum;
+
+ @SerializedName("live_id")
+ private int liveId;
+
+ @SerializedName("live_user_name")
+ private String liveUserName;
+
+ @SerializedName("live_avatar")
+ private String liveAvatar;
+
+ @SerializedName("user_name")
+ private String userName;
+
+ @SerializedName("avatar")
+ private String avatar;
+
+ @SerializedName("user_id")
+ private String userId;
+
+ @SerializedName("active_rank_hide")
+ private int activeRankHide;
+
+ @SerializedName("create_time")
+ private String createTime;
+ @SerializedName("naming_user_gift_hall_rank_hide")
+ private int naming_user_gift_hall_rank_hide;
+
+ // 如果需要,可以添加无参构造器、getter和setter(这里省略)
+
+ public int getNaming_user_gift_hall_rank_hide() {
+ return naming_user_gift_hall_rank_hide;
+ }
+
+ public void setNaming_user_gift_hall_rank_hide(int naming_user_gift_hall_rank_hide) {
+ this.naming_user_gift_hall_rank_hide = naming_user_gift_hall_rank_hide;
+ }
+
+ public int getGiftHallSendNum() {
+ return giftHallSendNum;
+ }
+ public String getGiftHallSendNumForString() {
+ if(giftHallSendNum>999999){
+ return "999999+";
+ }
+ return giftHallSendNum+"";
+ }
+
+ public void setGiftHallSendNum(int giftHallSendNum) {
+ this.giftHallSendNum = giftHallSendNum;
+ }
+
+ public int getLiveId() {
+ return liveId;
+ }
+
+ public void setLiveId(int liveId) {
+ this.liveId = liveId;
+ }
+
+ public String getLiveUserName() {
+ return liveUserName;
+ }
+
+ public void setLiveUserName(String liveUserName) {
+ this.liveUserName = liveUserName;
+ }
+
+ public String getLiveAvatar() {
+ return liveAvatar;
+ }
+
+ public void setLiveAvatar(String liveAvatar) {
+ this.liveAvatar = liveAvatar;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getUserId() {
+ if(StringUtil.isEmpty(userId)){
+ return "0";
+ }
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public int getActiveRankHide() {
+ return activeRankHide;
+ }
+
+ public void setActiveRankHide(int activeRankHide) {
+ this.activeRankHide = activeRankHide;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(String createTime) {
+ this.createTime = createTime;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/GiftWallTab2Bean.java b/common/src/main/java/com/yunbao/common/bean/GiftWallTab2Bean.java
new file mode 100644
index 000000000..151f1ba59
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/GiftWallTab2Bean.java
@@ -0,0 +1,312 @@
+package com.yunbao.common.bean;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+public class GiftWallTab2Bean extends BaseModel{
+
+
+ @SerializedName("illuminate_data")
+ private IlluminateData illuminateData;
+ @SerializedName("gift_hall_start_date")
+ private String gift_hall_start_date;
+ @SerializedName("gift_hall_end_date")
+ private String gift_hall_end_date;
+
+ public GiftWallTab2Bean() {
+ }
+
+ public IlluminateData getIlluminateData() {
+ return illuminateData;
+ }
+
+ public void setIlluminateData(IlluminateData illuminateData) {
+ this.illuminateData = illuminateData;
+ }
+
+ public String getGift_hall_start_date() {
+ return gift_hall_start_date;
+ }
+
+ public void setGift_hall_start_date(String gift_hall_start_date) {
+ this.gift_hall_start_date = gift_hall_start_date;
+ }
+
+ public String getGift_hall_end_date() {
+ return gift_hall_end_date;
+ }
+
+ public void setGift_hall_end_date(String gift_hall_end_date) {
+ this.gift_hall_end_date = gift_hall_end_date;
+ }
+
+ public static class IlluminateData{
+ @SerializedName("week_start_data")
+ private List weekStartData;
+ @SerializedName("gift_data")
+ private List giftData;
+
+ public IlluminateData() {
+ }
+
+ public List getWeekStartData() {
+ return weekStartData;
+ }
+
+ public void setWeekStartData(List weekStartData) {
+ this.weekStartData = weekStartData;
+ }
+
+ public List getGiftData() {
+ return giftData;
+ }
+
+ public void setGiftData(List giftData) {
+ this.giftData = giftData;
+ }
+ }
+ public static class Gift{
+ @SerializedName("gift_id")
+ public int giftId;
+
+ @SerializedName("sendtype")
+ public int sendType;
+
+ @SerializedName("gift_name")
+ public String giftName;
+
+ @SerializedName("need_coin")
+ public int needCoin;
+
+ @SerializedName("gift_icon")
+ public String giftIcon;
+
+ @SerializedName("week_star_level")
+ public int weekStarLevel;
+
+ @SerializedName("illuminate_num")
+ public int illuminateNum;
+
+ @SerializedName("gift_hall_type")
+ public int giftHallType;
+
+ @SerializedName("gift_name_en")
+ public String giftNameEn;
+
+ @SerializedName("gift_hall_start")
+ public String giftHallStart;
+
+ @SerializedName("gift_hall_end")
+ public String giftHallEnd;
+
+ @SerializedName("naming_live_id")
+ public int namingLiveId;
+
+ @SerializedName("naming_live_nicename")
+ public String namingLiveNicename;
+
+ @SerializedName("gift_hall_send_num")
+ public int giftHallSendNum;
+
+ @SerializedName("naming_live_avatar")
+ public String namingLiveAvatar;
+
+ @SerializedName("naming_live_active_rank_hide")
+ public int namingLiveActiveRankHide;
+
+ @SerializedName("illuminate_status")
+ public int illuminateStatus;
+
+ @SerializedName("naming_user_id")
+ public int namingUserId;
+
+ @SerializedName("naming_user_nicename")
+ public String namingUserNicename;
+
+ @SerializedName("naming_user_avatar")
+ public String namingUserAvatar;
+
+ @SerializedName("naming_user_gift_hall_rank_hide")
+ public int namingUserActiveRankHide;
+
+ @SerializedName("needcoin_total")
+ public long needCoinTotal;
+
+ public int getGiftId() {
+ return giftId;
+ }
+
+ public void setGiftId(int giftId) {
+ this.giftId = giftId;
+ }
+
+ public int getSendType() {
+ return sendType;
+ }
+
+ public void setSendType(int sendType) {
+ this.sendType = sendType;
+ }
+
+ public String getGiftName() {
+ return giftName;
+ }
+
+ public void setGiftName(String giftName) {
+ this.giftName = giftName;
+ }
+
+ public int getNeedCoin() {
+ return needCoin;
+ }
+
+ public void setNeedCoin(int needCoin) {
+ this.needCoin = needCoin;
+ }
+
+ public String getGiftIcon() {
+ return giftIcon;
+ }
+
+ public void setGiftIcon(String giftIcon) {
+ this.giftIcon = giftIcon;
+ }
+
+ public int getWeekStarLevel() {
+ return weekStarLevel;
+ }
+
+ public void setWeekStarLevel(int weekStarLevel) {
+ this.weekStarLevel = weekStarLevel;
+ }
+
+ public int getIlluminateNum() {
+ return illuminateNum;
+ }
+
+ public void setIlluminateNum(int illuminateNum) {
+ this.illuminateNum = illuminateNum;
+ }
+
+ public int getGiftHallType() {
+ return giftHallType;
+ }
+
+ public void setGiftHallType(int giftHallType) {
+ this.giftHallType = giftHallType;
+ }
+
+ public String getGiftNameEn() {
+ return giftNameEn;
+ }
+
+ public void setGiftNameEn(String giftNameEn) {
+ this.giftNameEn = giftNameEn;
+ }
+
+ public String getGiftHallStart() {
+ return giftHallStart;
+ }
+
+ public void setGiftHallStart(String giftHallStart) {
+ this.giftHallStart = giftHallStart;
+ }
+
+ public String getGiftHallEnd() {
+ return giftHallEnd;
+ }
+
+ public void setGiftHallEnd(String giftHallEnd) {
+ this.giftHallEnd = giftHallEnd;
+ }
+
+ public int getNamingLiveId() {
+ return namingLiveId;
+ }
+
+ public void setNamingLiveId(int namingLiveId) {
+ this.namingLiveId = namingLiveId;
+ }
+
+ public String getNamingLiveNicename() {
+ return namingLiveNicename;
+ }
+
+ public void setNamingLiveNicename(String namingLiveNicename) {
+ this.namingLiveNicename = namingLiveNicename;
+ }
+
+ public int getGiftHallSendNum() {
+ return giftHallSendNum;
+ }
+
+ public void setGiftHallSendNum(int giftHallSendNum) {
+ this.giftHallSendNum = giftHallSendNum;
+ }
+
+ public String getNamingLiveAvatar() {
+ return namingLiveAvatar;
+ }
+
+ public void setNamingLiveAvatar(String namingLiveAvatar) {
+ this.namingLiveAvatar = namingLiveAvatar;
+ }
+
+ public int getNamingLiveActiveRankHide() {
+ return namingLiveActiveRankHide;
+ }
+
+ public void setNamingLiveActiveRankHide(int namingLiveActiveRankHide) {
+ this.namingLiveActiveRankHide = namingLiveActiveRankHide;
+ }
+
+ public int getIlluminateStatus() {
+ return illuminateStatus;
+ }
+
+ public void setIlluminateStatus(int illuminateStatus) {
+ this.illuminateStatus = illuminateStatus;
+ }
+
+ public int getNamingUserId() {
+ return namingUserId;
+ }
+
+ public void setNamingUserId(int namingUserId) {
+ this.namingUserId = namingUserId;
+ }
+
+ public String getNamingUserNicename() {
+ return namingUserNicename;
+ }
+
+ public void setNamingUserNicename(String namingUserNicename) {
+ this.namingUserNicename = namingUserNicename;
+ }
+
+ public String getNamingUserAvatar() {
+ return namingUserAvatar;
+ }
+
+ public void setNamingUserAvatar(String namingUserAvatar) {
+ this.namingUserAvatar = namingUserAvatar;
+ }
+
+ public int getNamingUserActiveRankHide() {
+ return namingUserActiveRankHide;
+ }
+
+ public void setNamingUserActiveRankHide(int namingUserActiveRankHide) {
+ this.namingUserActiveRankHide = namingUserActiveRankHide;
+ }
+
+ public long getNeedCoinTotal() {
+ return needCoinTotal;
+ }
+
+ public void setNeedCoinTotal(long needCoinTotal) {
+ this.needCoinTotal = needCoinTotal;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/GuardPriceModel.java b/common/src/main/java/com/yunbao/common/bean/GuardPriceModel.java
index 24568f683..bdaebd67e 100644
--- a/common/src/main/java/com/yunbao/common/bean/GuardPriceModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/GuardPriceModel.java
@@ -22,6 +22,30 @@ public class GuardPriceModel extends BaseModel {
private String discount;
@SerializedName("price_key")
private int priceKey;
+ @SerializedName("coupon_discount")
+ private String couponDiscount;
+ @SerializedName("coupon_discount_en")
+ private String couponDiscountEn;
+ @SerializedName("coupon_discount_price")
+ private String couponDiscountPrice;
+ @SerializedName("coupon_id")
+ private String couponId;
+
+ public String getCouponDiscount() {
+ return couponDiscount;
+ }
+
+ public String getCouponId() {
+ return couponId;
+ }
+
+ public String getCouponDiscountEn() {
+ return couponDiscountEn;
+ }
+
+ public String getCouponDiscountPrice() {
+ return couponDiscountPrice;
+ }
public String getOpeningTime() {
return openingTime;
diff --git a/common/src/main/java/com/yunbao/common/bean/LiveAnchorCallMeModel.java b/common/src/main/java/com/yunbao/common/bean/LiveAnchorCallMeModel.java
index 400322cb9..7520ea169 100644
--- a/common/src/main/java/com/yunbao/common/bean/LiveAnchorCallMeModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/LiveAnchorCallMeModel.java
@@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.annotations.SerializedName;
+import com.yunbao.common.utils.StringUtil;
/**
* 联系方式
@@ -141,14 +142,14 @@ public class LiveAnchorCallMeModel extends BaseModel {
public static class AppBean {
private String number;
- private int isShow;
+ private String isShow;
public AppBean() {
}
public AppBean(String number, int isShow) {
this.number = number;
- this.isShow = isShow;
+ this.isShow = isShow + "";
}
public String getNumber() {
@@ -160,11 +161,14 @@ public class LiveAnchorCallMeModel extends BaseModel {
}
public int getIsShow() {
- return isShow;
+ if (StringUtil.isEmpty(isShow)) {
+ return 0;
+ }
+ return Integer.parseInt(isShow);
}
public void setIsShow(int isShow) {
- this.isShow = isShow;
+ this.isShow = isShow + "";
}
@NonNull
diff --git a/common/src/main/java/com/yunbao/common/bean/LiveGiftBean.java b/common/src/main/java/com/yunbao/common/bean/LiveGiftBean.java
index ee8b51204..44c90cf46 100644
--- a/common/src/main/java/com/yunbao/common/bean/LiveGiftBean.java
+++ b/common/src/main/java/com/yunbao/common/bean/LiveGiftBean.java
@@ -4,6 +4,7 @@ import android.view.View;
import com.alibaba.fastjson.annotation.JSONField;
import com.google.gson.annotations.SerializedName;
+import com.yunbao.common.utils.StringUtil;
/**
* Created by cxf on 2018/10/12.
@@ -52,9 +53,9 @@ public class LiveGiftBean {
@JSONField(name = "operate_url")
private String operateUrl;
- @JSONField(name = "naming_liveuid")
+ @JSONField(name = "naming_live_id")
private String namingLiveuid;
- @JSONField(name = "naming_uid")
+ @JSONField(name = "naming_user_id")
private String namingUid;
@JSONField(name = "naming_live_name")
private String namingLiveName;
@@ -74,6 +75,28 @@ public class LiveGiftBean {
private int blindBoxTicket;
@JSONField(name = "blind_box_ticket_id")
private int blindBoxTicketId;
+ @JSONField(name = "naming_user_gift_hall_rank_hide")
+ @SerializedName("naming_user_gift_hall_rank_hide")
+ private int naming_user_gift_hall_rank_hide;
+ @JSONField(name = "naming_live_gift_hall_rank_hide")
+ @SerializedName("naming_live_gift_hall_rank_hide")
+ private int naming_live_gift_hall_rank_hide;
+
+ public int getNaming_user_gift_hall_rank_hide() {
+ return naming_user_gift_hall_rank_hide;
+ }
+
+ public void setNaming_user_gift_hall_rank_hide(int naming_user_gift_hall_rank_hide) {
+ this.naming_user_gift_hall_rank_hide = naming_user_gift_hall_rank_hide;
+ }
+
+ public int getNaming_live_gift_hall_rank_hide() {
+ return naming_live_gift_hall_rank_hide;
+ }
+
+ public void setNaming_live_gift_hall_rank_hide(int naming_live_gift_hall_rank_hide) {
+ this.naming_live_gift_hall_rank_hide = naming_live_gift_hall_rank_hide;
+ }
public boolean isPageGift() {
return isPageGift;
@@ -146,6 +169,9 @@ public class LiveGiftBean {
}
public String getNamingUid() {
+ if(StringUtil.isEmpty(namingUid)){
+ namingUid="0";
+ }
return namingUid;
}
@@ -288,6 +314,9 @@ public class LiveGiftBean {
}
public String getSwf() {
+ if(StringUtil.isEmpty(swf)){
+ swf="";
+ }
return swf;
}
diff --git a/common/src/main/java/com/yunbao/common/bean/OpenAdModel.java b/common/src/main/java/com/yunbao/common/bean/OpenAdModel.java
index 638334d48..1131cc919 100644
--- a/common/src/main/java/com/yunbao/common/bean/OpenAdModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/OpenAdModel.java
@@ -3,6 +3,7 @@ package com.yunbao.common.bean;
import com.google.gson.annotations.SerializedName;
import com.yunbao.common.CommonAppConfig;
import com.yunbao.common.utils.StringUtil;
+import com.yunbao.common.utils.WordUtil;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -122,7 +123,7 @@ public class OpenAdModel extends BaseModel {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = CommonAppConfig.HOST + (url.startsWith("/") ? url : "/" + url);
}
- return url;
+ return url+"&isZh=" + (WordUtil.isNewZh() ? "1" : "0");
}
public String getOriginalUrl() {
diff --git a/common/src/main/java/com/yunbao/common/bean/SudGameInfoBean.java b/common/src/main/java/com/yunbao/common/bean/SudGameInfoBean.java
new file mode 100644
index 000000000..d47f5fe09
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/SudGameInfoBean.java
@@ -0,0 +1,60 @@
+package com.yunbao.common.bean;
+
+public class SudGameInfoBean {
+ private String uid;//玩家id
+ private String nick_name;//玩家昵称
+ private String avatar_url;//玩家头像
+ private String gender;//玩家性别
+ private int is_ai;//是否是ai
+
+ public String getUid() {
+ return uid;
+ }
+
+ public void setUid(String uid) {
+ this.uid = uid;
+ }
+
+ public String getNick_name() {
+ return nick_name;
+ }
+
+ public void setNick_name(String nick_name) {
+ this.nick_name = nick_name;
+ }
+
+ public String getAvatar_url() {
+ return avatar_url;
+ }
+
+ public void setAvatar_url(String avatar_url) {
+ this.avatar_url = avatar_url;
+ }
+
+ public String getGender() {
+ return gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public int getIs_ai() {
+ return is_ai;
+ }
+
+ public void setIs_ai(int is_ai) {
+ this.is_ai = is_ai;
+ }
+
+ @Override
+ public String toString() {
+ return "SudGameInfoBean{" +
+ "uid=" + uid +
+ ", nick_name='" + nick_name + '\'' +
+ ", avatar_url='" + avatar_url + '\'' +
+ ", gender='" + gender + '\'' +
+ ", is_ai=" + is_ai +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/SudGameScoreBean.java b/common/src/main/java/com/yunbao/common/bean/SudGameScoreBean.java
new file mode 100644
index 000000000..4742eaec0
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/SudGameScoreBean.java
@@ -0,0 +1,60 @@
+package com.yunbao.common.bean;
+
+public class SudGameScoreBean extends BaseModel{
+ private int golden_bean_remaining_balance;//
+ private int room_sill;//房间的金豆门槛
+ private int room_ticket;//收取的门票费
+ private int room_win_num;//赢家获得的金豆
+ private int game_mode;//1.双人对战 2.多人游戏
+
+ @Override
+ public String toString() {
+ return "SudGameScoreBean{" +
+ "golden_bean_remaining_balance=" + golden_bean_remaining_balance +
+ ", room_sill=" + room_sill +
+ ", room_ticket=" + room_ticket +
+ ", room_win_num=" + room_win_num +
+ ", game_mode=" + game_mode +
+ '}';
+ }
+
+ public int getGame_mode() {
+ return game_mode;
+ }
+
+ public void setGame_mode(int game_mode) {
+ this.game_mode = game_mode;
+ }
+
+ public int getGolden_bean_remaining_balance() {
+ return golden_bean_remaining_balance;
+ }
+
+ public void setGolden_bean_remaining_balance(int golden_bean_remaining_balance) {
+ this.golden_bean_remaining_balance = golden_bean_remaining_balance;
+ }
+
+ public int getRoom_sill() {
+ return room_sill;
+ }
+
+ public void setRoom_sill(int room_sill) {
+ this.room_sill = room_sill;
+ }
+
+ public int getRoom_ticket() {
+ return room_ticket;
+ }
+
+ public void setRoom_ticket(int room_ticket) {
+ this.room_ticket = room_ticket;
+ }
+
+ public int getRoom_win_num() {
+ return room_win_num;
+ }
+
+ public void setRoom_win_num(int room_win_num) {
+ this.room_win_num = room_win_num;
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/SudSettleBean.java b/common/src/main/java/com/yunbao/common/bean/SudSettleBean.java
new file mode 100644
index 000000000..9738a1e87
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/bean/SudSettleBean.java
@@ -0,0 +1,71 @@
+package com.yunbao.common.bean;
+
+import java.util.List;
+
+public class SudSettleBean {
+ private String uid;//玩家id
+ private String nick_name;//玩家昵称
+ private String avatar_url;//玩家头像
+ private int rank;//玩家排名
+ private int win_num;//赢得或者失去的金豆
+
+ public String getUid() {
+ return uid;
+ }
+
+ public void setUid(String uid) {
+ this.uid = uid;
+ }
+
+ public String getNick_name() {
+ return nick_name;
+ }
+
+ public void setNick_name(String nick_name) {
+ this.nick_name = nick_name;
+ }
+
+ public String getAvatar_url() {
+ return avatar_url;
+ }
+
+ public void setAvatar_url(String avatar_url) {
+ this.avatar_url = avatar_url;
+ }
+
+ public int getRank() {
+ return rank;
+ }
+
+ public void setRank(int rank) {
+ this.rank = rank;
+ }
+
+ public int getWin_num() {
+ return win_num;
+ }
+
+ public void setWin_num(int win_num) {
+ this.win_num = win_num;
+ }
+
+
+ public SudSettleBean(String uid, String nick_name, String avatar_url, int rank, int win_num) {
+ this.uid = uid;
+ this.nick_name = nick_name;
+ this.avatar_url = avatar_url;
+ this.rank = rank;
+ this.win_num = win_num;
+ }
+
+ @Override
+ public String toString() {
+ return "SudSettleBean{" +
+ "uid='" + uid + '\'' +
+ ", nick_name='" + nick_name + '\'' +
+ ", avatar_url='" + avatar_url + '\'' +
+ ", rank=" + rank +
+ ", win_num=" + win_num +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/bean/UserMedalModel.java b/common/src/main/java/com/yunbao/common/bean/UserMedalModel.java
index 4ac5dde3e..b0b22b603 100644
--- a/common/src/main/java/com/yunbao/common/bean/UserMedalModel.java
+++ b/common/src/main/java/com/yunbao/common/bean/UserMedalModel.java
@@ -1,8 +1,9 @@
package com.yunbao.common.bean;
import com.google.gson.annotations.SerializedName;
+import com.stx.xhb.androidx.entity.BaseBannerInfo;
-public class UserMedalModel extends BaseModel {
+public class UserMedalModel extends BaseModel implements BaseBannerInfo {
@SerializedName("id")
private String id;
@SerializedName("display_src")
@@ -13,9 +14,26 @@ public class UserMedalModel extends BaseModel {
private String dressDescription;
@SerializedName("sort")
private String sort;
+ @SerializedName("use_status")
+ private String use_status;
@SerializedName("dress_status")
private String dressStatus;
+ @SerializedName("users_dress_id")
+ private String users_dress_id;
+
+ public String getUsersDressId() {
+ return users_dress_id;
+ }
+
+ public String getUseStatus() {
+ return use_status;
+ }
+
+ public void setUse_status(String use_status) {
+ this.use_status = use_status;
+ }
+
public String getId() {
return id;
}
@@ -69,4 +87,14 @@ public class UserMedalModel extends BaseModel {
this.dressStatus = dressStatus;
return this;
}
+
+ @Override
+ public Object getXBannerUrl() {
+ return null;
+ }
+
+ @Override
+ public String getXBannerTitle() {
+ return null;
+ }
}
diff --git a/common/src/main/java/com/yunbao/common/custom/LiveGifWallAchieveWearTransformer.java b/common/src/main/java/com/yunbao/common/custom/LiveGifWallAchieveWearTransformer.java
new file mode 100644
index 000000000..56032e07a
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/custom/LiveGifWallAchieveWearTransformer.java
@@ -0,0 +1,75 @@
+package com.yunbao.common.custom;
+
+import android.view.View;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.view.ViewCompat;
+import androidx.viewpager.widget.ViewPager;
+
+import com.stx.xhb.androidx.transformers.BasePageTransformer;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.L;
+
+public class LiveGifWallAchieveWearTransformer extends BasePageTransformer {
+ /**
+ * author: xiaohaibin.
+ * time: 2018/10/9
+ * mail:xhb_199409@163.com
+ * github:https://github.com/xiaohaibin
+ * describe: 适用于一屏显示多个模式
+ */
+ private float mMinScale = 0.85f;
+ private float mMinAlpha = 1f;
+
+ public LiveGifWallAchieveWearTransformer() {
+ }
+
+ public LiveGifWallAchieveWearTransformer(float minAlpha, float minScale) {
+ setMinAlpha(minAlpha);
+ setMinScale(minScale);
+ }
+
+ @Override
+ public void handleInvisiblePage(View view, float position) {
+ // ViewCompat.setAlpha(view, 0);
+ }
+
+ @Override
+ public void handleLeftPage(View view, float position) {
+ float scale = Math.max(mMinScale, 1 + position);
+ float vertMargin = view.getHeight() * (1 - scale) / 2;
+ float horzMargin = view.getWidth() * (1 - scale) / 2;
+ view.setTranslationX(horzMargin - vertMargin / 2);
+ view.setScaleX(scale);
+ view.setScaleY( scale);
+ L.e("handleLeftPage scale:"+scale);
+ // view.setAlpha( mMinAlpha + (scale - mMinScale) / (1 - mMinScale) * (1 - mMinAlpha));
+ view.setAlpha(1f);
+ }
+
+ @Override
+ public void handleRightPage(View view, float position) {
+ float scale = Math.max(mMinScale, 1 - position);
+ float vertMargin = view.getHeight() * (1 - scale) / 2;
+ float horzMargin = view.getWidth() * (1 - scale) / 2;
+ view.setTranslationX( -horzMargin + vertMargin / 2);
+ view.setScaleX( scale);
+
+ view.setScaleY( scale);
+ L.e("handleRightPage scale:"+scale);
+ // view.setAlpha( mMinAlpha + (scale - mMinScale) / (1 - mMinScale) * (1 - mMinAlpha));
+ view.setAlpha(1f);
+ }
+
+ public void setMinAlpha(float minAlpha) {
+ if (minAlpha >= 0.6f && minAlpha <= 1.0f) {
+ mMinAlpha = minAlpha;
+ }
+ }
+
+ public void setMinScale(float minScale) {
+ if (minScale >= 0.6f && minScale <= 1.0f) {
+ mMinScale = minScale;
+ }
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/AbsDialogCenterPopupWindow.java b/common/src/main/java/com/yunbao/common/dialog/AbsDialogCenterPopupWindow.java
index b0b894576..a685192b0 100644
--- a/common/src/main/java/com/yunbao/common/dialog/AbsDialogCenterPopupWindow.java
+++ b/common/src/main/java/com/yunbao/common/dialog/AbsDialogCenterPopupWindow.java
@@ -24,6 +24,11 @@ public abstract class AbsDialogCenterPopupWindow extends CenterPopupView {
public abstract void buildDialog(XPopup.Builder builder);
public abstract int bindLayoutId();
+ @Override
+ protected void onShow() {
+ super.onShow();
+ }
+
@Override
protected int getImplLayoutId() {
return bindLayoutId();
@@ -36,4 +41,24 @@ public abstract class AbsDialogCenterPopupWindow extends CenterPopupView {
buildDialog(builder);
builder.asCustom(this).show();
}
+
+ /**
+ * Dismiss监听
+ */
+ private OnDismissListener onDismissListener;
+ public interface OnDismissListener{
+ void onDismiss();
+ }
+
+ public void setOnDismissListener(OnDismissListener onDismissListener) {
+ this.onDismissListener = onDismissListener;
+ }
+
+ @Override
+ protected void onDismiss() {
+ super.onDismiss();
+ if (onDismissListener != null){
+ onDismissListener.onDismiss();
+ }
+ }
}
diff --git a/common/src/main/java/com/yunbao/common/dialog/AbsDialogPopupWindow.java b/common/src/main/java/com/yunbao/common/dialog/AbsDialogPopupWindow.java
index be1adad33..aa385d22f 100644
--- a/common/src/main/java/com/yunbao/common/dialog/AbsDialogPopupWindow.java
+++ b/common/src/main/java/com/yunbao/common/dialog/AbsDialogPopupWindow.java
@@ -6,6 +6,11 @@ import androidx.annotation.NonNull;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BottomPopupView;
+import com.yunbao.common.event.ClosePopupDialogEvent;
+import com.yunbao.common.utils.Bus;
+
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* 底部弹窗
@@ -16,12 +21,20 @@ public abstract class AbsDialogPopupWindow extends BottomPopupView {
public AbsDialogPopupWindow(@NonNull Context context) {
super(context);
this.mContext = context;
+ Bus.getOn(this);
+ }
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ Bus.getOff(this);
}
/**
* 参考配置
*/
public abstract void buildDialog(XPopup.Builder builder);
+
public abstract int bindLayoutId();
@Override
@@ -36,4 +49,16 @@ public abstract class AbsDialogPopupWindow extends BottomPopupView {
buildDialog(builder);
builder.asCustom(this).show();
}
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onWishSendGift(ClosePopupDialogEvent bean) {
+ if(bean.getId()==null) {
+ dismiss();
+ return;
+ }
+ if(bean.getId().equals(getTag())) {
+ dismiss();
+ }
+ }
+
}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveDialog.java
new file mode 100644
index 000000000..7325b31cf
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveDialog.java
@@ -0,0 +1,166 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.lxj.xpopup.XPopup;
+import com.yunbao.common.CommonAppConfig;
+import com.yunbao.common.R;
+import com.yunbao.common.adapter.GiftWallAchieveAdapter;
+import com.yunbao.common.bean.IMLoginModel;
+import com.yunbao.common.bean.MedalAchievementModel;
+import com.yunbao.common.bean.UserMedalListModel;
+import com.yunbao.common.fragment.GiftWallMainTab1Fragment;
+import com.yunbao.common.http.base.HttpCallback;
+import com.yunbao.common.http.live.LiveNetManager;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.RouteUtil;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.ToastUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 礼物墙-荣誉成就
+ */
+public class GiftWallAchieveDialog extends AbsDialogPopupWindow {
+
+ private ImageView mIvBg;
+ private ImageView mIvBack;
+ private TextView numCount;
+ private boolean isFullWindows;
+ private RecyclerView mRecyclerView;
+ private GiftWallAchieveAdapter giftWallAchieveAdapter;
+ private String toUid;
+ private boolean isAnchor;
+ private View topBar;
+ private TextView honor;
+ private ImageView top_icon;
+
+ private List userMedalListModelList = new ArrayList<>();
+
+ public GiftWallAchieveDialog(@NonNull Context context) {
+ super(context);
+ }
+
+ public GiftWallAchieveDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+
+ public GiftWallAchieveDialog setAnchor(boolean anchor) {
+ isAnchor = anchor;
+ return this;
+ }
+
+ public GiftWallAchieveDialog setToUid(String toUid) {
+ this.toUid = toUid;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_achieve;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight();
+ }
+ int screenHeight = ScreenDimenUtil.getInstance().getScreenHeight();
+ return (int) (screenHeight * 0.8);
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvBack = findViewById(R.id.iv_back);
+ mRecyclerView = findViewById(R.id.recyclerView);
+ mRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 3, GridLayoutManager.VERTICAL, false));
+ numCount = findViewById(R.id.numCount);
+ topBar = findViewById(R.id.top_bar);
+ honor = findViewById(R.id.honor);
+ top_icon = findViewById(R.id.top_icon);
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) top_icon.getLayoutParams();
+ params.width = DpUtil.dp2px(WordUtil.isNewZh() ? 65 : 130);
+ top_icon.setLayoutParams(params);
+ mIvBack.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dialog.dismiss();
+ }
+ });
+
+ ViewClicksAntiShake.clicksAntiShake(honor, () -> {
+ StringBuffer htmlUrl = new StringBuffer();
+ IMLoginModel userInfo = IMLoginManager.get(getContext()).getUserInfo();
+ htmlUrl.append(CommonAppConfig.HOST).append("/h5/shequ/index.html#/h5/shequ/RongYuQiang?").append("touid=").append(toUid).append("&token=").append(userInfo.getToken()).append("&uid=").append(userInfo.getId()).append("&isZh=").append(WordUtil.isNewZh() ? "1" : 0);
+ RouteUtil.forwardLiveZhuangBanActivity(htmlUrl.toString(), true);
+ });
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+ if (isFullWindows) {
+ mIvBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ ViewGroup.LayoutParams params1 = topBar.getLayoutParams();
+ params1.height = DpUtil.dp2px(35);
+ ;
+ topBar.setLayoutParams(params1);
+ } else {
+ mIvBg.setScaleType(ImageView.ScaleType.FIT_XY);
+ }
+ initData();
+ }
+
+ private void initData() {
+ LiveNetManager.get(getContext()).getGiftHallMedalList(toUid, isAnchor ? "1" : "2", new HttpCallback() {
+ @Override
+ public void onSuccess(MedalAchievementModel data) {
+ numCount.setText(data.getMedalLightNumber() + "/" + data.getMedalTotalNumber());
+ userMedalListModelList = data.getMedalData();
+ giftWallAchieveAdapter = new GiftWallAchieveAdapter(userMedalListModelList, mContext);
+ giftWallAchieveAdapter.setOnItemClickListener(new GiftWallAchieveAdapter.OnItemClickListener() {
+ @Override
+ public void onItemClick(int position) {
+ GiftWallAchieveWearDialog giftWallAchieveWearDialog = new GiftWallAchieveWearDialog(mContext, toUid, isAnchor, userMedalListModelList.get(position).getDressInfo(), new GiftWallAchieveWearDialog.UserUseDressSuccess() {
+ @Override
+ public void onSuccess() {
+ initData();
+ }
+ });
+ giftWallAchieveWearDialog.showDialog();
+ }
+ });
+ mRecyclerView.setAdapter(giftWallAchieveAdapter);
+ }
+
+ @Override
+ public void onError(String error) {
+ ToastUtil.show(error);
+ }
+ });
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveWearDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveWearDialog.java
new file mode 100644
index 000000000..7731165c5
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallAchieveWearDialog.java
@@ -0,0 +1,210 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.viewpager.widget.ViewPager;
+
+import com.lxj.xpopup.XPopup;
+import com.stx.xhb.androidx.XBanner;
+import com.stx.xhb.androidx.transformers.BasePageTransformer;
+import com.stx.xhb.androidx.transformers.Transformer;
+import com.yunbao.common.CommonAppConfig;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.HttpCallbackModel;
+import com.yunbao.common.bean.UserBean;
+import com.yunbao.common.bean.UserMedalModel;
+import com.yunbao.common.custom.LiveGifWallAchieveWearTransformer;
+import com.yunbao.common.custom.LiveGuardScalePageTransformer;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.http.base.HttpCallback;
+import com.yunbao.common.http.live.LiveNetManager;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.ToastUtil;
+import com.yunbao.common.utils.WordUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 礼物墙-荣誉成就
+ */
+public class GiftWallAchieveWearDialog extends AbsDialogPopupWindow {
+
+ private ImageView mIvBg;
+ private ImageView mIvBack;
+ private boolean isFullWindows;
+ private String toUid;
+ private XBanner xBanner;
+ private TextView textAchieveName;
+ private TextView textAchieveHint;
+ private TextView btnConfirm;
+ private int selectPosition = 0;
+ private boolean isAnchor;
+
+ String putOn = WordUtil.isNewZh() ? "佩戴" : "wearing";
+ String wearing = WordUtil.isNewZh() ? "已佩戴" : "worn";
+ private List achieveWearModels = new ArrayList<>();
+ private UserUseDressSuccess userUseDressSuccess;
+ private int useIndex = 0;
+
+ public GiftWallAchieveWearDialog(@NonNull Context context, String toUid, boolean isAnchor, List achieveWearModels, UserUseDressSuccess userUseDressSuccess) {
+ super(context);
+ this.toUid = toUid;
+ this.isAnchor = isAnchor;
+ this.achieveWearModels = achieveWearModels;
+ this.userUseDressSuccess = userUseDressSuccess;
+ for (int i = 0; i < this.achieveWearModels.size(); i++) {
+ if ("1".equals(this.achieveWearModels.get(i).getUseStatus())) {
+ useIndex = i;
+ break;
+ }
+ }
+ }
+
+ public GiftWallAchieveWearDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+ public GiftWallAchieveWearDialog setToUid(String toUid) {
+ this.toUid = toUid;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_achieve_wear;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight();
+ }
+ return ScreenDimenUtil.getInstance().getScreenHeight();
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvBack = findViewById(R.id.iv_back);
+ xBanner = findViewById(R.id.gift_wall_achieve_banner);
+ textAchieveName = findViewById(R.id.text_achieve_name);
+ textAchieveHint = findViewById(R.id.text_achieve_hint);
+ btnConfirm = findViewById(R.id.btn_confirm);
+ findViewById(R.id.btn_cancel).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dialog.dismiss();
+ }
+ });
+ btnConfirm.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (achieveWearModels.get(selectPosition).getUseStatus().equals("0") && achieveWearModels.get(selectPosition).getDressStatus().equals("2")) {
+ LiveNetManager.get(mContext).userUseDress(
+ achieveWearModels.get(selectPosition).getUsersDressId(), new HttpCallback() {
+ @Override
+ public void onSuccess(HttpCallbackModel data) {
+ ToastUtil.show(data.getMsg());
+ if (data.getCode() == 0) {
+ UserBean u = CommonAppConfig.getInstance().getUserBean();
+ u.setMedal_no_display_src(achieveWearModels.get(selectPosition).getDisplaySrc());
+ CommonAppConfig.getInstance().setUserBean(u);
+ if (userUseDressSuccess != null) {
+ userUseDressSuccess.onSuccess();
+ }
+ dialog.dismiss();
+ }
+ }
+
+ @Override
+ public void onError(String error) {
+
+ }
+ });
+ }
+ }
+ });
+ btnConfirm.setVisibility(CommonAppConfig.getInstance().getUid().equals(toUid) ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+ /*RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mIvBack.getLayoutParams();
+ if (isFullWindows) {
+ params.width=DpUtil.dp2px(20);
+ mIvBack.setVisibility(View.VISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ } else {
+ params.width=DpUtil.dp2px(1);
+ mIvBack.setVisibility(View.INVISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.FIT_XY);
+ }
+ mIvBack.setLayoutParams(params);*/
+ initData();
+ }
+
+ public void setWearInfo() {
+ textAchieveName.setText(achieveWearModels.get(selectPosition).getDressName());
+ textAchieveHint.setText(achieveWearModels.get(selectPosition).getDressDescription());
+ btnConfirm.setText(achieveWearModels.get(selectPosition).getUseStatus().equals("1") ? wearing : putOn);
+ if (achieveWearModels.get(selectPosition).getUseStatus().equals("0") && achieveWearModels.get(selectPosition).getDressStatus().equals("2")) {
+ btnConfirm.setBackground(getResources().getDrawable(R.drawable.gift_wall_achieve_wear_sure));
+ } else {
+ btnConfirm.setBackground(getResources().getDrawable(R.drawable.gift_wall_achieve_wear_disable));
+ }
+ }
+
+ private void initData() {
+ setWearInfo();
+ xBanner.setBannerData(R.layout.dialog_gift_wall_achieve_wear_item, achieveWearModels);
+ //xBanner.setCustomPageTransformer(new LiveGuardScalePageTransformer());
+ xBanner.setCustomPageTransformer(new LiveGifWallAchieveWearTransformer());
+ xBanner.setIsClipChildrenMode(true);
+ //xBanner.setCustomPageTransformer(BasePageTransformer.getPageTransformer(Transformer.Zoom));
+ xBanner.getViewPager().setOffscreenPageLimit(3);
+ xBanner.loadImage(new XBanner.XBannerAdapter() {
+ @Override
+ public void loadBanner(XBanner banner, Object model, View view, int position) {
+ UserMedalModel guardBannerModel = ((UserMedalModel) model);
+ ImageView wearImg = view.findViewById(R.id.wearImg);
+ ImageView notUnlocked = view.findViewById(R.id.notUnlocked);
+ ImgLoader.display(getContext(), guardBannerModel.getDisplaySrc(), wearImg);
+ notUnlocked.setVisibility(guardBannerModel.getDressStatus().equals("1") ? VISIBLE : View.GONE);
+ }
+ });
+ xBanner.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int i, float v, int i1) {
+
+ }
+
+ @Override
+ public void onPageSelected(int i) {
+ selectPosition = i;
+ setWearInfo();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int i) {
+
+ }
+ });
+ // xBanner.getViewPager().setCurrentItem(useIndex); //自动定位到已佩戴到的勋章
+ }
+
+ public interface UserUseDressSuccess {
+ void onSuccess();
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallDialog.java
new file mode 100644
index 000000000..3b016f84d
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallDialog.java
@@ -0,0 +1,228 @@
+package com.yunbao.common.dialog;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.lxj.xpopup.XPopup;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallBean;
+import com.yunbao.common.fragment.BaseFragment;
+import com.yunbao.common.fragment.GiftWallMainTab1Fragment;
+import com.yunbao.common.fragment.GiftWallMainTab2Fragment;
+import com.yunbao.common.interfaces.OnItemClickListener;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.CustomEllipsizeTextView;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * 礼物墙
+ */
+public class GiftWallDialog extends AbsDialogPopupWindow {
+
+ private ImageView mIvBg;
+ private ImageView mIvTips;
+ private ImageView mIvBack;
+ private CustomEllipsizeTextView mTvUserName;
+ private View mAchievement;
+ private TextView mTvTab1, mTvTab2;
+ private ViewPager2 mViewPager;
+ private LinearLayout mIvTabsLayout;
+ private List fragments = new ArrayList<>();
+ private String anchorId;
+
+ private boolean isFullWindows;
+ String toUserId;
+ String userName;
+ boolean isAnchor;
+ boolean isTab2;
+
+ public GiftWallDialog(@NonNull Context context, String toUserId, String userName, String anchorId, boolean isAnchor) {
+ super(context);
+ this.toUserId = toUserId;
+ this.isAnchor = isAnchor;
+ this.userName = userName;
+ this.anchorId = anchorId;
+ }
+
+ public GiftWallDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+ public GiftWallDialog setTab2(boolean isTab2) {
+ this.isTab2 = isTab2;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight() - DpUtil.dp2px(10);
+ }
+ int screenHeight = ScreenDimenUtil.getInstance().getScreenHeight();
+ return (int) (screenHeight * 0.8);
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvTips = findViewById(R.id.v_tips);
+ mIvBack = findViewById(R.id.iv_back);
+ mTvUserName = findViewById(R.id.user_name);
+ mAchievement = findViewById(R.id.v_achievement);
+ mTvTab1 = findViewById(R.id.tab1);
+ mTvTab2 = findViewById(R.id.tab2);
+ mViewPager = findViewById(R.id.viewPager2);
+ mIvTabsLayout = findViewById(R.id.tab_layout);
+
+ mTvUserName.setText(String.format(Locale.getDefault(), "%s%s",
+ userName,
+ WordUtil.isNewZh() ? "的禮物展館" : "'s Gift Hall"
+ ));
+
+ fragments.add(new GiftWallMainTab1Fragment().setToUserId(toUserId).setAnchor(isAnchor).setAnchorId(anchorId).setLiveRoom(!isFullWindows).setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(GiftWallBean bean, int position) {
+ if (position == 1) {
+ if (toUserId.equals(IMLoginManager.get(mContext).getUserInfo().getId() + "")) {
+ mAchievement.setVisibility(View.VISIBLE);
+ } else {
+ mAchievement.setVisibility(View.INVISIBLE);
+ }
+ } else {
+ mAchievement.setVisibility(View.VISIBLE);
+ }
+ }
+ }));
+ fragments.add(new GiftWallMainTab2Fragment().setToUserId(toUserId).setAnchorId(anchorId).setAnchor(isAnchor).setLiveRoom(!isFullWindows));
+ mViewPager.setAdapter(new FragmentStateAdapter((FragmentActivity) mContext) {
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ return fragments.get(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return fragments.size();
+ }
+ });
+ mViewPager.setUserInputEnabled(false);
+ mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ fragments.get(position).updateData();
+ if (position == 0) {
+ mTvUserName.setTextColor(Color.parseColor("#6BCDFF"));
+ } else {
+ mTvUserName.setTextColor(Color.parseColor("#FFCF94"));
+ if (isTab2) {
+ ((GiftWallMainTab2Fragment) fragments.get(position)).setTab2();
+ }
+ }
+ }
+ });
+ if (isTab2) {
+ mViewPager.setCurrentItem(1);
+ }
+
+ ViewClicksAntiShake.clicksAntiShake(mTvTab1, () -> {
+ mIvBg.setImageResource(R.mipmap.bg_gift_wall_main_root);
+ mIvTabsLayout.setBackgroundResource(R.mipmap.icon_gift_wall_main_switch_main);
+ mTvTab1.setTextColor(Color.parseColor("#9CE7FF"));
+ mTvTab1.setTextSize(16);
+ mTvTab1.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+
+ mTvTab2.setTextColor(Color.parseColor("#FFFFFF"));
+ mTvTab2.setTextSize(14);
+ mTvTab2.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
+ mViewPager.setCurrentItem(0, false);
+ });
+ ViewClicksAntiShake.clicksAntiShake(mTvTab2, () -> {
+
+ mIvBg.setImageResource(R.mipmap.bg_gift_wall_main_root2);
+ mIvTabsLayout.setBackgroundResource(R.mipmap.icon_gift_wall_main_switch_full);
+ mTvTab1.setTextColor(Color.parseColor("#FDF5EE"));
+ mTvTab1.setTextSize(14);
+ mTvTab1.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
+
+ mTvTab2.setTextColor(Color.parseColor("#FFC593"));
+ if (WordUtil.isNewZh()) {
+ mTvTab2.setTextSize(16);
+ } else {
+ mTvTab2.setTextSize(14.5f);
+ }
+ mTvTab2.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+ mViewPager.setCurrentItem(1, false);
+ });
+ ViewClicksAntiShake.clicksAntiShake(mAchievement, () -> {
+ new GiftWallAchieveDialog(mContext).setFullWindows(isFullWindows).setAnchor(isAnchor).setToUid(toUserId).showDialog();
+ });
+ ViewClicksAntiShake.clicksAntiShake(mIvTips, () -> {
+ new GiftWallRuleDialog(mContext).setFullWindows(isFullWindows).showDialog();
+ });
+ resetWindows();
+ if (isTab2) {
+ mTvTab2.callOnClick();
+ }
+ }
+
+ private void resetWindows() {
+ if (isFullWindows) {
+ ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) findViewById(R.id.v_achievement).getLayoutParams();
+ params.topMargin = DpUtil.dp2px(47);
+ findViewById(R.id.v_achievement).setLayoutParams(params);
+ }
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+ ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) mIvBack.getLayoutParams();
+ if (isFullWindows) {
+ params.width = DpUtil.dp2px(20);
+ mIvBack.setVisibility(View.VISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ } else {
+ params.width = DpUtil.dp2px(1);
+ mIvBack.setVisibility(View.INVISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.FIT_XY);
+ }
+ mIvBack.setLayoutParams(params);
+ ViewClicksAntiShake.clicksAntiShake(mIvBack, this::dismiss);
+ }
+
+
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallGiftInfoDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallGiftInfoDialog.java
new file mode 100644
index 000000000..6b554682f
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallGiftInfoDialog.java
@@ -0,0 +1,478 @@
+package com.yunbao.common.dialog;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.widget.NestedScrollView;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.lxj.xpopup.XPopup;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.opensource.svgaplayer.SVGADrawable;
+import com.opensource.svgaplayer.SVGAImageView;
+import com.opensource.svgaplayer.SVGAParser;
+import com.opensource.svgaplayer.SVGAVideoEntity;
+import com.yunbao.common.R;
+import com.yunbao.common.adapter.GiftWallGiftInfoListItemAdapter;
+import com.yunbao.common.bean.GiftWallInfoBean;
+import com.yunbao.common.bean.JsWishBean;
+import com.yunbao.common.custom.ItemDecoration;
+import com.yunbao.common.event.ClosePopupDialogEvent;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.http.base.HttpCallback;
+import com.yunbao.common.http.live.LiveNetManager;
+import com.yunbao.common.interfaces.OnItemClickListener;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.Bus;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.Locale;
+
+public class GiftWallGiftInfoDialog extends AbsDialogPopupWindow {
+ private boolean isFullWindows;
+ private ImageView mIvBg;
+ private ImageView mIvBack;
+ TextView giftName;
+ ImageView gift;
+ SVGAImageView gift_bg;
+ TextView diamond_text;
+ TextView gift_tv_progress;
+ TextView gift_tv_max;
+ ProgressBar gift_progress;
+ Button gift_btn;
+ Button tab1, tab2;
+ ImageView tips_timer;
+ TextView tv_list_title;
+ RoundedImageView avatar;
+ TextView user_name;
+ TextView send_num;
+ TextView btn_one;
+ Button btn_one_tips;
+ Button btn_lighten;
+ View tab_layout;
+ View bottom_layout;
+ View gift_schedule;
+ ImageView diamond_icon;
+
+ GiftWallGiftInfoListItemAdapter adapter;
+ RecyclerView recyclerView;
+
+ String giftId;
+ String toUserId;
+ String anchorId;
+ boolean isAnchor;
+ int gift_hall_type = 1;
+ int list_type = 2;
+ private boolean isLiveRoom;
+ String time;
+ private boolean isStar;
+ private boolean isTab2Enter = false;
+
+
+ public GiftWallGiftInfoDialog(Context context, String giftId, String toUserId, boolean isAnchor) {
+ super(context);
+ this.giftId = giftId;
+ this.toUserId = toUserId;
+ this.isAnchor = isAnchor;
+ }
+
+ public GiftWallGiftInfoDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+ public GiftWallGiftInfoDialog setTab2Enter(boolean tab2Enter) {
+ isTab2Enter = tab2Enter;
+ return this;
+ }
+
+ public GiftWallGiftInfoDialog setAnchorId(String anchorId) {
+ this.anchorId = anchorId;
+ return this;
+ }
+
+ public GiftWallGiftInfoDialog setLiveRoom(boolean isLiveRoom) {
+ this.isLiveRoom = isLiveRoom;
+ return this;
+ }
+
+ public GiftWallGiftInfoDialog setStar(boolean isStar) {
+ this.isStar = isStar;
+ return this;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight();
+ }
+ int screenHeight = ScreenDimenUtil.getInstance().getScreenHeight();
+ return (int) (screenHeight * 0.8);
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_gift_info;
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+ initData();
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvBack = findViewById(R.id.iv_back);
+ diamond_icon = findViewById(R.id.diamond_icon);
+ giftName = findViewById(R.id.gift_name);
+ gift = findViewById(R.id.gift);
+ diamond_text = findViewById(R.id.diamond_text);
+ gift_tv_progress = findViewById(R.id.gift_tv_progress);
+ gift_tv_max = findViewById(R.id.gift_tv_max);
+ gift_progress = findViewById(R.id.gift_progress);
+ gift_btn = findViewById(R.id.gift_btn);
+ tab1 = findViewById(R.id.tab1);
+ tab2 = findViewById(R.id.tab2);
+ tips_timer = findViewById(R.id.tips_timer);
+ tv_list_title = findViewById(R.id.tv_list_title);
+ avatar = findViewById(R.id.bottom_avatar);
+ user_name = findViewById(R.id.bottom_user_name);
+ send_num = findViewById(R.id.send_num);
+ btn_one = findViewById(R.id.btn_one);
+ btn_one_tips = findViewById(R.id.btn_one_tips);
+ gift_bg = findViewById(R.id.gift_bg);
+ btn_lighten = findViewById(R.id.btn_lighten);
+ recyclerView = findViewById(R.id.recyclerView);
+ tab_layout = findViewById(R.id.tab_layout);
+ bottom_layout = findViewById(R.id.bottom_layout);
+ gift_schedule = findViewById(R.id.gift_schedule);
+ adapter = new GiftWallGiftInfoListItemAdapter();
+ adapter.setAnchor(isAnchor);
+ adapter.setLiveRoom(isLiveRoom);
+ adapter.setStar(isStar);
+ recyclerView.setAdapter(adapter);
+ recyclerView.addItemDecoration(new ItemDecoration(mContext, 0x00000000, 0, 10));
+
+ initTabText();
+
+ findViewById(R.id.item_anchor_name).setVisibility(View.GONE);
+ ViewClicksAntiShake.clicksAntiShake(tab1, () -> {
+
+ btn_one.setVisibility(View.GONE);
+ btn_one_tips.setVisibility(View.GONE);
+
+ tab1.setBackgroundResource(R.drawable.gift_wall_gift_info_list_btn_up);
+ tab1.setTextColor(Color.parseColor("#31326D"));
+
+ tab2.setBackgroundResource(R.drawable.gift_wall_gift_info_list_btn_down);
+ tab2.setTextColor(Color.parseColor("#FFFFFF"));
+ list_type = 1;
+ adapter.setList_type(list_type);
+ ((TextView) findViewById(R.id.user_name)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_assistance_user));
+ ((TextView) findViewById(R.id.tv_rename)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_assistance_star));
+ initData();
+ });
+ ViewClicksAntiShake.clicksAntiShake(tab2, () -> {
+ btn_one.setVisibility(View.VISIBLE);
+ btn_one_tips.setVisibility(View.VISIBLE);
+
+ tab2.setBackgroundResource(R.drawable.gift_wall_gift_info_list_btn_up);
+ tab2.setTextColor(Color.parseColor("#31326D"));
+
+ tab1.setBackgroundResource(R.drawable.gift_wall_gift_info_list_btn_down);
+ tab1.setTextColor(Color.parseColor("#FFFFFF"));
+ list_type = 2;
+ adapter.setList_type(list_type);
+ initTabText();
+ initData();
+ });
+ XPopup.Builder builder = new XPopup.Builder(getContext())
+ .atView(tips_timer);
+ builder.hasShadowBg(false);
+ tips_timer.setTag(builder);
+ ViewClicksAntiShake.clicksAntiShake(tips_timer, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ XPopup.Builder b = (XPopup.Builder) tips_timer.getTag();
+ b.asCustom(new GiftWallMainTab1TipsDialog(mContext, new OnItemClickListener() {
+ @Override
+ public void onItemClick(Integer bean, int position) {
+
+ }
+ }).setTime(time)).show();
+ }
+ });
+ ViewClicksAntiShake.clicksAntiShake(btn_one, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ Bus.get().post(new JsWishBean(giftId));//setUname==by
+ Bus.get().post(new ClosePopupDialogEvent());
+ }
+ });
+ ViewClicksAntiShake.clicksAntiShake(gift_btn, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ Bus.get().post(new JsWishBean(giftId));//setUname==by
+ Bus.get().post(new ClosePopupDialogEvent());
+ }
+ });
+
+ ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) mIvBack.getLayoutParams();
+ if (isFullWindows) {
+ params.width = DpUtil.dp2px(20);
+ mIvBack.setVisibility(View.VISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ } else {
+ params.width = DpUtil.dp2px(20);
+ mIvBack.setVisibility(View.VISIBLE);
+ mIvBg.setScaleType(ImageView.ScaleType.FIT_XY);
+ }
+ mIvBack.setLayoutParams(params);
+ ViewClicksAntiShake.clicksAntiShake(mIvBack, this::dismiss);
+ resetWindows();
+ }
+
+ private void initTabText() {
+ if (isStar) {
+ tab2.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_title_star));
+ ((TextView) findViewById(R.id.user_name)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_list_header_rename1));
+ ((TextView) findViewById(R.id.tv_rename)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_list_header_rename_value1));
+ tv_list_title.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_title_star));
+ } else {
+ tab2.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_title_champion));
+ tv_list_title.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_title_champion));
+ ((TextView) findViewById(R.id.user_name)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_list_header_rename));
+ ((TextView) findViewById(R.id.tv_rename)).setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_list_header_rename_value));
+ }
+ }
+
+ private void resetWindows() {
+ if (isFullWindows) {
+ ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) findViewById(R.id.gift_name).getLayoutParams();
+ params.topMargin = DpUtil.dp2px(47);
+ findViewById(R.id.gift_name).setLayoutParams(params);
+ }
+ }
+
+ void initData() {
+ adapter.setList_type(list_type);
+ if (isAnchor) {
+ if (isStar) {
+ gift_hall_type = 2;
+ } else {
+ gift_hall_type = 1;
+ }
+ LiveNetManager.get(mContext)
+ .liveGiftHallDetail(toUserId, giftId, gift_hall_type, list_type, new HttpCallback() {
+ @Override
+ public void onSuccess(GiftWallInfoBean data) {
+ initData(data);
+ }
+
+ @Override
+ public void onError(String error) {
+
+ }
+ });
+ } else {
+ LiveNetManager.get(mContext)
+ .singleUserGiftHallDetail(toUserId, giftId, new HttpCallback() {
+ @Override
+ public void onSuccess(GiftWallInfoBean data) {
+ initData(data);
+ }
+
+ @Override
+ public void onError(String error) {
+
+ }
+ });
+ }
+
+
+ }
+
+ void initData(GiftWallInfoBean giftBean) {
+ giftName.setText(WordUtil.isNewZh() ? giftBean.getGift_info().getGiftname() : giftBean.getGift_info().getGiftname_en());
+ ImgLoader.display(mContext, giftBean.getGift_info().getGifticon(), gift);
+ diamond_text.setText(String.format(Locale.getDefault(), "%d", giftBean.getGift_info().getNeedcoin()));
+ gift_tv_max.setText(String.format(Locale.getDefault(), "/%s", giftBean.getGift_info().getIlluminate_num()));
+ gift_tv_progress.setText(String.format(Locale.getDefault(), "%s", giftBean.getGift_info().getGift_hall_send_num()));
+ gift_progress.setMax(giftBean.getGift_info().getIlluminate_num());
+ gift_progress.setProgress(Integer.parseInt(giftBean.getGift_info().getGift_hall_send_num()));
+ if (giftBean.getGift_info().getSendtype() == 0) {
+ diamond_icon.setImageResource(R.mipmap.diamond);
+ } else {
+ diamond_icon.setImageResource(R.mipmap.gold_coin);
+ }
+ if (giftBean.getGift_info().getIlluminate_status() == 1) {
+ gift_btn.setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_top_btn_continue));
+ btn_lighten.setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_spinner_up));
+ btn_lighten.setBackgroundResource(R.drawable.gift_wall_gift_info_lighten);
+ } else {
+ gift_btn.setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_info_top_btn_to));
+ btn_lighten.setText(WordUtil.getNewString(R.string.dialog_gift_wall_list_spinner_down));
+ btn_lighten.setBackgroundResource(R.drawable.gift_wall_gift_info_un_lighten);
+ }
+ adapter.setGiftStatus(giftBean.getGift_info().getIlluminate_status());
+ /**
+ * 如果对方是主播,要有点亮标记。
+ * 如果对方是用户,不要有点亮标记
+ *
+ */
+ if (isAnchor) {
+ tab_layout.setVisibility(View.VISIBLE);
+ bottom_layout.setVisibility(View.VISIBLE);
+ tv_list_title.setVisibility(View.GONE);
+ if (isTab2Enter) {
+ tab_layout.setVisibility(View.GONE);
+ bottom_layout.setVisibility(View.GONE);
+ tv_list_title.setVisibility(View.VISIBLE);
+ }
+ } else {
+ tab_layout.setVisibility(View.GONE);
+ bottom_layout.setVisibility(View.GONE);
+ tv_list_title.setVisibility(View.VISIBLE);
+ gift_progress.setVisibility(View.GONE);
+ gift_schedule.setVisibility(View.GONE);
+ if (isTab2Enter || ((!toUserId.equals(IMLoginManager.get(mContext).getUserInfo().getId() + "")) && !isTab2Enter)) {
+ gift_btn.setVisibility(View.GONE);
+ } else {
+ System.out.println("---------------显示 " + toUserId + " " + IMLoginManager.get(mContext).getUserInfo().getId() + "|" + isTab2Enter);
+ }
+ }
+
+ if (!isLiveRoom || giftBean.getGift_info().getGift_status() == 0) {
+ gift_btn.setEnabled(false);
+ btn_one.setEnabled(false);
+ gift_btn.setBackgroundResource(R.drawable.gift_wall_gift_info_btn_un);
+ btn_one.setBackgroundResource(R.drawable.gift_wall_gift_info_btn_un);
+ }
+ adapter.setData(giftBean.getData());
+ time = (WordUtil.isNewZh() ? "榜單結算時間:" : "Settlement time:") + giftBean.getGift_info().getGift_hall_start() + " - " + giftBean.getGift_info().getGift_hall_end();
+ ImgLoader.display(mContext, IMLoginManager.get(mContext).getUserInfo().getAvatar(), avatar);
+ user_name.setText(IMLoginManager.get(mContext).getUserInfo().getUserNicename());
+ send_num.setText(String.format(Locale.getDefault(), "%s", giftBean.getGift_info().getUser_gift_hall_send_num()));
+
+ String tmp = "";
+ if (giftBean.getGift_info().getIlluminate_status() != 1) {//未點亮
+ btn_one.setText(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_light);
+ tmp = String.format(Locale.getDefault(), "%s", (giftBean.getGift_info().getIlluminate_num() - Integer.parseInt(giftBean.getGift_info().getGift_hall_send_num())));
+ setTips(tmp);
+ } else {//冠名/摘星
+ if (isStar) {
+ loadStar(giftBean);
+ } else {
+ loadChampion(giftBean);
+ }
+ }
+
+ initAnim();
+ }
+
+ private void setTips(String tmp) {
+ btn_one_tips.setVisibility(View.VISIBLE);
+ btn_one_tips.setText(String.format(Locale.getDefault(), "%s%s%s"
+ , WordUtil.isNewZh() ? "需 " : "Need ",
+ tmp,
+ WordUtil.isNewZh() ? "" : ""));
+ }
+
+ private void loadChampion(GiftWallInfoBean giftBean) {
+ int tmp = 0;
+ int mySend = giftBean.getGift_info().getUser_gift_hall_send_num();
+ if (giftBean.getData() != null && !giftBean.getData().isEmpty()) {
+ tmp = giftBean.getData().get(0).getGift_hall_send_num() - giftBean.getGift_info().getUser_gift_hall_send_num() + 1;
+ }
+ System.out.println("冠名数据 我发的 = " + mySend + " 检测的 = " + tmp + " 第一名id = " + giftBean.getData().get(0).getUser_id() + " 我的id = " + IMLoginManager.get(mContext).getUserInfo().getId());
+ if (mySend > tmp || giftBean.getData().get(0).getUser_id().equals(IMLoginManager.get(mContext).getUserInfo().getId() + "")) {
+ btn_one.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_champion_get));
+ btn_one_tips.setVisibility(View.GONE);
+ } else {
+ btn_one.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_champion));
+ setTips(String.valueOf(tmp));
+ }
+ }
+
+ private void loadStar(GiftWallInfoBean giftBean) {
+ int tmp = 0;
+ int mySend = giftBean.getGift_info().getUser_gift_hall_send_num();
+ if (giftBean.getData() != null && !giftBean.getData().isEmpty()) {
+ tmp = giftBean.getData().get(0).getGift_hall_send_num() - giftBean.getGift_info().getUser_gift_hall_send_num() + 1;
+ }
+ if (mySend > tmp || giftBean.getData().get(0).getUser_id().equals(IMLoginManager.get(mContext).getUserInfo().getId() + "")) {
+ btn_one.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_star_get));
+ btn_one_tips.setVisibility(View.GONE);
+ } else {
+ btn_one.setText(WordUtil.getNewString(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_star));
+ setTips(String.valueOf(tmp));
+ }
+ }
+
+ void initAnim() {
+ if (gift.getTag() != null) {
+ return;
+ }
+ // 创建一个向上移动的动画
+ ObjectAnimator upAnimator = ObjectAnimator.ofFloat(gift, "translationY", 0f, -10f); // 假设 10f 是你想要移动的距离(注意:这里使用的是像素值,而不是 dp)
+ upAnimator.setDuration(1000); // 设置动画时长为 1000 毫秒(即 1 秒)
+ // 创建一个向下移动的动画
+ ObjectAnimator downAnimator = ObjectAnimator.ofFloat(gift, "translationY", -10f, 0f);
+ downAnimator.setDuration(1000); // 同样设置动画时长为 1 秒
+ // 设置动画监听器以在向上动画结束后开始向下动画(如果需要的话)
+ upAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ // 在这里开始向下动画
+ downAnimator.start();
+ }
+ });
+ downAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ gift.postDelayed(upAnimator::start, 1000);
+ }
+ });
+ // 开始向上动画
+ upAnimator.start();
+ gift.setTag("start");
+
+ new SVGAParser(getContext()).decodeFromAssets("gift_wall_gift_info_light.svga", new SVGAParser.ParseCompletion() {
+ @Override
+ public void onComplete(@NonNull SVGAVideoEntity videoItem) {
+ gift_bg.setImageDrawable(new SVGADrawable(videoItem));
+ gift_bg.setLoops(0);
+ gift_bg.startAnimation();
+ }
+
+ @Override
+ public void onError() {
+ System.err.println("-------------SVGA报错了");
+ }
+ }, null);
+ }
+
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1List2SpinnerDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1List2SpinnerDialog.java
new file mode 100644
index 000000000..1bc190d9f
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1List2SpinnerDialog.java
@@ -0,0 +1,60 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.lxj.xpopup.core.AttachPopupView;
+import com.yunbao.common.R;
+import com.yunbao.common.interfaces.OnItemClickListener;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+public class GiftWallMainTab1List2SpinnerDialog extends AttachPopupView {
+ TextView all, up, down;
+ OnItemClickListener listener;
+ int type=0;
+
+ public GiftWallMainTab1List2SpinnerDialog(@NonNull Context context,int type, OnItemClickListener listener) {
+ super(context);
+ this.listener = listener;
+ this.type=type;
+ }
+
+ @Override
+ protected void onDismiss() {
+ super.onDismiss();
+ listener.onItemClick(-1, 0);
+ }
+
+ @Override
+ protected int getImplLayoutId() {
+ return R.layout.dialog_gift_wall_main_tab1_list2_spinner;
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ all = findViewById(R.id.spinner_all);
+ up = findViewById(R.id.spinner_up);
+ down = findViewById(R.id.spinner_down);
+ if(type==1){
+ up.setText(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_champion_get);
+ down.setText(R.string.dialog_gift_wall_gfit_info_list_bottom_btn_one_champion_get_un);
+ }
+ ViewClicksAntiShake.clicksAntiShake(all, () -> {
+ listener.onItemClick(0, 0);
+ dismiss();
+ });
+
+ ViewClicksAntiShake.clicksAntiShake(up, () -> {
+ listener.onItemClick(1, 0);
+ dismiss();
+ });
+
+ ViewClicksAntiShake.clicksAntiShake(down, () -> {
+ listener.onItemClick(2, 0);
+ dismiss();
+ });
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1TipsDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1TipsDialog.java
new file mode 100644
index 000000000..72a1794c5
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab1TipsDialog.java
@@ -0,0 +1,48 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.lxj.xpopup.core.AttachPopupView;
+import com.yunbao.common.R;
+import com.yunbao.common.interfaces.OnItemClickListener;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+public class GiftWallMainTab1TipsDialog extends AttachPopupView {
+ TextView tips;
+ OnItemClickListener listener;
+ String time;
+
+ public GiftWallMainTab1TipsDialog(@NonNull Context context, OnItemClickListener listener) {
+ super(context);
+ this.listener = listener;
+ }
+
+ public GiftWallMainTab1TipsDialog setTime(String time) {
+ this.time = time;
+ return this;
+ }
+
+ @Override
+ protected void onDismiss() {
+ super.onDismiss();
+ listener.onItemClick(-1, 0);
+ }
+
+ @Override
+ protected int getImplLayoutId() {
+ return R.layout.dialog_gift_wall_main_tab1_tips;
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ tips = findViewById(R.id.tips);
+ tips.setText(time);
+ ViewClicksAntiShake.clicksAntiShake(tips, () -> {
+ listener.onItemClick(0, 0);
+ });
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab2ClassicInfoDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab2ClassicInfoDialog.java
new file mode 100644
index 000000000..9c42cc9e8
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallMainTab2ClassicInfoDialog.java
@@ -0,0 +1,229 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.lxj.xpopup.XPopup;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.yunbao.common.R;
+import com.yunbao.common.adapter.GiftWallTab2GiftInfoListItemAdapter;
+import com.yunbao.common.bean.GiftWallMainTab2ClassicInfoBean;
+import com.yunbao.common.bean.GiftWallTab2Bean;
+import com.yunbao.common.custom.ItemDecoration;
+import com.yunbao.common.fragment.BaseFragment;
+import com.yunbao.common.fragment.GiftWallMainTab1Fragment;
+import com.yunbao.common.fragment.GiftWallMainTab2Fragment;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.http.base.HttpCallback;
+import com.yunbao.common.http.live.LiveNetManager;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.RouteUtil;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.ToastUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.CustomEllipsizeTextView;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class GiftWallMainTab2ClassicInfoDialog extends AbsDialogPopupWindow {
+
+ private ImageView mIvBg;
+ private ImageView mIvTips;
+ private ImageView mIvBack;
+ private ImageView mIvGift;
+ private RoundedImageView user_avatar;
+ private TextView mTvUserName;
+ private TextView star_value;
+ private RoundedImageView user_avatar_1, user_avatar_2, user_avatar_3;
+ private TextView user_name_1, user_name_2, user_name_3;
+ private TextView user_value_1, user_value_2, user_value_3;
+ private TextView gift_name;
+ private View mAchievement;
+ private TextView mTvTab1, mTvTab2;
+ private ViewPager2 mViewPager;
+ private LinearLayout mIvTabsLayout;
+ private List fragments = new ArrayList<>();
+ private RecyclerView recyclerView;
+ GiftWallTab2GiftInfoListItemAdapter adapter;
+ private boolean isFullWindows;
+ GiftWallTab2Bean.Gift gift;
+ String userName;
+ boolean isAnchor;
+
+ public GiftWallMainTab2ClassicInfoDialog(@NonNull Context context, GiftWallTab2Bean.Gift gift, boolean isAnchor) {
+ super(context);
+ this.gift = gift;
+ this.isAnchor = isAnchor;
+
+ }
+
+ public GiftWallMainTab2ClassicInfoDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_tab2_classic_info;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight();
+ }
+ int screenHeight = ScreenDimenUtil.getInstance().getScreenHeight();
+ return (int) (screenHeight * 0.8);
+ }
+
+ void initData() {
+ LiveNetManager.get(mContext).lastAllGiftHallWeekStarDetail(gift.getGiftId() + "", gift.getNamingLiveId() + "", new HttpCallback() {
+ @Override
+ public void onSuccess(GiftWallMainTab2ClassicInfoBean data) {
+ initData(data);
+ }
+
+ @Override
+ public void onError(String error) {
+
+ }
+ });
+ }
+
+ void initData(GiftWallMainTab2ClassicInfoBean data) {
+ ImgLoader.display(mContext, data.getGiftInfo().getGiftIcon(), mIvGift);
+ if (data.getGiftInfo().getNamingLiveActiveRankHide() == 0 || data.getGiftInfo().getNamingLiveId() == IMLoginManager.get(mContext).getUserInfo().getId()) {
+ ImgLoader.display(mContext, data.getGiftInfo().getNamingLiveAvatar(), user_avatar);
+ mTvUserName.setText(data.getGiftInfo().getNamingLiveNicename());
+ } else {
+ user_avatar.setImageResource(R.mipmap.hide);
+ mTvUserName.setText(WordUtil.getNewString(R.string.mystery_man));
+ }
+ gift_name.setText(WordUtil.isNewZh() ? data.getGiftInfo().getGiftName() : data.getGiftInfo().getGiftNameEn());
+ star_value.setText(String.format(Locale.getDefault(), "%d", data.getGiftInfo().getGiftHallSendNum()));
+ int max = data.getData().size() > 3 ? 3 : 0;
+ if (max != 0) {
+ adapter.setData(data.getData().subList(max, data.getData().size()));
+ }
+ for (int i = 0; i < data.getData().size() && i < 3; i++) {
+ switch (i) {
+ case 0:
+ setTopData(data.getData().get(0), user_avatar_1, user_name_1, user_value_1);
+ break;
+ case 1:
+ setTopData(data.getData().get(1), user_avatar_2, user_name_2, user_value_2);
+ break;
+ case 2:
+ setTopData(data.getData().get(2), user_avatar_3, user_name_3, user_value_3);
+ break;
+ }
+ }
+ ViewClicksAntiShake.clicksAntiShake(user_avatar, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ if (data.getGiftInfo().getNamingLiveActiveRankHide() == 0) {
+ RouteUtil.forwardUserHome(mContext, String.valueOf(data.getGiftInfo().getNamingLiveId()), 0);
+ }
+ }
+ });
+ }
+
+ void setTopData(GiftWallMainTab2ClassicInfoBean.GiftData data, ImageView avatar, TextView name, TextView value) {
+ if (data.getNaming_user_gift_hall_rank_hide() == 1 && Integer.parseInt(data.getUserId()) != IMLoginManager.get(mContext).getUserInfo().getId()) {
+ avatar.setImageResource(R.mipmap.hide);
+ name.setText(WordUtil.getNewString(R.string.mystery_man));
+ return;
+ }
+ ImgLoader.display(mContext, data.getAvatar(), avatar);
+ name.setText(data.getUserName());
+ value.setText(String.format(Locale.getDefault(), "%d", data.getGiftHallSendNum()));
+ ViewClicksAntiShake.clicksAntiShake(avatar, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ if (data.getActiveRankHide() == 0) {
+ RouteUtil.forwardUserHome(mContext, String.valueOf(data.getUserId()), 0);
+ }
+ }
+ });
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvTips = findViewById(R.id.v_tips);
+ mIvBack = findViewById(R.id.iv_back);
+ mTvUserName = findViewById(R.id.anchor_name);
+ mAchievement = findViewById(R.id.v_achievement);
+ mTvTab1 = findViewById(R.id.tab1);
+ mTvTab2 = findViewById(R.id.tab2);
+ mViewPager = findViewById(R.id.viewPager2);
+ mIvTabsLayout = findViewById(R.id.tab_layout);
+ mIvGift = findViewById(R.id.gift);
+ gift_name = findViewById(R.id.gift_name);
+ user_avatar = findViewById(R.id.user_avatar);
+ star_value = findViewById(R.id.star_value);
+ user_avatar_1 = findViewById(R.id.user_avatar_1);
+ user_avatar_2 = findViewById(R.id.user_avatar_2);
+ user_avatar_3 = findViewById(R.id.user_avatar_3);
+ user_name_1 = findViewById(R.id.user_name_1);
+ user_name_2 = findViewById(R.id.user_name_2);
+ user_name_3 = findViewById(R.id.user_name_3);
+ user_value_1 = findViewById(R.id.user_value_1);
+ user_value_2 = findViewById(R.id.user_value_2);
+ user_value_3 = findViewById(R.id.user_value_3);
+ recyclerView = findViewById(R.id.recycler_view);
+ adapter = new GiftWallTab2GiftInfoListItemAdapter();
+ recyclerView.setAdapter(adapter);
+ recyclerView.addItemDecoration(new ItemDecoration(mContext, 0x000, 0, DpUtil.dp2px(2)));
+
+ ViewClicksAntiShake.clicksAntiShake(mIvBack, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ dismiss();
+ }
+ });
+
+ initData();
+ resetWindows();
+ }
+
+ private void resetWindows() {
+ if (isFullWindows) {
+ ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) findViewById(R.id.iv_back).getLayoutParams();
+ params.topMargin = DpUtil.dp2px(47);
+ findViewById(R.id.iv_back).setLayoutParams(params);
+ params = (ConstraintLayout.LayoutParams) findViewById(R.id.scrollView).getLayoutParams();
+ params.topMargin = DpUtil.dp2px(47);
+ findViewById(R.id.scrollView).setLayoutParams(params);
+ }
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallRuleDialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallRuleDialog.java
new file mode 100644
index 000000000..70d0897c2
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallRuleDialog.java
@@ -0,0 +1,106 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.lxj.xpopup.XPopup;
+import com.yunbao.common.R;
+import com.yunbao.common.adapter.GiftWallAchieveAdapter;
+import com.yunbao.common.bean.MedalAchievementModel;
+import com.yunbao.common.bean.UserMedalListModel;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.http.base.HttpCallback;
+import com.yunbao.common.http.live.LiveNetManager;
+import com.yunbao.common.utils.DpUtil;
+import com.yunbao.common.utils.ScreenDimenUtil;
+import com.yunbao.common.utils.ToastUtil;
+import com.yunbao.common.utils.WordUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 礼物墙-規則
+ */
+public class GiftWallRuleDialog extends AbsDialogPopupWindow {
+
+ private ImageView mIvBg;
+ private ImageView mIvBack;
+ private ImageView iv_rule;
+ private boolean isFullWindows;
+ private View topBar;
+ public GiftWallRuleDialog(@NonNull Context context) {
+ super(context);
+ }
+
+ public GiftWallRuleDialog setFullWindows(boolean fullWindows) {
+ isFullWindows = fullWindows;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_rule;
+ }
+
+ @Override
+ protected int getPopupHeight() {
+ if (isFullWindows) {
+ return super.getPopupHeight();
+ }
+ int screenHeight = ScreenDimenUtil.getInstance().getScreenHeight();
+ return (int) (screenHeight * 0.8);
+ }
+
+ void initView() {
+ mIvBg = findViewById(R.id.iv_root_bg);
+ mIvBack = findViewById(R.id.iv_back);
+ iv_rule= findViewById(R.id.iv_rule);
+ topBar = findViewById(R.id.top_bar);
+ mIvBack.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dialog.dismiss();
+ }
+ });
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ initView();
+ if (isFullWindows) {
+ mIvBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ ViewGroup.LayoutParams params1 = topBar.getLayoutParams();
+ params1.height= DpUtil.dp2px(35);;
+ topBar.setLayoutParams(params1);
+ } else {
+ mIvBg.setScaleType(ImageView.ScaleType.FIT_XY);
+ }
+ ImgLoader.displayDrawable(mContext, WordUtil.isNewZh() ? "https://downs.yaoulive.com/%E4%B8%AD%E6%96%87%E8%A7%84%E5%88%99.png" : "https://downs.yaoulive.com/%E8%8B%B1%E6%96%87%E8%A7%84%E5%88%99.png", -1, -1, new ImgLoader.DrawableCallback() {
+ @Override
+ public void onLoadSuccess(Drawable drawable) {
+ iv_rule.setImageDrawable(drawable);
+ }
+
+ @Override
+ public void onLoadFailed() {
+
+ }
+ });
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GiftWallTab2List2Dialog.java b/common/src/main/java/com/yunbao/common/dialog/GiftWallTab2List2Dialog.java
new file mode 100644
index 000000000..191d0f2ca
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GiftWallTab2List2Dialog.java
@@ -0,0 +1,98 @@
+package com.yunbao.common.dialog;
+
+import android.content.Context;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.lxj.xpopup.XPopup;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.yunbao.common.R;
+import com.yunbao.common.bean.GiftWallTab2Bean;
+import com.yunbao.common.glide.ImgLoader;
+import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.RouteUtil;
+import com.yunbao.common.utils.WordUtil;
+import com.yunbao.common.views.weight.ViewClicksAntiShake;
+
+import java.util.Locale;
+
+public class GiftWallTab2List2Dialog extends AbsDialogCenterPopupWindow {
+ RoundedImageView user1Avatar, user2Avatar;
+ TextView user1Name, user2Name;
+ ImageView giftImage;
+ TextView giftName;
+ TextView titleValue;
+
+ GiftWallTab2Bean.Gift gift;
+
+ public GiftWallTab2List2Dialog(@NonNull Context context) {
+ super(context);
+ }
+
+ public GiftWallTab2List2Dialog setGift(GiftWallTab2Bean.Gift gift) {
+ this.gift = gift;
+ return this;
+ }
+
+ @Override
+ public void buildDialog(XPopup.Builder builder) {
+
+ }
+
+ @Override
+ public int bindLayoutId() {
+ return R.layout.dialog_gift_wall_tab2_list2;
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ user1Avatar = findViewById(R.id.user1_avatar);
+ user2Avatar = findViewById(R.id.user2_avatar);
+ user1Name = findViewById(R.id.user1_name);
+ user2Name = findViewById(R.id.user2_name);
+ giftImage = findViewById(R.id.gift);
+ titleValue = findViewById(R.id.title_value);
+ giftName = findViewById(R.id.gift_name);
+
+ ImgLoader.display(mContext, gift.getGiftIcon(), giftImage);
+ if (gift.getNamingLiveActiveRankHide() == 0 || gift.getNamingLiveId()== IMLoginManager.get(mContext).getUserInfo().getId()) {
+ ImgLoader.display(mContext, gift.getNamingLiveAvatar(), user2Avatar);
+ user2Name.setText(gift.getNamingLiveNicename());
+ } else {
+ user2Avatar.setImageResource(R.mipmap.hide);
+ user2Name.setText(WordUtil.getNewString(R.string.mystery_man));
+ }
+ if (gift.getNamingUserActiveRankHide() == 0|| gift.getNamingUserId()== IMLoginManager.get(mContext).getUserInfo().getId()) {
+ ImgLoader.display(mContext, gift.getNamingUserAvatar(), user1Avatar);
+ user1Name.setText(gift.getNamingUserNicename());
+ } else {
+ user1Avatar.setImageResource(R.mipmap.hide);
+ user1Name.setText(WordUtil.getNewString(R.string.mystery_man));
+ }
+
+
+ giftName.setText(WordUtil.isNewZh() ? gift.getGiftName() : gift.getGiftNameEn());
+ titleValue.setText(String.format(Locale.getDefault(), "%d", gift.getGiftHallSendNum()));
+
+ ViewClicksAntiShake.clicksAntiShake(user1Avatar, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ if (gift.getNamingUserActiveRankHide() == 0) {
+ RouteUtil.forwardUserHome(mContext, String.valueOf(gift.getNamingUserId()), 0);
+ }
+ }
+ });
+ ViewClicksAntiShake.clicksAntiShake(user2Avatar, new ViewClicksAntiShake.ViewClicksCallBack() {
+ @Override
+ public void onViewClicks() {
+ if (gift.getNamingLiveActiveRankHide() == 0) {
+ RouteUtil.forwardUserHome(mContext, String.valueOf(gift.getNamingLiveId()), 0);
+ }
+
+ }
+ });
+ }
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GuardBuyCouponTipsDialog.java b/common/src/main/java/com/yunbao/common/dialog/GuardBuyCouponTipsDialog.java
new file mode 100644
index 000000000..38b86f353
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GuardBuyCouponTipsDialog.java
@@ -0,0 +1,80 @@
+package com.yunbao.common.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.text.Html;
+import android.text.Spanned;
+import android.view.View;
+import android.widget.TextView;
+
+import com.yunbao.common.R;
+import com.yunbao.common.utils.DialogUitl;
+import com.yunbao.common.utils.WordUtil;
+
+public class GuardBuyCouponTipsDialog {
+
+ /**
+ * @param context
+ * @param coin 钻石
+ * @param content 购买类型名称
+ * @param simpleCallback
+ */
+ public static void showBuyOrRenewDialog(Context context, String coupon, String coin, String content,
+ DialogUitl.SimpleCallback3 simpleCallback) {
+ if (context instanceof Activity) {
+ if (((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
+ return;
+ }
+ }
+
+ final Dialog dialog = new Dialog(context, R.style.dialog2);
+ dialog.setContentView(R.layout.dialog_guard_buy_coupon_tips);
+ dialog.setCancelable(true);
+ dialog.setCanceledOnTouchOutside(true);
+ TextView btn_confirm = dialog.findViewById(R.id.btn_confirm);
+ TextView content2 = dialog.findViewById(R.id.content2);
+
+ Spanned tips;
+ if (WordUtil.isNewZh()) {
+ tips = Html.fromHtml("您有一張"
+ + "" + content + "優惠券
"
+ + "開通/續費" + content + "(1個月)時,
可享"
+ + "" + coupon + "折"
+ + "優惠 (折後:"
+ + "" + coin + "鑽)
"
+ + "是否使用優惠券?");
+ } else {
+ tips = Html.fromHtml("You have a "
+ + "" + content + " coupon"
+ + " When activating/renewing " + content + "(1 month), you can enjoy a"
+ + " " + coupon + "% "
+ + "discount (After folding:"
+ + "" + coin + " diamonds"
+ + ")Do you want to use coupons?");
+ }
+ content2.setText(tips);
+ dialog.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ });
+ dialog.findViewById(R.id.btn_cancel1).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ simpleCallback.onCancel();
+ dialog.dismiss();
+ }
+ });
+ btn_confirm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ simpleCallback.onConfirmClick(dialog);
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/GuardBuyTipsNewDialog.java b/common/src/main/java/com/yunbao/common/dialog/GuardBuyTipsNewDialog.java
new file mode 100644
index 000000000..f8742fd99
--- /dev/null
+++ b/common/src/main/java/com/yunbao/common/dialog/GuardBuyTipsNewDialog.java
@@ -0,0 +1,44 @@
+package com.yunbao.common.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.view.View;
+import android.widget.TextView;
+
+import com.yunbao.common.R;
+import com.yunbao.common.utils.WordUtil;
+
+public class GuardBuyTipsNewDialog {
+ /**
+ * @param context
+ */
+ public static void showBuyOrRenewDialog(Context context) {
+ if (context instanceof Activity) {
+ if (((Activity) context).isDestroyed() || ((Activity) context).isFinishing()) {
+ return;
+ }
+ }
+
+ final Dialog dialog = new Dialog(context, R.style.dialog2);
+ dialog.setContentView(R.layout.dialog_guard_buy_tips);
+ dialog.setCancelable(true);
+ dialog.setCanceledOnTouchOutside(true);
+ TextView btn_confirm = dialog.findViewById(R.id.btn_confirm);
+ btn_confirm.setText(WordUtil.isNewZh() ? "確認" : "Confirm");
+ dialog.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ });
+ dialog.findViewById(R.id.btn_confirm).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+
+}
diff --git a/common/src/main/java/com/yunbao/common/dialog/OrderLevelPopupWindow.java b/common/src/main/java/com/yunbao/common/dialog/OrderLevelPopupWindow.java
index 0d64fa8c4..b40d38354 100644
--- a/common/src/main/java/com/yunbao/common/dialog/OrderLevelPopupWindow.java
+++ b/common/src/main/java/com/yunbao/common/dialog/OrderLevelPopupWindow.java
@@ -1,7 +1,11 @@
package com.yunbao.common.dialog;
+import android.app.Dialog;
import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.view.View;
+import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -16,6 +20,7 @@ import com.yunbao.common.http.base.HttpCallback;
import com.yunbao.common.http.live.LiveNetManager;
import com.yunbao.common.interfaces.OnItemClickListener;
import com.yunbao.common.manager.IMLoginManager;
+import com.yunbao.common.utils.StringUtil;
import com.yunbao.common.utils.ToastUtil;
import com.yunbao.common.utils.WordUtil;
import com.yunbao.common.views.weight.ViewClicksAntiShake;
@@ -26,18 +31,19 @@ import java.math.BigDecimal;
* 战令等级 经验
*/
public class OrderLevelPopupWindow extends CenterPopupView {
- private TextView orderLevel, orderLevelDiamond, balanceDiamond, current, expText;
+ private TextView orderLevelDiamond, balanceDiamond, current, expText;
private int currentExperience, totalExperience;//当前经验,全部经验
- private String buyExp = "100", currentLevel, balance;
+ private String buyExp = "1", currentLevel, balance;
private ProgressBar progressBar;
private OrderLevelCallback orderLevelCallback;
private long maxExp;
private BattlePassUserInfoBean userInfoBean;
+ private Context mContext;
+ private EditText orderLevel;
- public OrderLevelPopupWindow(@NonNull Context context, BattlePassUserInfoBean userInfoBean,
- int mCurrentExperience, int mTotalExperience,
- String mCurrentLevel, String mBalance, long maxExp, OrderLevelCallback mOrderLevelCallback) {
+ public OrderLevelPopupWindow(@NonNull Context context, BattlePassUserInfoBean userInfoBean, int mCurrentExperience, int mTotalExperience, String mCurrentLevel, String mBalance, long maxExp, OrderLevelCallback mOrderLevelCallback) {
super(context);
+ this.mContext = context;
this.userInfoBean = userInfoBean;
currentExperience = mCurrentExperience;
totalExperience = mTotalExperience;
@@ -67,15 +73,15 @@ public class OrderLevelPopupWindow extends CenterPopupView {
progressBar.setProgress(currentExperience);
expText.setText(String.format("%s/%s", userInfoBean.getBattlePassExp(), userInfoBean.getNextLevelExp()));
current.setText(String.format("Lv%s", currentLevel));
- balanceDiamond.setText(balance);
+ balanceDiamond.setText((WordUtil.isNewZh() ? "剩餘:" : "Balance:") + balance);
findViewById(R.id.sub).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
float exp = new BigDecimal(buyExp).floatValue();
- if (exp > 100) {
- BigDecimal buyExpBigDecimal = new BigDecimal(buyExp).subtract(new BigDecimal("100"));
+ if (exp > 1) {
+ BigDecimal buyExpBigDecimal = new BigDecimal(buyExp).subtract(new BigDecimal("1"));
buyExp = String.valueOf(buyExpBigDecimal.intValue());
- orderLevelDiamond.setText(String.valueOf(buyExpBigDecimal.floatValue()));
+ orderLevelDiamond.setText("00 = " + buyExp + "00");
orderLevel.setText(buyExp);
}
}
@@ -84,15 +90,14 @@ public class OrderLevelPopupWindow extends CenterPopupView {
@Override
public void onClick(View view) {
float exp = new BigDecimal(buyExp).floatValue();
- if (exp < maxExp && exp < 10000) {
- BigDecimal buyExpBigDecimal = new BigDecimal(buyExp).add(new BigDecimal("100"));
+ if (exp < maxExp && (exp + 1) < 10000) {
+ BigDecimal buyExpBigDecimal = new BigDecimal(buyExp).add(new BigDecimal("1"));
buyExp = String.valueOf(buyExpBigDecimal.intValue());
- orderLevelDiamond.setText(String.valueOf(buyExpBigDecimal.floatValue()));
+ orderLevelDiamond.setText("00 = " + buyExp + "00");
orderLevel.setText(buyExp);
} else if (exp >= maxExp) {
- ToastUtil.show(WordUtil.isNewZh() ? "经验已滿" : "Experience full");
+ ToastUtil.show(WordUtil.isNewZh() ? "經驗超出,僅需" + maxExp + "經驗可達滿级" : "Exp exceeds.Only " + maxExp + " exp is needed to reach the max level.");
}
-
}
});
ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.war_order_close), new ViewClicksAntiShake.ViewClicksCallBack() {
@@ -101,40 +106,68 @@ public class OrderLevelPopupWindow extends CenterPopupView {
dialog.dismiss();
}
});
+ orderLevel.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ buyExp = charSequence.toString();
+ orderLevelDiamond.setText("00 = " + charSequence.toString() + "00");
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+
+ }
+ });
ViewClicksAntiShake.clicksAntiShake(findViewById(R.id.buying_experience), new ViewClicksAntiShake.ViewClicksCallBack() {
@Override
public void onViewClicks() {
- LiveNetManager.get(getContext())
- .buyingExperiencePoint(buyExp, new HttpCallback>() {
- @Override
- public void onSuccess(ResponseModel