tagFlow 展开按钮添加
This commit is contained in:
parent
bb87a3d138
commit
2426f6b8bd
|
|
@ -1,6 +1,7 @@
|
|||
package com.remax.visualnovel.configs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.multidex.MultiDex
|
||||
import androidx.multidex.MultiDexApplication
|
||||
|
|
@ -28,6 +29,9 @@ class NovelApplication : MultiDexApplication() {
|
|||
fun getCurrentActivity(): Activity? {
|
||||
return currentActivity?.get()
|
||||
}
|
||||
|
||||
private lateinit var instance: NovelApplication
|
||||
fun appContext(): Context = instance
|
||||
}
|
||||
|
||||
private val proxies = listOf<ApplicationProxy>(CommonApplicationProxy)
|
||||
|
|
@ -38,6 +42,7 @@ class NovelApplication : MultiDexApplication() {
|
|||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
MultiDex.install(this)
|
||||
instance = this
|
||||
proxies.forEach { it.onCreate(this) }
|
||||
appInitializersProvider.startInit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package com.remax.visualnovel.extension
|
||||
|
||||
|
||||
import com.remax.visualnovel.configs.NovelApplication
|
||||
|
||||
private val resources = NovelApplication.appContext().resources
|
||||
|
||||
// dp, pixcel 相关
|
||||
fun Float.dpToPx(): Float = this * resources.displayMetrics.density
|
||||
fun Int.dpToPx(): Int = this * resources.displayMetrics.density.toInt()
|
||||
fun Float.spToPx(): Float = this * resources.displayMetrics.scaledDensity
|
||||
|
|
@ -9,8 +9,6 @@ import com.alibaba.android.arouter.launcher.ARouter
|
|||
import com.dylanc.loadingstateview.BgColorType
|
||||
import com.remax.visualnovel.app.base.BaseBindingFragment
|
||||
import com.remax.visualnovel.databinding.FragmentMainActorBinding
|
||||
import com.remax.visualnovel.databinding.FragmentMainBookBinding
|
||||
import com.remax.visualnovel.ui.main.book.BookListViewModel
|
||||
import com.remax.visualnovel.utils.Routers
|
||||
import com.remax.visualnovel.widget.custom.TagItem
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
|
@ -56,7 +54,7 @@ class ActorListFragment : BaseBindingFragment<FragmentMainActorBinding>() {
|
|||
TagItem("8", "LastLine"),
|
||||
)
|
||||
|
||||
tagFlowLayout.setTags(tags)
|
||||
tagFlowLayout.setTagDataList(tags)
|
||||
|
||||
tagFlowLayout.setOnTagClickListener { tag ->
|
||||
Toast.makeText(context, "Clicked: ${tag.text}", Toast.LENGTH_SHORT).show()
|
||||
|
|
|
|||
|
|
@ -7,11 +7,16 @@ import android.graphics.drawable.GradientDrawable
|
|||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.remax.visualnovel.R
|
||||
import com.remax.visualnovel.extension.dpToPx
|
||||
import com.remax.visualnovel.extension.spToPx
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import androidx.core.content.withStyledAttributes
|
||||
|
||||
class TagFlowLayout2 @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
|
@ -20,26 +25,27 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
) : ViewGroup(context, attrs, defStyleAttr) {
|
||||
|
||||
// 属性变量
|
||||
private var horizontalSpacing = 20f.dpToPx()
|
||||
private var verticalSpacing = 12f.dpToPx()
|
||||
private var textSize = 14f.spToPx()
|
||||
private var textColor = Color.WHITE
|
||||
private var horizontalSpacing = 10f.dpToPx()
|
||||
private var verticalSpacing = 8f.dpToPx()
|
||||
private var textSize = 12f.spToPx()
|
||||
private var textColor = context.resources.getColor(R.color.tag_text_color)
|
||||
private var tagBackground: Drawable? = null
|
||||
private var maxLines = Int.MAX_VALUE
|
||||
private var maxLinesWhileShrink = 1
|
||||
private var eachLineMaxTagNum = 2
|
||||
private var expandIndicator: Drawable? = null
|
||||
private var collapseIndicator: Drawable? = null
|
||||
private var eachLineMaxTagNum = 2 //一行最大标签宽度数
|
||||
private var shrinkIndicator: Drawable? = null
|
||||
|
||||
|
||||
// 状态变量
|
||||
private var isExpanded = false
|
||||
private var actualLineCount = 0
|
||||
private var showExpandButton = false
|
||||
private var eachLineAvailableWidth = 0 // 可用宽度
|
||||
private var eachLineAvailableWidth = 0
|
||||
|
||||
// 数据
|
||||
private val tagItems = mutableListOf<TagItem>()
|
||||
private val tagViews = mutableListOf<TextView>()
|
||||
private lateinit var expandButton: TextView
|
||||
private lateinit var expandIcon: ImageView
|
||||
|
||||
// 监听器
|
||||
private var onTagClickListener: ((TagItem) -> Unit)? = null
|
||||
|
|
@ -51,26 +57,27 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun initAttributes(attrs: AttributeSet?) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout2)
|
||||
context.withStyledAttributes(attrs, R.styleable.TagFlowLayout2) {
|
||||
|
||||
horizontalSpacing = typedArray.getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_horizontal_spacing, horizontalSpacing
|
||||
)
|
||||
verticalSpacing = typedArray.getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_vertical_spacing, verticalSpacing
|
||||
)
|
||||
textSize = typedArray.getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_text_size, textSize
|
||||
)
|
||||
textColor = typedArray.getColor(
|
||||
R.styleable.TagFlowLayout2_tag_text_color, textColor
|
||||
)
|
||||
tagBackground = typedArray.getDrawable(R.styleable.TagFlowLayout2_tag_background)
|
||||
maxLines = typedArray.getInt(R.styleable.TagFlowLayout2_tag_max_lines, Int.MAX_VALUE)
|
||||
expandIndicator = typedArray.getDrawable(R.styleable.TagFlowLayout2_expand_indicator_drawable)
|
||||
collapseIndicator = typedArray.getDrawable(R.styleable.TagFlowLayout2_collapse_indicator_drawable)
|
||||
eachLineMaxTagNum = typedArray.getInt(R.styleable.TagFlowLayout2_each_line_max_num, 2)
|
||||
typedArray.recycle()
|
||||
horizontalSpacing = getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_horizontal_spacing, horizontalSpacing
|
||||
)
|
||||
verticalSpacing = getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_vertical_spacing, verticalSpacing
|
||||
)
|
||||
textSize = getDimension(
|
||||
R.styleable.TagFlowLayout2_tag_text_size, textSize
|
||||
)
|
||||
textColor = getColor(
|
||||
R.styleable.TagFlowLayout2_tag_text_color, textColor
|
||||
)
|
||||
tagBackground = getDrawable(R.styleable.TagFlowLayout2_tag_background)
|
||||
maxLinesWhileShrink = getInt(R.styleable.TagFlowLayout2_tag_max_lines, 1)
|
||||
eachLineMaxTagNum = getInt(R.styleable.TagFlowLayout2_tag_each_line_max_num, 2)
|
||||
|
||||
expandIndicator = getDrawable(R.styleable.TagFlowLayout2_tag_expand_drawable)
|
||||
shrinkIndicator = getDrawable(R.styleable.TagFlowLayout2_tag_shrink_drawable)
|
||||
}
|
||||
|
||||
|
||||
if (tagBackground == null) {
|
||||
|
|
@ -79,8 +86,8 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
if (expandIndicator == null) {
|
||||
expandIndicator = ContextCompat.getDrawable(context, R.mipmap.tag_flow_expand)
|
||||
}
|
||||
if (collapseIndicator == null) {
|
||||
collapseIndicator = ContextCompat.getDrawable(context, R.mipmap.tag_flow_shrink)
|
||||
if (shrinkIndicator == null) {
|
||||
shrinkIndicator = ContextCompat.getDrawable(context, R.mipmap.tag_flow_shrink)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,38 +99,26 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun initExpandButton() {
|
||||
expandButton = TextView(context).apply {
|
||||
text = "展开"
|
||||
setCompoundDrawablesWithIntrinsicBounds(null, null, expandIndicator, null)
|
||||
compoundDrawablePadding = 4.dpToPx()
|
||||
setTextColor(Color.parseColor("#8A8A8E"))
|
||||
expandIcon = AppCompatImageView(context).apply {
|
||||
textSize = 12f
|
||||
setPadding(12.dpToPx(), 6.dpToPx(), 8.dpToPx(), 6.dpToPx())
|
||||
background = createExpandButtonBackground()
|
||||
|
||||
setPadding(5.dpToPx(), 5.dpToPx(), 5.dpToPx(), 5.dpToPx())
|
||||
bringToFront()
|
||||
setOnClickListener {
|
||||
toggleExpandState()
|
||||
}
|
||||
}
|
||||
addView(expandButton)
|
||||
addView(expandIcon)
|
||||
|
||||
updateExpandButton()
|
||||
}
|
||||
|
||||
private fun createExpandButtonBackground(): Drawable {
|
||||
val gradientDrawable = GradientDrawable()
|
||||
gradientDrawable.cornerRadius = 16f.dpToPx()
|
||||
gradientDrawable.setColor(Color.parseColor("#E5E5EA"))
|
||||
gradientDrawable.setStroke(1.dpToPx(), Color.parseColor("#C6C6C8"))
|
||||
return gradientDrawable
|
||||
}
|
||||
|
||||
// 设置标签数据
|
||||
fun setTags(tags: List<TagItem>) {
|
||||
fun setTagDataList(tags: List<TagItem>) {
|
||||
tagItems.clear()
|
||||
tagViews.forEach { removeView(it) }
|
||||
tagViews.clear()
|
||||
|
||||
tagItems.addAll(tags)
|
||||
|
||||
tags.forEach { tag ->
|
||||
val textView = createTagView(tag)
|
||||
tagViews.add(textView)
|
||||
|
|
@ -138,7 +133,7 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
text = tag.text
|
||||
setTextColor(textColor)
|
||||
textSize = textSize / resources.displayMetrics.scaledDensity
|
||||
setPadding(16.dpToPx(), 8.dpToPx(), 16.dpToPx(), 8.dpToPx())
|
||||
setPadding(10.dpToPx(), 7.dpToPx(), 10.dpToPx(), 7.dpToPx())
|
||||
setBackgroundResource(R.drawable.tag_flow_item_bg)
|
||||
isSingleLine = true
|
||||
ellipsize = TextUtils.TruncateAt.END
|
||||
|
|
@ -172,8 +167,8 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
|
||||
var curLineTotalWidth = 0
|
||||
var curLineTotalHeight = 0
|
||||
var lineCount = 0
|
||||
val maxDisplayLines = if (isExpanded) Int.MAX_VALUE else maxLines
|
||||
var lineIndex = 0
|
||||
val maxDisplayLines = if (isExpanded) Int.MAX_VALUE else maxLinesWhileShrink
|
||||
|
||||
tagViews.forEach { view ->
|
||||
val childWidth = view.measuredWidth
|
||||
|
|
@ -181,16 +176,15 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
|
||||
// 检查是否需要换行(考虑水平间距)
|
||||
val curLineNeedTotalWidth: Int = if (curLineTotalWidth == 0) childWidth
|
||||
else curLineTotalWidth + horizontalSpacing.toInt() + childWidth
|
||||
else curLineTotalWidth + horizontalSpacing.toInt() + childWidth
|
||||
|
||||
if (curLineNeedTotalWidth > eachLineAvailableWidth) {
|
||||
// 换行处理
|
||||
lineCount++
|
||||
if (lineCount >= maxDisplayLines) {
|
||||
if (curLineNeedTotalWidth > eachLineAvailableWidth) { // 换行处理
|
||||
lineIndex++
|
||||
if (lineIndex >= maxDisplayLines) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
totalNeedHeight += curLineTotalHeight + (if (lineCount >= 1) verticalSpacing.toInt() else 0)
|
||||
totalNeedHeight += curLineTotalHeight + (if (lineIndex >= 1) verticalSpacing.toInt() else 0)
|
||||
curLineTotalWidth = childWidth
|
||||
curLineTotalHeight = childHeight
|
||||
} else {
|
||||
|
|
@ -200,21 +194,21 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
// 添加最后一行高度
|
||||
if (lineCount < maxDisplayLines && tagViews.isNotEmpty()) {
|
||||
if (tagViews.isNotEmpty()) {
|
||||
totalNeedHeight += curLineTotalHeight
|
||||
}
|
||||
|
||||
// 添加padding
|
||||
totalNeedHeight += paddingTop + paddingBottom
|
||||
|
||||
actualLineCount = lineCount + 1
|
||||
showExpandButton = actualLineCount > maxLines && !isExpanded
|
||||
actualLineCount = lineIndex + 1
|
||||
showExpandButton = actualLineCount > maxLinesWhileShrink && !isExpanded
|
||||
|
||||
// 测量展开按钮
|
||||
if (showExpandButton) {
|
||||
val buttonWidthSpec = MeasureSpec.makeMeasureSpec(eachLineAvailableWidth, MeasureSpec.AT_MOST)
|
||||
val buttonHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
|
||||
expandButton.measure(buttonWidthSpec, buttonHeightSpec)
|
||||
expandIcon.measure(buttonWidthSpec, buttonHeightSpec)
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, totalNeedHeight)
|
||||
|
|
@ -230,7 +224,7 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
var currentTop = paddingTop
|
||||
var currentLineHeight = 0
|
||||
var lineCount = 0
|
||||
val maxDisplayLines = if (isExpanded) Int.MAX_VALUE else maxLines
|
||||
val maxDisplayLines = if (isExpanded) Int.MAX_VALUE else maxLinesWhileShrink
|
||||
|
||||
// 布局可见的标签
|
||||
for (i in tagViews.indices) {
|
||||
|
|
@ -264,22 +258,22 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
|
||||
private fun layoutExpandButton(parentWidth: Int, currentTop: Int, currentLineHeight: Int) {
|
||||
if (showExpandButton) {
|
||||
expandButton.visibility = VISIBLE
|
||||
val buttonWidth = expandButton.measuredWidth
|
||||
val buttonHeight = expandButton.measuredHeight
|
||||
expandIcon.visibility = VISIBLE
|
||||
val buttonWidth = expandIcon.measuredWidth
|
||||
val buttonHeight = expandIcon.measuredHeight
|
||||
|
||||
// 计算按钮位置(在当前行右侧)
|
||||
val buttonLeft = parentWidth - paddingRight - buttonWidth
|
||||
val buttonTop = currentTop + (currentLineHeight - buttonHeight) / 2
|
||||
|
||||
expandButton.layout(
|
||||
expandIcon.layout(
|
||||
buttonLeft,
|
||||
buttonTop,
|
||||
buttonLeft + buttonWidth,
|
||||
buttonTop + buttonHeight
|
||||
)
|
||||
} else {
|
||||
expandButton.visibility = GONE
|
||||
expandIcon.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,12 +285,10 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun updateExpandButton() {
|
||||
val indicator = if (isExpanded) collapseIndicator else expandIndicator
|
||||
expandButton.setCompoundDrawablesWithIntrinsicBounds(null, null, indicator, null)
|
||||
expandButton.text = if (isExpanded) "收起" else "展开"
|
||||
val indicator = if (isExpanded) shrinkIndicator else expandIndicator
|
||||
expandIcon.setImageDrawable(indicator)
|
||||
}
|
||||
|
||||
// 公共方法
|
||||
fun setOnTagClickListener(listener: (TagItem) -> Unit) {
|
||||
onTagClickListener = listener
|
||||
}
|
||||
|
|
@ -311,7 +303,7 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun collapse() {
|
||||
fun shrink() {
|
||||
if (isExpanded) {
|
||||
toggleExpandState()
|
||||
}
|
||||
|
|
@ -319,15 +311,11 @@ class TagFlowLayout2 @JvmOverloads constructor(
|
|||
|
||||
fun isExpanded(): Boolean = isExpanded
|
||||
|
||||
// 设置最大标签数
|
||||
fun setMaxTagsNumEachLine(maxTagNumForEachLine: Int) {
|
||||
require(maxTagNumForEachLine >= 1 && maxTagNumForEachLine <= 10) { "Ratio must be between 1 and 10" }
|
||||
require(maxTagNumForEachLine >= 1 && maxTagNumForEachLine <= 10) { "tags numb in one line must be between 1 and 8" }
|
||||
eachLineMaxTagNum = maxTagNumForEachLine
|
||||
requestLayout()
|
||||
}
|
||||
|
||||
// 扩展函数
|
||||
private fun Float.dpToPx(): Float = this * resources.displayMetrics.density
|
||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).toInt()
|
||||
private fun Float.spToPx(): Float = this * resources.displayMetrics.scaledDensity
|
||||
|
||||
}
|
||||
|
|
@ -2,5 +2,5 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
<corners android:radius="15dp" />
|
||||
<solid android:color="@color/tag_bg_gray" />
|
||||
<solid android:color="@color/tag_bg_color" />
|
||||
</shape>
|
||||
|
|
@ -36,9 +36,10 @@
|
|||
app:tag_horizontal_spacing="10dp"
|
||||
app:tag_vertical_spacing="8dp"
|
||||
app:tag_text_size="12sp"
|
||||
app:tag_max_lines="1"
|
||||
app:tag_text_color="@color/white"
|
||||
app:each_line_max_num="2"
|
||||
app:expand_indicator_drawable="@mipmap/tag_flow_expand"
|
||||
app:collapse_indicator_drawable="@mipmap/tag_flow_shrink" />
|
||||
app:tag_each_line_max_num="2"
|
||||
app:tag_expand_drawable="@mipmap/tag_flow_expand"
|
||||
app:tag_shrink_drawable="@mipmap/tag_flow_shrink" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -1441,9 +1441,9 @@
|
|||
<attr name="tag_text_color" format="color" />
|
||||
<attr name="tag_background" format="reference" />
|
||||
<attr name="tag_max_lines" format="integer" />
|
||||
<attr name="expand_indicator_drawable" format="reference" />
|
||||
<attr name="collapse_indicator_drawable" format="reference" />
|
||||
<attr name="each_line_max_num" format="integer" />
|
||||
<attr name="tag_expand_drawable" format="reference" />
|
||||
<attr name="tag_shrink_drawable" format="reference" />
|
||||
<attr name="tag_each_line_max_num" format="integer" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,9 @@
|
|||
|
||||
|
||||
<!-- new added -->
|
||||
<color name="tag_bg_gray">#ffbac5d2</color>
|
||||
<color name="tag_bg_color">#ffbac5d2</color>
|
||||
<color name="tag_text_color">#ffe5f1ff</color>
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
Loading…
Reference in New Issue