Reputation: 115932
I have an action item that's not quite standard. It has its own layout, because I've failed to create a nice Drawable for it (written about it here).
Basically, it's just a TextView with a background that wraps its short text that it shows.
Sadly I can't find a way of fully mimic it to look like normal ones:
Here are screenshots to demonstrate the differences:
The new, non standard, action item:
A native action item:
For the color of the ripple effect, I think I can use "colorControlHighlight", but I can't find out which color is the one used by default, correctly. I've looked inside the "values.xml" file of the support library, and noticed that it's "ripple_material_dark" color (or "ripple_material_light", in case the toolbar is supposed to be white) , but this seems a bit like a hack.
Not sure about the size, but looking at the layout inspector, I think the view has padding:
I've also noticed that the view class name of the toolbar is ActionMenuItemView
. I tried to look at its code (probably avaialble online too, here) , but didn't notice anything mentioned there about background. For padding I think it just tries to put the icon in the middle:
Anyway, this is the current code of the POC:
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var goToTodayView: View
lateinit var goToTodayTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
goToTodayView = LayoutInflater.from(this).inflate(R.layout.go_to_today_action_item, toolbar, false)
goToTodayTextView = goToTodayView.goToTodayTextView
goToTodayTextView.setBackgroundDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_backtodate))
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menu.add("goToToday").setActionView(goToTodayView).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
menu.add("asd").setIcon(R.drawable.abc_ic_menu_copy_mtrl_am_alpha).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) //for comparison
return super.onCreateOptionsMenu(menu)
}
}
go_to_today_action_item.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/selectableItemBackgroundBorderless" android:backgroundTint="#fff" android:clickable="true"
android:focusable="true">
<TextView
android:id="@+id/goToTodayTextView" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:gravity="center" android:text="1"
android:textColor="#fff" android:textSize="12dp" tools:background="@drawable/ic_backtodate" tools:layout_gravity="center"/>
</FrameLayout>
ActionMenuItemView
class somehow? Maybe a very different solution from what I tried?EDIT: for the background of the action items, I made it a bit like the original ones, but it's still not the same. Clicking effect seems a tiny bit different, and I haven't found how to show the toast of the action item upon long clicking on it. Here's the result:
Anyway, here's what I did:
go_to_today_action_item.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:clickable="true"
android:focusable="true">
<ImageView
android:layout_width="@dimen/action_item_background_size"
android:layout_height="@dimen/action_item_background_size" android:layout_gravity="center"
android:background="@drawable/action_item_selector" android:duplicateParentState="true"/>
<TextView
android:id="@+id/goToTodayTextView" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:gravity="center" android:text="31" android:textColor="#fff"
android:textSize="12dp" tools:background="@drawable/ic_backtodate" tools:layout_gravity="center"/>
</FrameLayout>
drawable/action_item_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/clicking_semi_white_ripple_color"/>
</shape>
</item>
<item android:drawable="@android:color/transparent"/>
</selector>
drawable-v21/action_item_selector.xml
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/clicking_semi_white_ripple_color">
<item android:id="@android:id/mask">
<shape android:shape="oval">
<solid android:color="@android:color/white"/>
</shape>
</item>
</ripple>
colors.xml
<color name="clicking_semi_white_ripple_color">#33ffffff</color>
values/dimens.xml
<dimen name="action_item_background_size">48dp</dimen>
values-v21/dimens.xml
<dimen name="action_item_background_size">40dp</dimen>
Upvotes: 4
Views: 221
Reputation: 62831
The following code will use your layout to populate a standard menu item for the date. As a standard menu item, it will exhibit all the characteristics that you are looking for and should be compatible with future changes to a menu item's behavior.
The basic concept is to inflate the layout with the boxed date and use its drawing cache to create a bitmap that is then used as the drawable for the menu item's icon.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var goToTodayView: View? = null
private var goToTodayTextView: TextView? = null
private val textDrawable: TextDrawable? = null
private var mOptionsMenu: Menu? = null
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(findViewById<View>(R.id.toolbar) as Toolbar)
testWithCustomViews()
}
private fun updateDateView() {
if (mOptionsMenu == null)
return
goToTodayView!!.invalidate()
goToTodayView!!.buildDrawingCache()
val bmp = Bitmap.createBitmap(goToTodayView!!.drawingCache)
val d = BitmapDrawable(resources, bmp)
mOptionsMenu!!.getItem(0).icon = d
}
private fun testWithCustomViews() {
val toolbar = findViewById<View>(R.id.toolbar) as Toolbar
goToTodayView = LayoutInflater.from(this).inflate(R.layout.go_to_today_action_item, toolbar, false)
goToTodayView!!.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
goToTodayView!!.layout(0, 0, goToTodayView!!.measuredWidth, goToTodayView!!.measuredHeight)
goToTodayTextView = goToTodayView!!.findViewById(R.id.goToTodayTextView)
goToTodayTextView!!.setBackgroundDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_backtodate))
goToTodayView!!.isDrawingCacheEnabled = true
val handler = Handler()
val runnable = object : Runnable {
internal var i = 0
override fun run() {
if (isFinishing || isDestroyed)
return
goToTodayTextView!!.text = (i + 1).toString()
i = (i + 1) % 31
updateDateView()
handler.postDelayed(this, 1000)
}
}
runnable.run()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
mOptionsMenu = menu
menu.add("goToToday").setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
updateDateView()
menu.add("asd").setIcon(R.drawable.abc_ic_menu_copy_mtrl_am_alpha).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return super.onCreateOptionsMenu(menu)
}
}
Since go_to_today_action_item.xml
now doesn't need the extra views to mimic standard menu item behavior, it can be stripped down. In fact, the menu item icon appears too small without adjustments. Change go_to_today_action_item.xml
to the following:
<TextView
android:id="@+id/goToTodayTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/ic_backtodate"
android:gravity="center"
android:text="31"
android:textColor="#fff"
android:textSize="12dp"
tools:layout_gravity="center" />
Upvotes: 2