背景
我试图让工具栏只显示操作项。无题。我希望它们尽可能地填充空间,如果没有空间,请将它们放在溢出菜单项上。
这可以包括所有类型的操作项(包括具有自定义操作 View 的操作项)。
问题
出于某种原因,即使我在工具栏上设置了所有内边距/间距,并且为每个操作项设置了 SHOW_AS_ACTION_IF_ROOM
,它也不会发生。
即使还有很多空间,它最多显示 2 个项目:
我尝试过的
我尝试设置工具栏的各种填充/间距重置:
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
android:padding="0px" app:contentInsetEnd="0px" app:contentInsetEndWithActions="0px" app:contentInsetLeft="0px"
app:contentInsetRight="0px" app:contentInsetStart="0px" app:contentInsetStartWithNavigation="0px"
app:layout_constraintEnd_toEndOf="parent" app:logo="@null" app:title="@null" app:titleMargin="0px"
tools:background="#ffcc0000" />
为了测试它,我使用了:
for (i in 0..10)
toolbar.menu.add("item $i").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
遗憾的是,正如我所说,这没有帮助。
我还尝试使用 ActionMenuView
而不是 Toolbar
编写一些代码,但它有太多仅从库调用并依赖于它的函数。我找不到办法让它看起来与工具栏相似,而且在某些情况下它还存在一些奇怪的点击效果问题。
问题
如何设置工具栏,让所有项目都能在有足够空间的情况下自行查看,如果有些项目放不下,则让它们显示在溢出菜单中?
有没有办法覆盖工具栏的行为?这种行为到底写在哪里?
最佳答案
好吧,我有办法解决这个问题,但它有一些重要的注释和假设。我认为通过一些调整,它也可以解决我过去问过的类似问题 to have the action items on the left 。全部写在代码中:
ToolbarAdjuster.kt
object ToolbarAdjuster {
/**
* a special behavior for Toolbar, to put all of its menu items that can fit - to actually fit, and the rest to be in overflow menu
* Important notes and assumptions:
* 1. You should call it each time you reset the menu items
* 2. Toolbar has a size. You can use in `onCreateOptionsMenu` if it's the actionBar, or `doOnPreDraw` otherwise.
* 3. Only action items that have actionView can be on the toolbar. The rest should always be in the overflow menu
* 4. Toolbar should consist only of action items. No spacing, no padding, no title, ... Otherwise the calculation will be incorrect.
* Meaning:
* android:padding="0px" app:contentInsetEnd="0px" app:contentInsetEndWithActions="0px" app:contentInsetLeft="0px"
* app:contentInsetRight="0px" app:contentInsetStart="0px" app:contentInsetStartWithNavigation="0px"
* app:layout_constraintEnd_toEndOf="parent" app:logo="@null" app:title="@null" app:titleMargin="0px"
*/
fun adjustToolbar(context: Context, toolbar: Toolbar, menu: Menu) {
val toolbarWidth = toolbar.width
val indexToWidthMap = HashMap<Int, Int>()
val menuItemsCount = menu.size
var sizeSoFar = 0
var foundNeedForOverflowItem = false
//first find if we will need an overflow menu item:
for (i in 0 until menuItemsCount) {
val menuItem = menu[i]
val menuItemView = menuItem.actionView
if (!menuItem.isVisible)
continue
if (menuItemView == null) {
foundNeedForOverflowItem = true
continue
}
menuItemView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val menuItemViewWidth = menuItemView.measuredWidth
indexToWidthMap[i] = menuItemViewWidth
if (menuItemViewWidth + sizeSoFar > toolbarWidth) {
foundNeedForOverflowItem = true
break
}
sizeSoFar += menuItemViewWidth
}
//now we know if we need an overflow menu or not, so go over again, and set each menu item to how it will be shown
var spaceLeft = if (foundNeedForOverflowItem) toolbarWidth - getDefaultOverflowWidth(context) else toolbarWidth
for (i in 0 until menuItemsCount) {
val menuItem = menu[i]
val menuItemView = menuItem.actionView
if (!menuItem.isVisible)
continue
if (menuItemView == null || spaceLeft <= 0) {
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
continue
}
val measuredAItemViewWidth = indexToWidthMap[i]!!
if (spaceLeft - measuredAItemViewWidth < 0) {
//this item's view can't fit into the space we have left, so none of the next ones will fit
spaceLeft = 0
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
} else {
//this item's view can still fit
spaceLeft -= measuredAItemViewWidth
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}
}
private fun getDefaultOverflowWidth(context: Context): Int {
val overflowMenuButton = OverflowMenuButton(context)
overflowMenuButton.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val overflowCellSize = overflowMenuButton.measuredWidth
return if (overflowCellSize > 0) overflowCellSize else TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40f, context.resources.displayMetrics).toInt()
}
/**fake view, copied from ActionMenuPresenter, which is used only to get its width*/
private class OverflowMenuButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.actionOverflowButtonStyle) : AppCompatImageView(context, attrs, defStyleAttr)
}
用法示例:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = null
setSupportActionBar(toolbar)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
for (i in 0..10) {
val actionView = LayoutInflater.from(this).inflate(R.layout.action_item, toolbar, false)
actionView.textView.text = "item $i"
menu.add("item $i").setActionView(actionView).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
for (i in 0..10)
menu.add("item $i").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
ToolbarAdjuster.adjustToolbar(this, toolbar, menu)
return super.onCreateOptionsMenu(menu)
}
}
action_item.xml
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/textView" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="match_parent"
android:background="?attr/selectableItemBackground" android:clickable="true" android:drawableLeft="@android:drawable/ic_dialog_email"
android:drawablePadding="8dp" android:focusable="true" android:focusableInTouchMode="false"
android:gravity="center_vertical|start" android:paddingLeft="15dp" android:paddingRight="15dp"
android:text="text" tools:background="#11ff0000"
tools:layout_gravity="center" tools:layout_height="?attr/actionBarSize" />
activity_main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
android:padding="0px" app:contentInsetEnd="0px" app:contentInsetEndWithActions="0px" app:contentInsetLeft="0px"
app:contentInsetRight="0px" app:contentInsetStart="0px" app:contentInsetStartWithNavigation="0px"
app:layout_constraintEnd_toEndOf="parent" app:logo="@null" app:title="@null" app:titleMargin="0px"
tools:background="#ffcc0000" />
</FrameLayout>
结果如下:
关于android - 如何让工具栏只包含操作项,并尽可能多地利用其空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58838220/