增加阅读底部按钮自定义功能

This commit is contained in:
HapeLee
2025-08-29 02:11:29 +08:00
parent b3e9040089
commit ed21dca146
12 changed files with 501 additions and 184 deletions
@@ -80,6 +80,7 @@ import io.legato.kazusa.ui.book.read.config.ReadAloudDialog
import io.legato.kazusa.ui.book.read.config.ReadStyleDialog
import io.legato.kazusa.ui.book.read.config.TipConfigDialog.Companion.TIP_COLOR
import io.legato.kazusa.ui.book.read.config.TipConfigDialog.Companion.TIP_DIVIDER_COLOR
import io.legato.kazusa.ui.book.read.config.ToolButtonConfigDialog
import io.legato.kazusa.ui.book.read.page.ContentTextView
import io.legato.kazusa.ui.book.read.page.ReadView
import io.legato.kazusa.ui.book.read.page.entities.PageDirection
@@ -151,6 +152,7 @@ class ReadBookActivity : BaseReadBookActivity(),
ChangeChapterSourceDialog.CallBack,
ReadBook.CallBack,
AutoReadDialog.CallBack,
ToolButtonConfigDialog.CallBack,
TxtTocRuleDialog.CallBack,
ColorPickerDialogListener,
LayoutProgressListener {
@@ -533,6 +535,11 @@ class ReadBookActivity : BaseReadBookActivity(),
ReadBook.loadContent(false)
}
R.id.menu_tool_button -> {
binding.readMenu.runMenuOut()
showDialogFragment(ToolButtonConfigDialog())
}
// R.id.menu_enable_review -> {
// AppConfig.enableReview = !AppConfig.enableReview
// item.isChecked = AppConfig.enableReview
@@ -1485,6 +1492,10 @@ class ReadBookActivity : BaseReadBookActivity(),
binding.readView.autoPager.resume()
}
override fun refresh() {
recreate()
}
override fun onLayoutPageCompleted(index: Int, page: TextPage) {
upSeekBarThrottle.invoke()
binding.readView.onLayoutPageCompleted(index, page)
@@ -2,6 +2,8 @@ package io.legato.kazusa.ui.book.read
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
@@ -13,6 +15,8 @@ import android.widget.SeekBar
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialButtonGroup
import com.google.android.material.slider.Slider
import io.legato.kazusa.R
import io.legato.kazusa.constant.PreferKey
@@ -41,7 +45,6 @@ import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.themeColor
import io.legato.kazusa.utils.visible
import splitties.views.onClick
import splitties.views.onLongClick
/**
* 阅读界面菜单
@@ -189,6 +192,10 @@ class ReadMenu @JvmOverloads constructor(
//// tvChapterName.setTextColor(textColor)
//// tvChapterUrl.setTextColor(textColor)
// }
val allButtons = getUserButtons()
renderButtons(binding.bottomView, allButtons)
val brightnessBackground = GradientDrawable()
brightnessBackground.cornerRadius = 5F.dpToPx()
//brightnessBackground.setColor(ColorUtils.adjustAlpha(bgColor, 0.5f))
@@ -231,7 +238,12 @@ class ReadMenu @JvmOverloads constructor(
/**
* 确保视图不被导航栏遮挡
*/
binding.bottomView.applyNavigationBarPadding()
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
binding.bottomMenu.applyNavigationBarPadding()
} else {
binding.bottomView.applyNavigationBarPadding()
}
}
fun reset() {
@@ -459,20 +471,6 @@ class ReadMenu @JvmOverloads constructor(
}
})
//搜索
fabSearch.setOnClickListener {
runMenuOut {
callBack.openSearchActivity(null)
}
}
//自动翻页
fabAutoPage.setOnClickListener {
runMenuOut {
callBack.autoPage()
}
}
//替换
//fabReplaceRule.setOnClickListener { callBack.openReplaceRule() }
@@ -488,32 +486,130 @@ class ReadMenu @JvmOverloads constructor(
//下一章
tvNext.setOnClickListener { ReadBook.moveToNextChapter(true) }
//目录
ivCatalog.setOnClickListener {
runMenuOut {
callBack.openChapterList()
}
fun renderButtons(group: MaterialButtonGroup, buttons: List<ToolButton>) {
group.removeAllViews()
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
buttons.forEach { btn ->
val button = MaterialButton(
group.context,
null,
com.google.android.material.R.attr.materialIconButtonFilledTonalStyle
).apply {
id = btn.id.hashCode()
setIconResource(btn.iconRes)
contentDescription = btn.description
tooltipText = btn.description
setOnClickListener { btn.onClick() }
btn.onLongClick?.let { longAction ->
setOnLongClickListener {
longAction()
true
}
}
}
group.addView(button)
}
} else {
buttons.forEach { btn ->
val button = MaterialButton(
group.context,
null,
com.google.android.material.R.attr.materialIconButtonOutlinedStyle
).apply {
id = btn.id.hashCode()
setIconResource(btn.iconRes)
contentDescription = btn.description
tooltipText = btn.description
strokeWidth = 0
val primaryColor = context.themeColor(androidx.appcompat.R.attr.colorPrimary)
iconTint = ColorStateList.valueOf(primaryColor)
setOnClickListener { btn.onClick() }
btn.onLongClick?.let { longAction ->
setOnLongClickListener {
longAction()
true
}
}
}
group.addView(button)
}
}
}
private fun getAllButtons(): List<ToolButton> {
return listOf(
ToolButton(
id = "search",
iconRes = R.drawable.ic_search,
description = context.getString(R.string.search_content),
onClick = { callBack.openSearchActivity(null) }
),
ToolButton(
id = "auto_page",
iconRes = R.drawable.ic_auto_page,
description = context.getString(R.string.auto_next_page),
onClick = { callBack.autoPage() }
),
ToolButton(
id = "catalog",
iconRes = R.drawable.ic_toc,
description = context.getString(R.string.chapter_list),
onClick = { callBack.openChapterList() }
),
ToolButton(
id = "read_aloud",
iconRes = R.drawable.ic_read_aloud,
description = context.getString(R.string.read_aloud),
onClick = { callBack.onClickReadAloud() },
onLongClick = { callBack.showReadAloudDialog() }
),
ToolButton(
id = "setting",
iconRes = R.drawable.ic_settings,
description = context.getString(R.string.setting),
onClick = { callBack.showReadStyle() }
),
ToolButton(
id = "addBookmark",
iconRes = R.drawable.ic_bookmark,
description = context.getString(R.string.bookmark),
onClick = { callBack.addBookmark() }
)
)
}
private fun getUserButtons(): List<ToolButton> {
val prefs by lazy {
context.getSharedPreferences("tool_button_config", Context.MODE_PRIVATE)
}
val allButtons = getAllButtons().associateBy { it.id }
val str = prefs.getString("tool_buttons", null)
val savedList = str?.split(";")?.mapNotNull {
val parts = it.split(",")
if (parts.size == 2) parts[0] to parts[1].toBoolean() else null
} ?: emptyList()
val result = mutableListOf<ToolButton>()
savedList.forEach { (id, enabled) ->
if (enabled) allButtons[id]?.let { result.add(it) }
}
getAllButtons().forEach { btn ->
if (savedList.none { it.first == btn.id }) {
result.add(btn)
}
}
//朗读
ivReadAloud.setOnClickListener {
runMenuOut {
callBack.onClickReadAloud()
}
}
ivReadAloud.onLongClick {
runMenuOut {
callBack.showReadAloudDialog()
}
}
//设置
ivSetting.setOnClickListener {
runMenuOut {
callBack.showReadStyle()
}
}
return result
}
private fun initAnimation() {
@@ -522,8 +618,16 @@ class ReadMenu @JvmOverloads constructor(
}
fun upBookView() {
binding.titleBar.title = " "
binding.tvBookName.text = ReadBook.book?.name
val bookName = ReadBook.book?.name ?: ""
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
binding.titleBar.title = bookName
binding.tvBookName.gone()
} else {
binding.titleBar.title = " "
binding.tvBookName.text = bookName
}
ReadBook.curTextChapter?.let {
binding.tvChapterName.text = it.title
if (!ReadBook.isLocalBook) {
@@ -598,16 +702,18 @@ class ReadMenu @JvmOverloads constructor(
}
fun setAutoPage(autoPage: Boolean) = binding.run {
if (autoPage) {
fabAutoPage.setIconResource(R.drawable.ic_auto_page_stop)
fabAutoPage.contentDescription = context.getString(R.string.auto_next_page_stop)
} else {
fabAutoPage.setIconResource(R.drawable.ic_auto_page)
fabAutoPage.contentDescription = context.getString(R.string.auto_next_page)
fabAutoPage?.let { fab ->
if (autoPage) {
fab.setIconResource(R.drawable.ic_auto_page_stop)
fab.contentDescription = context.getString(R.string.auto_next_page_stop)
} else {
fab.setIconResource(R.drawable.ic_auto_page)
fab.contentDescription = context.getString(R.string.auto_next_page)
}
}
//fabAutoPage.setColorFilter(textColor)
}
private fun upBrightnessVwPos() {
if (AppConfig.brightnessVwPos) {
binding.root.modifyBegin()
@@ -630,6 +736,7 @@ class ReadMenu @JvmOverloads constructor(
fun openSourceEditActivity()
fun openBookInfoActivity()
fun showReadStyle()
fun addBookmark()
fun showReadAloudDialog()
fun upSystemUiVisibility()
fun onClickReadAloud()
@@ -642,4 +749,11 @@ class ReadMenu @JvmOverloads constructor(
fun onMenuHide()
}
}
data class ToolButton(
val id: String, // 唯一标识
val iconRes: Int, // 图标资源
val description: String, // contentDescription / tooltipText
val onClick: () -> Unit, // 点击事件
val onLongClick: (() -> Unit)? = null // 可选长按
)
}
@@ -24,20 +24,6 @@ class AutoReadDialog : BaseBottomSheetDialogFragment(R.layout.dialog_auto_read)
private val binding by viewBinding(DialogAutoReadBinding::bind)
private val callBack: CallBack? get() = activity as? CallBack
override fun onStart() {
super.onStart()
// dialog?.window?.run {
// clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
// setBackgroundDrawableResource(R.color.background)
// decorView.setPadding(0, 0, 0, 0)
// val attr = attributes
// attr.dimAmount = 0.0f
// attr.gravity = Gravity.BOTTOM
// attributes = attr
// setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
// }
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
(activity as ReadBookActivity).bottomDialog--
@@ -49,20 +35,6 @@ class AutoReadDialog : BaseBottomSheetDialogFragment(R.layout.dialog_auto_read)
dismiss()
return
}
//val bg = requireContext().bottomBackground
//val isLight = ColorUtils.isColorLight(bg)
//val textColor = requireContext().getPrimaryTextColor(isLight)
//root.setBackgroundColor(bg)
// tvReadSpeedTitle.setTextColor(textColor)
// tvReadSpeed.setTextColor(textColor)
// ivCatalog.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
// tvCatalog.setTextColor(textColor)
// ivMainMenu.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
// tvMainMenu.setTextColor(textColor)
// ivAutoPageStop.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
// tvAutoPageStop.setTextColor(textColor)
// ivSetting.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
// tvSetting.setTextColor(textColor)
initOnChange()
initData()
initEvent()
@@ -31,14 +31,6 @@ import io.legato.kazusa.utils.showDialogFragment
class ReadAloudConfigDialog : BasePrefDialogFragment() {
private val readAloudPreferTag = "readAloudPreferTag"
override fun onStart() {
super.onStart()
dialog?.window?.run {
//setBackgroundDrawableResource(R.color.transparent)
//setLayout(0.9f, ViewGroup.LayoutParams.WRAP_CONTENT)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -0,0 +1,200 @@
package io.legato.kazusa.ui.book.read.config
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.legato.kazusa.R
import io.legato.kazusa.base.BaseBottomSheetDialogFragment
import io.legato.kazusa.databinding.DialogToolButtonConfigBinding
import io.legato.kazusa.databinding.ItemToolButtonBinding
import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
class ToolButtonConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tool_button_config) {
private val binding by viewBinding(DialogToolButtonConfigBinding::bind)
private val prefs by lazy {
requireContext().getSharedPreferences(
"tool_button_config",
Context.MODE_PRIVATE
)
}
private val callBack: CallBack? get() = activity as? CallBack
private lateinit var adapter: ToolButtonAdapter
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) = binding.run {
val configList = loadButtonConfig().toMutableList()
adapter = ToolButtonAdapter(configList)
recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
val touchHelper = ItemTouchHelper(TouchHelperCallback(adapter))
touchHelper.attachToRecyclerView(recyclerView)
btnSave.setOnClickListener {
saveButtonConfig(adapter.items)
callBack?.refresh()
dismiss()
}
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
(activity as ReadBookActivity).bottomDialog--
}
data class ConfigEntry(val id: String, var enabled: Boolean)
inner class ToolButtonAdapter(val items: MutableList<ConfigEntry>) :
RecyclerView.Adapter<ToolButtonAdapter.VH>() {
inner class VH(val binding: ItemToolButtonBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val binding = ItemToolButtonBinding.inflate(layoutInflater, parent, false)
return VH(binding)
}
override fun onBindViewHolder(holder: VH, position: Int) {
val item = items[position]
val (iconRes, name) = getButtonInfo(item.id)
holder.binding.tvName.text = name
holder.binding.ivIcon.setIconResource(iconRes)
holder.binding.ivIcon.isEnabled = item.enabled
holder.binding.btnDisable.icon = ContextCompat.getDrawable(
holder.itemView.context,
if (item.enabled) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
)
holder.binding.btnDisable.setOnClickListener {
val pos = holder.bindingAdapterPosition
if (pos == RecyclerView.NO_POSITION) return@setOnClickListener
item.enabled = !item.enabled
holder.binding.btnDisable.icon = ContextCompat.getDrawable(
holder.itemView.context,
if (item.enabled) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
)
if (!item.enabled) {
val removed = items.removeAt(pos)
items.add(removed)
notifyItemMoved(pos, items.size - 1)
} else {
notifyItemChanged(pos)
}
holder.binding.ivIcon.isEnabled = item.enabled
}
}
override fun getItemCount() = items.size
fun swap(from: Int, to: Int) {
if (from == RecyclerView.NO_POSITION || to == RecyclerView.NO_POSITION) return
val fromItem = items[from]
val toItem = items[to]
if (!fromItem.enabled || !toItem.enabled) return
items.add(to, items.removeAt(from))
notifyItemMoved(from, to)
}
}
private fun getAllButtonIds(): List<String> {
return listOf("search", "auto_page", "catalog", "read_aloud", "setting", "addBookmark")
}
private fun getButtonInfo(id: String): Pair<Int, String> {
return when (id) {
"search" -> R.drawable.ic_search to getString(R.string.search_content)
"auto_page" -> R.drawable.ic_auto_page to getString(R.string.auto_next_page)
"catalog" -> R.drawable.ic_toc to getString(R.string.chapter_list)
"read_aloud" -> R.drawable.ic_read_aloud to getString(R.string.read_aloud)
"setting" -> R.drawable.ic_settings to getString(R.string.setting)
"addBookmark" -> R.drawable.ic_bookmark to getString(R.string.bookmark)
else -> R.drawable.ic_help to id
}
}
private fun loadButtonConfig(): List<ConfigEntry> {
val str = prefs.getString("tool_buttons", null)
return if (str.isNullOrBlank()) {
getAllButtonIds().map { ConfigEntry(it, true) }
} else {
val saved = str.split(";").mapNotNull {
val parts = it.split(",")
if (parts.size == 2) ConfigEntry(parts[0], parts[1].toBoolean()) else null
}.toMutableList()
val allIds = getAllButtonIds()
for (id in allIds) {
if (saved.none { it.id == id }) {
saved.add(ConfigEntry(id, true))
}
}
saved
}
}
private fun saveButtonConfig(list: List<ConfigEntry>) {
val str = list.joinToString(";") { "${it.id},${it.enabled}" }
prefs.edit { putString("tool_buttons", str) }
}
class TouchHelperCallback(
private val adapter: ToolButtonAdapter
) : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val pos = viewHolder.bindingAdapterPosition
if (pos == RecyclerView.NO_POSITION) return 0
val item = adapter.items[pos]
return if (!item.enabled) {
0
} else {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
makeMovementFlags(dragFlags, 0)
}
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.bindingAdapterPosition
val toPos = target.bindingAdapterPosition
if (fromPos == RecyclerView.NO_POSITION || toPos == RecyclerView.NO_POSITION) return false
adapter.swap(fromPos, toPos)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
override fun isLongPressDragEnabled() = true
}
interface CallBack {
fun refresh()
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M160,600L160,520L800,520L800,600L160,600ZM160,440L160,360L800,360L800,440L160,440Z" />
</vector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,640Q555,640 607.5,587.5Q660,535 660,460Q660,385 607.5,332.5Q555,280 480,280Q405,280 352.5,332.5Q300,385 300,460Q300,535 352.5,587.5Q405,640 480,640ZM480,568Q435,568 403.5,536.5Q372,505 372,460Q372,415 403.5,383.5Q435,352 480,352Q525,352 556.5,383.5Q588,415 588,460Q588,505 556.5,536.5Q525,568 480,568ZM480,760Q334,760 214,678.5Q94,597 40,460Q94,323 214,241.5Q334,160 480,160Q626,160 746,241.5Q866,323 920,460Q866,597 746,678.5Q626,760 480,760ZM480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460ZM480,680Q593,680 687.5,620.5Q782,561 832,460Q782,359 687.5,299.5Q593,240 480,240Q367,240 272.5,299.5Q178,359 128,460Q178,561 272.5,620.5Q367,680 480,680Z" />
</vector>
@@ -136,13 +136,13 @@
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
android:layout_weight="2" />
<!--章节设置-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_weight="2"
android:layout_marginVertical="8dp"
android:importantForAccessibility="no"
android:gravity="center"
@@ -174,8 +174,6 @@
android:layout_gravity="center_vertical"/>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.button.MaterialButton
android:id="@+id/tv_next"
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
@@ -189,15 +187,15 @@
tools:ignore="TouchTargetSizeCheck"/>
</LinearLayout>
<LinearLayout
<com.google.android.material.button.MaterialButtonGroup
android:id="@+id/bottom_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:layout_weight="2"
android:importantForAccessibility="no"
android:paddingVertical="8dp"
android:paddingEnd="16dp"
android:gravity="center"
android:paddingHorizontal="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
@@ -256,7 +254,7 @@
app:iconGravity="textStart"
tools:ignore="NestedWeights" />
</LinearLayout>
</com.google.android.material.button.MaterialButtonGroup>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/header_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingBottom="8dp">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="配置底部按钮"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSave"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginBottom="8dp"
android:text="@string/action_save"
android:textColor="?attr/colorTertiary"
app:backgroundTint="?attr/colorTertiaryContainer" />
</LinearLayout>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp">
<!-- 图标 -->
<com.google.android.material.button.MaterialButton
android:id="@+id/ivIcon"
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false" />
<!-- 按钮名称 -->
<TextView
android:id="@+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:text="按钮名称"
android:textColor="?attr/colorOnSurface"
android:textSize="16sp" />
<!-- 禁用/隐藏按钮 -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnDisable"
style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
app:icon="@drawable/ic_visibility_on" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:src="@drawable/ic_drag_handle" />
</LinearLayout>
+3 -91
View File
@@ -180,7 +180,7 @@
tools:ignore="TouchTargetSizeCheck"/>
</LinearLayout>
<LinearLayout
<com.google.android.material.button.MaterialButtonGroup
android:id="@+id/bottom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -188,99 +188,11 @@
android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
android:background="?attr/colorSurfaceContainer"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/fabSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.IconButton"
android:background="?attr/selectableItemBackgroundBorderless"
app:iconTint="?attr/colorPrimary"
android:contentDescription="@string/search_content"
android:tooltipText="@string/search_content"
app:icon="@drawable/ic_search"
app:iconGravity="textStart"/>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:importantForAccessibility="no" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_read_aloud"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.IconButton"
android:background="?attr/selectableItemBackgroundBorderless"
app:iconTint="?attr/colorPrimary"
android:contentDescription="@string/read_aloud"
android:maxHeight="24dp"
app:icon="@drawable/ic_read_aloud"
app:iconGravity="textStart"
tools:ignore="NestedWeights" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:importantForAccessibility="no" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_catalog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.IconButton"
android:background="?attr/selectableItemBackgroundBorderless"
app:iconTint="?attr/colorPrimary"
android:contentDescription="@string/chapter_list"
android:tooltipText="@string/chapter_list"
android:maxHeight="24dp"
app:icon="@drawable/ic_toc"
app:iconGravity="textStart"
tools:ignore="NestedWeights" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:importantForAccessibility="no" />
<com.google.android.material.button.MaterialButton
android:id="@+id/fabAutoPage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.IconButton"
android:background="?attr/selectableItemBackgroundBorderless"
app:iconTint="?attr/colorPrimary"
android:contentDescription="@string/auto_next_page"
android:tooltipText="@string/auto_next_page"
app:icon="@drawable/ic_auto_page"
app:iconGravity="textStart"
tools:ignore="UnusedAttribute" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:importantForAccessibility="no" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.IconButton"
android:background="?attr/selectableItemBackgroundBorderless"
app:iconTint="?attr/colorPrimary"
android:contentDescription="@string/setting"
android:tooltipText="@string/setting"
android:maxHeight="24dp"
app:icon="@drawable/ic_settings"
app:iconGravity="textStart"
tools:ignore="NestedWeights" />
</LinearLayout>
</com.google.android.material.button.MaterialButtonGroup>
</LinearLayout>
</LinearLayout>
+5
View File
@@ -44,6 +44,11 @@
</group>
<item
android:id="@+id/menu_tool_button"
android:title="配置底部按钮"
app:showAsAction="never" />
<item
android:id="@+id/menu_add_bookmark"
android:title="@string/bookmark_add"