我正在尝试让工具栏仅显示操作项。无题。我希望它们尽可能地填充空间,如果没有空间,可以在溢出菜单项中放置它们。
这可以包括各种动作项(包括具有自定义动作视图的动作项)。
由于某种原因,即使我已经在工具栏上设置了所有填充/间距,并且即使我为每个操作项都设置了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
编写一些代码,但是它有太多的函数,只能从库中调用并依赖于此。我找不到使它看起来与工具栏相似的方法,并且在某些情况下,它还存在一些奇怪的单击效果问题。
如果有足够的空间,如何设置工具栏以使所有项目都可以自己查看;如果有些项目无法容纳,则将其置于溢出菜单中?
有没有一种方法可以覆盖工具栏的行为?这种行为甚至写在哪里?
答案 0 :(得分:2)
好的,我有解决的办法,但是其中有一些重要的注意事项和假设。我认为,通过一些调整,它也可以解决我过去问过的类似问题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>
结果如下: