絵文字ピッカーのレイアウト改善
This commit is contained in:
parent
7dae622f70
commit
5e0a44a321
|
@ -10,8 +10,10 @@ import android.view.*
|
|||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatImageButton
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -25,7 +27,6 @@ import jp.juggler.subwaytooter.databinding.EmojiPickerDialogBinding
|
|||
import jp.juggler.subwaytooter.emoji.*
|
||||
import jp.juggler.subwaytooter.pref.PrefB
|
||||
import jp.juggler.subwaytooter.pref.PrefS
|
||||
import jp.juggler.subwaytooter.span.EmojiImageSpan
|
||||
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.subwaytooter.util.emojiSizeMode
|
||||
|
@ -37,6 +38,7 @@ import jp.juggler.util.coroutine.launchAndShowError
|
|||
import jp.juggler.util.data.*
|
||||
import jp.juggler.util.log.*
|
||||
import jp.juggler.util.ui.*
|
||||
import org.jetbrains.anko.image
|
||||
import org.jetbrains.anko.wrapContent
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sign
|
||||
|
@ -72,11 +74,16 @@ private class EmojiPicker(
|
|||
private open class PickerItemCategory(
|
||||
var name: String,
|
||||
val category: EmojiCategory,
|
||||
val original: PickerItemCategory? = null,
|
||||
var next: PickerItemCategory? = null,
|
||||
) : PickerItem {
|
||||
val items = ArrayList<PickerItem>()
|
||||
|
||||
open fun createFiltered(keywordLower: String?) =
|
||||
PickerItemCategory(name = name, category = category).also { dst ->
|
||||
PickerItemCategory(
|
||||
name = name,
|
||||
category = category,
|
||||
original = this,
|
||||
).also { dst ->
|
||||
dst.items.addAll(
|
||||
if (keywordLower.isNullOrEmpty()) {
|
||||
items
|
||||
|
@ -192,24 +199,63 @@ private class EmojiPicker(
|
|||
abstract fun bind(item: PickerItem)
|
||||
}
|
||||
|
||||
private var lastExpandCategory: PickerItemCategory? = null
|
||||
private var canCollapse = true
|
||||
|
||||
private inner class VhCategory(
|
||||
view: FrameLayout = FrameLayout(activity),
|
||||
view: LinearLayout = LinearLayout(activity),
|
||||
) : ViewHolderBase(view) {
|
||||
var lastItem: PickerItemCategory? = null
|
||||
|
||||
val ibExpand = AppCompatImageButton(activity).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(gridSize, matchParent)
|
||||
background = ContextCompat.getDrawable(
|
||||
this@EmojiPicker.activity,
|
||||
R.drawable.btn_bg_transparent_round6dp
|
||||
)
|
||||
setOnClickListener {
|
||||
val orig = lastItem?.original
|
||||
?: return@setOnClickListener
|
||||
lastExpandCategory = if (lastExpandCategory != orig) orig else lastItem?.next
|
||||
// 再表示
|
||||
showFiltered(
|
||||
lastSelectedCategory,
|
||||
lastSelectedKeyword,
|
||||
scrollCategoryTab = false,
|
||||
scrollToCategory = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val tv = AppCompatTextView(activity).apply {
|
||||
layoutParams = FrameLayout.LayoutParams(headerWidth, gridSize)
|
||||
layoutParams = LinearLayout.LayoutParams(0, wrapContent).apply {
|
||||
weight = 1f
|
||||
}
|
||||
minHeightCompat = (density * 48f + 0.5f).toInt()
|
||||
gravity = Gravity.START or Gravity.CENTER_VERTICAL
|
||||
includeFontPadding = false
|
||||
}
|
||||
|
||||
init {
|
||||
view.layoutParams = RecyclerView.LayoutParams(wrapContent, wrapContent)
|
||||
view.layoutParams = RecyclerView.LayoutParams(headerWidth, wrapContent)
|
||||
view.setPadding(cellMargin, cellMargin, cellMargin, cellMargin)
|
||||
view.isBaselineAligned = false
|
||||
view.gravity = Gravity.START or Gravity.CENTER_VERTICAL
|
||||
view.addView(ibExpand)
|
||||
view.addView(tv)
|
||||
}
|
||||
|
||||
override fun bind(item: PickerItem) {
|
||||
if (item is PickerItemCategory) {
|
||||
lastItem = item
|
||||
tv.text = item.name
|
||||
ibExpand.vg(canCollapse)?.let {
|
||||
val drawableId = when (lastExpandCategory == item.original) {
|
||||
true -> R.drawable.ic_arrow_drop_down
|
||||
else -> R.drawable.ic_arrow_drop_up
|
||||
}
|
||||
it.image = ContextCompat.getDrawable(activity, drawableId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -564,27 +610,53 @@ private class EmojiPicker(
|
|||
private fun showFiltered(
|
||||
selectedCategory: EmojiCategory?,
|
||||
selectedKeyword: String?,
|
||||
scrollCategoryTab: Boolean = true,
|
||||
scrollToCategory: Boolean = false,
|
||||
) {
|
||||
lastSelectedCategory = selectedCategory
|
||||
lastSelectedKeyword = selectedKeyword
|
||||
adapter.list = buildList {
|
||||
val keywordLower = selectedKeyword?.lowercase()?.trim()
|
||||
pickerCategries.filter {
|
||||
this.canCollapse =
|
||||
keywordLower.isNullOrEmpty() && (selectedCategory == null || selectedCategory == EmojiCategory.Custom)
|
||||
|
||||
val list = buildList {
|
||||
val filteredCategories = pickerCategries.filter {
|
||||
selectedCategory == null || it.category == selectedCategory
|
||||
}.mapNotNull { category ->
|
||||
category.createFiltered(keywordLower)
|
||||
.takeIf { it.items.isNotEmpty() }
|
||||
}.forEach {
|
||||
if (it.category == EmojiCategory.Custom || selectedCategory == null) add(it)
|
||||
}
|
||||
|
||||
for (i in filteredCategories.indices) {
|
||||
filteredCategories[i].next =
|
||||
filteredCategories.elementAtOrNull(i + 1)?.original
|
||||
?: filteredCategories.elementAtOrNull(i - 1)?.original
|
||||
}
|
||||
|
||||
if (lastExpandCategory == null ||
|
||||
filteredCategories.none { it.original == lastExpandCategory }
|
||||
) lastExpandCategory = filteredCategories.firstOrNull()?.original
|
||||
|
||||
filteredCategories.forEach {
|
||||
if (selectedCategory == null || it.category == EmojiCategory.Custom) {
|
||||
// 見出し付き表示の場合は折りたたむ可能性がある
|
||||
add(it)
|
||||
if (!canCollapse || lastExpandCategory == it.original) addAll(it.items)
|
||||
} else {
|
||||
// カスタム以外のカテゴリが選択されている場合、(ヘッダがなく解除できないので) 折りたたみはできない
|
||||
addAll(it.items)
|
||||
// val mod = it.items.size % gridCols
|
||||
// if (mod > 0) {
|
||||
// repeat(gridCols - mod) {
|
||||
// add(PickerItemSpace)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
adapter.list = list
|
||||
if (scrollToCategory) {
|
||||
val idx =
|
||||
list.indexOfFirst { (it as? PickerItemCategory)?.original == lastExpandCategory }
|
||||
if (idx != -1) {
|
||||
views.rvGrid.smoothScrollToPosition(idx)
|
||||
}
|
||||
}
|
||||
|
||||
for (it in views.llCategories.children) {
|
||||
val backgroundId = when (it.tag) {
|
||||
selectedCategory -> R.drawable.bg_button_cw
|
||||
|
@ -592,7 +664,7 @@ private class EmojiPicker(
|
|||
}
|
||||
it.background = ContextCompat.getDrawable(it.context, backgroundId)
|
||||
|
||||
if (it.tag == selectedCategory) {
|
||||
if (it.tag == selectedCategory && scrollCategoryTab) {
|
||||
val oldScrollX = views.svCategories.scrollX
|
||||
val visibleWidth = views.svCategories.width
|
||||
log.i("left=${it.left},r=${it.right},s=$oldScrollX")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package jp.juggler.subwaytooter.util
|
||||
|
||||
import android.graphics.RectF
|
||||
import androidx.collection.LruCache
|
||||
import jp.juggler.subwaytooter.api.entity.TootInstance
|
||||
import jp.juggler.subwaytooter.table.SavedAccount
|
||||
import jp.juggler.util.log.LogCategory
|
||||
|
@ -35,8 +34,7 @@ class EmojiImageRect(
|
|||
companion object {
|
||||
private val log = LogCategory("EmojiImageRect")
|
||||
|
||||
// ImageWidthCache
|
||||
val imageAspectCache = LruCache<String, Float>(1024)
|
||||
val imageAspectCache = HashMap<String, Float>()
|
||||
}
|
||||
|
||||
val rectDst = RectF()
|
||||
|
@ -44,7 +42,7 @@ class EmojiImageRect(
|
|||
var emojiHeight = 0f
|
||||
var transY = 0f
|
||||
|
||||
private var lastWidth: Float? = null
|
||||
var lastWidth: Float? = null
|
||||
|
||||
/**
|
||||
* lastAspect に基づいて rectDst と transY を更新する
|
||||
|
@ -71,9 +69,7 @@ class EmojiImageRect(
|
|||
) {
|
||||
this.emojiHeight = h
|
||||
val aspect = when (aspectArg) {
|
||||
null -> {
|
||||
imageAspectCache[url] ?: 1f
|
||||
}
|
||||
null -> imageAspectCache[url] ?: 1f
|
||||
else -> {
|
||||
imageAspectCache.put(url, aspectArg)
|
||||
aspectArg
|
||||
|
|
|
@ -60,6 +60,7 @@ class NetworkEmojiView(
|
|||
lp.width = w
|
||||
lp.height = h
|
||||
layoutParams = lp
|
||||
requestLayout()
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -72,20 +73,17 @@ class NetworkEmojiView(
|
|||
this.url = url
|
||||
mPaint.isFilterBitmap = true
|
||||
invalidate()
|
||||
if (url != null && initialAspect != null) {
|
||||
emojiImageRect.lastWidth = null
|
||||
emojiImageRect.updateRect(
|
||||
url = url,
|
||||
url = url ?: "",
|
||||
aspectArg = initialAspect,
|
||||
h = defaultHeight.toFloat(),
|
||||
// may call layout callback
|
||||
)
|
||||
} else {
|
||||
val lp = layoutParams
|
||||
lp.width = defaultWidth
|
||||
lp.height = defaultHeight
|
||||
lp.width = (emojiImageRect.emojiWidth + 0.5f).toInt()
|
||||
lp.height = (emojiImageRect.emojiHeight + 0.5f).toInt()
|
||||
layoutParams = lp
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
|
|
Loading…
Reference in New Issue