|
@@ -42,7 +42,9 @@ class CustomNavBar @JvmOverloads constructor(
|
|
|
context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
|
|
context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
|
|
|
) : LinearLayout(context, attrs, defStyle) {
|
|
) : LinearLayout(context, attrs, defStyle) {
|
|
|
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
|
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
|
|
-
|
|
|
|
|
|
|
+ private companion object {
|
|
|
|
|
+ const val NO_SELECTION = -1
|
|
|
|
|
+ }
|
|
|
@SuppressLint("RestrictedApi")
|
|
@SuppressLint("RestrictedApi")
|
|
|
private val menuBuilder = MenuBuilder(context)
|
|
private val menuBuilder = MenuBuilder(context)
|
|
|
val menu: Menu get() = menuBuilder
|
|
val menu: Menu get() = menuBuilder
|
|
@@ -197,51 +199,48 @@ class CustomNavBar @JvmOverloads constructor(
|
|
|
container.getChildAt(c).refreshDrawableState() // ★ 子也刷一下
|
|
container.getChildAt(c).refreshDrawableState() // ★ 子也刷一下
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (length > 0) selectIndex(selectedIdx.coerceIn(0, length - 1))
|
|
|
|
|
|
|
+ if (length > 0) {
|
|
|
|
|
+ if (selectedIdx in 0 until length) {
|
|
|
|
|
+ selectIndex(selectedIdx)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ selectIndex(NO_SELECTION) // 全部不选
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private fun selectIndex(idx: Int) {
|
|
private fun selectIndex(idx: Int) {
|
|
|
- if (idx == selectedIdx) {
|
|
|
|
|
- invalidate(); return
|
|
|
|
|
- }
|
|
|
|
|
selectedIdx = idx
|
|
selectedIdx = idx
|
|
|
|
|
+
|
|
|
for (i in 0 until childCount) {
|
|
for (i in 0 until childCount) {
|
|
|
- val v = getChildAt(i)
|
|
|
|
|
- v.isSelected = (i == selectedIdx)
|
|
|
|
|
- v.refreshDrawableState() // ★
|
|
|
|
|
- for (c in 0 until (v as ViewGroup).childCount) {
|
|
|
|
|
- val childView = v.getChildAt(c)
|
|
|
|
|
- when (childView) {
|
|
|
|
|
|
|
+ val container = getChildAt(i) as ViewGroup
|
|
|
|
|
+ val selected = (selectedIdx >= 0 && i == selectedIdx)
|
|
|
|
|
+
|
|
|
|
|
+ container.isSelected = selected
|
|
|
|
|
+ container.refreshDrawableState()
|
|
|
|
|
+
|
|
|
|
|
+ for (c in 0 until container.childCount) {
|
|
|
|
|
+ val child = container.getChildAt(c)
|
|
|
|
|
+ when (child) {
|
|
|
is ImageView -> {
|
|
is ImageView -> {
|
|
|
- if (v.isSelected) {
|
|
|
|
|
- childView.layoutParams = childView.layoutParams.apply {
|
|
|
|
|
- width = iconSelectedSize.toInt()
|
|
|
|
|
- height = iconSelectedSize.toInt()
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- childView.layoutParams = childView.layoutParams.apply {
|
|
|
|
|
- width = iconSize.toInt()
|
|
|
|
|
- height = iconSize.toInt()
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ child.layoutParams = child.layoutParams.apply {
|
|
|
|
|
+ val s = if (selected) iconSelectedSize else iconSize
|
|
|
|
|
+ width = s; height = s
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
is TextView -> {
|
|
is TextView -> {
|
|
|
- if (v.isSelected) {
|
|
|
|
|
- childView.setTextSize(
|
|
|
|
|
- TypedValue.COMPLEX_UNIT_PX, textSelectedSizePx.toFloat()
|
|
|
|
|
- )
|
|
|
|
|
- } else {
|
|
|
|
|
- childView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx.toFloat())
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ child.setTextSize(
|
|
|
|
|
+ TypedValue.COMPLEX_UNIT_PX,
|
|
|
|
|
+ (if (selected) textSelectedSizePx else textSizePx).toFloat()
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- childView.refreshDrawableState() // ★
|
|
|
|
|
|
|
+ child.refreshDrawableState()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
invalidate()
|
|
invalidate()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
@SuppressLint("RestrictedApi")
|
|
@SuppressLint("RestrictedApi")
|
|
|
override fun onDraw(canvas: Canvas) {
|
|
override fun onDraw(canvas: Canvas) {
|
|
|
// 菜单发生变化(比如运行时 add/remove)时自动重建
|
|
// 菜单发生变化(比如运行时 add/remove)时自动重建
|
|
@@ -256,17 +255,29 @@ class CustomNavBar @JvmOverloads constructor(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var selectedItemId: Int
|
|
var selectedItemId: Int
|
|
|
- @SuppressLint("RestrictedApi") get() = menuBuilder.getItemOrNull(selectedIdx)?.itemId
|
|
|
|
|
- ?: View.NO_ID
|
|
|
|
|
- @SuppressLint("RestrictedApi") set(id) {
|
|
|
|
|
- if (isEmpty() && menuBuilder.size() > 0) buildItems() // ★
|
|
|
|
|
- val idx =
|
|
|
|
|
- (0 until menuBuilder.size()).firstOrNull { menuBuilder.getItem(it).itemId == id }
|
|
|
|
|
- ?: return
|
|
|
|
|
|
|
+ @SuppressLint("RestrictedApi")
|
|
|
|
|
+ get() = if (selectedIdx in 0 until menuBuilder.size())
|
|
|
|
|
+ menuBuilder.getItem(selectedIdx).itemId
|
|
|
|
|
+ else View.NO_ID
|
|
|
|
|
+ @SuppressLint("RestrictedApi")
|
|
|
|
|
+ set(id) {
|
|
|
|
|
+ if (isEmpty() && menuBuilder.size() > 0) buildItems()
|
|
|
|
|
+
|
|
|
|
|
+ // ★ 支持“清空选中”
|
|
|
|
|
+ if (id == View.NO_ID) {
|
|
|
|
|
+ selectIndex(NO_SELECTION)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ val idx = (0 until menuBuilder.size())
|
|
|
|
|
+ .firstOrNull { menuBuilder.getItem(it).itemId == id }
|
|
|
|
|
+ ?: return
|
|
|
|
|
+
|
|
|
selectIndex(idx)
|
|
selectIndex(idx)
|
|
|
onItemSelected?.invoke(menuBuilder.getItem(idx))
|
|
onItemSelected?.invoke(menuBuilder.getItem(idx))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
// —— 工具 —— //
|
|
// —— 工具 —— //
|
|
|
private fun dp(dp: Float): Int = AutoSizeUtils.dp2px(context, dp)
|
|
private fun dp(dp: Float): Int = AutoSizeUtils.dp2px(context, dp)
|
|
|
private fun sp(sp: Float): Int = AutoSizeUtils.sp2px(context, sp)
|
|
private fun sp(sp: Float): Int = AutoSizeUtils.sp2px(context, sp)
|
|
@@ -286,4 +297,11 @@ class CustomNavBar @JvmOverloads constructor(
|
|
|
@SuppressLint("RestrictedApi")
|
|
@SuppressLint("RestrictedApi")
|
|
|
private fun MenuBuilder.getItemOrNull(i: Int): MenuItem? =
|
|
private fun MenuBuilder.getItemOrNull(i: Int): MenuItem? =
|
|
|
if (i in 0 until size()) getItem(i) else null
|
|
if (i in 0 until size()) getItem(i) else null
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 取消选择
|
|
|
|
|
+ */
|
|
|
|
|
+ fun clearSelected() {
|
|
|
|
|
+ selectIndex(NO_SELECTION) // 直接调 index 逻辑,别再走 selectedItemId
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|