In my application there is a ListFragment where each item from the list contains a checkbox. Whenever the user clicks on one of those checkboxes the app starts an ActionMode context menu.
But I want the application to close the ActionMode menu when clicking on another component.
I tried Fragment#closeContextMenu() without success.
Any ideas how can I accomplish that?
Whenever you are creating/starting ActionMode Create by
mMode = startActionMode(....);
To Dismiss it use following Syntax
if (mMode != null)
{
mMode.finish();
}
actionMode.finish();
When finish method is called from actionmode ...it will destroy the action mode.
#Override
public void onDestroyActionMode(ActionMode mode) {
//When action mode destroyed remove selected selections and set action mode to null
}
and destroy method is called from callback event
Kotlin code
Use ActionMode.Callback to finish ActionMode after menu item pressed
private val actionModeCallbacks = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.menu_action_mode, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_item -> {
mode.finish() // after click of menu item close action mode
return true
}
}
return false
}
override fun onDestroyActionMode(mode: ActionMode) {
}
}
startSupportActionMode
(activity as AppCompatActivity).startSupportActionMode(actionModeCallbacks)
Related
I hope you are well.
My question is why this callback class has two of the same functions?
the only difference that I see is that some functions deal with nullable and the others don't, but in the end, we can achieve what want with both ways (with nullable or without nullable)
if anyone has a good explanation for this and thanks in advance
private val actionModeCallback = object : Callback, android.view.ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false // Return false if nothing is done
}
// Called when the user selects a contextual menu item
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
return false
}
// Called when the user exits the action mode
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
override fun onCreateActionMode(p0: android.view.ActionMode?, p1: Menu?): Boolean {
// Called when the action mode is created; startActionMode() was called
// Inflate a menu resource providing context menu items
val inflater: MenuInflater = p0!!.menuInflater
inflater.inflate(R.menu.memory_fragment_context_menu, p1)
return true
}
override fun onPrepareActionMode(p0: android.view.ActionMode?, p1: Menu?): Boolean {
return false
}
override fun onActionItemClicked(p0: android.view.ActionMode?, p1: MenuItem?): Boolean {
return when (p1?.itemId) {
R.id.someId -> {
Toast.makeText(context,"go to hell", Toast.LENGTH_LONG).show()
selectionTracker?.clearSelection()
p0?.finish() // Action picked, so close the CAB
true
}
else -> false
}
}
override fun onDestroyActionMode(p0: android.view.ActionMode?) {
}
}
I would like to open the settings activity just by clicking on the overflow button in my Material Toolbar.
How can I setup a click listener on this button ? I don't want to inflate any menu by clicking on it, I just want to load another activity.
Before redesigning my app, I was inflating a menu by overriding onCreateOptionsMenu, but now I can't find any method to override that looks like onOverflowIconClickListener, or something like this.
I hope my question was clear enough.
All the answers are found here Menu
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.game_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle item selection
return when (item.itemId) {
R.id.new_game -> {
newGame()
true
}
R.id.help -> {
showHelp()
true
}
else -> super.onOptionsItemSelected(item)
}
}
I am trying setup contextual action bar when long click on a item in a recyclerview. But menu icon is not shown.
Code is given below.
listAdapter.setOnItemClickListener(object : OnItemClickListener {
override fun onItemClick(position: Int) {
...
}
override fun onItemLongClick(position: Int): Boolean {
if (actionMode != null) {
return false
}
val activity = activity as AppCompatActivity
actionMode = activity.startSupportActionMode(actionModeCallback)
return true
}
})
Action Mode callback
internal val actionModeCallback = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.item_delete -> {
actionMode?.finish()
return true
}
}
return false
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
actionMode?.menuInflater?.inflate(R.menu.menu_context, menu)
actionMode?.title = "delete"
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {
actionMode = null
}
}
menu_context.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/item_delete"
android:title="#string/menu_option_text_delete"
android:icon="#drawable/ic_delete_white_24dp"
app:showAsAction="always"
/>
</menu>
What I tried?
using non support lib version for Activity and ActionMode
tried changing action mode background to see whether the issue with the theming
set SHOW_AS_ACTION_ALWAYS in onPrepareActionMode
Did not work, even the action mode title is not shown.
I am using androidx, appCompat version : 1.1.0-rc01
Please help!
The soulution is to update the menus manually in onPrepareActionMode
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
menu.findItem(R.id.menu_archive).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.findItem(R.id.menu_delete).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.findItem(R.id.menu_upload_to_cloud).setShowAsAction
(MenuItem.SHOW_AS_ACTION_ALWAYS);
return true;
}
Actually this was a mistake in my part as pointed out in the issue tracker
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
/*-->*/mode?.menuInflater?.inflate(R.menu.menu_context, menu)
return true
}
Note that you should use the passed in mode and not your own
ActionMode object to get the correct inflater.
I have a list activity in which the user can do open action modes A and B. The user can also open action mode A then B on top of it.
The problem is that when action mode A is shown and action mode B is shown on top of it, A gets closed automatically when B is shown. The user can't navigate back from B to A.
I thought I could take note of action mode A visibility when action mode B is opened then restore it when action mode B is closed, but that doesn't work. It seems that it's not possible to immediately show another action mode after closing one. However this issue only happens if the action mode A is closed with the back arrow. When closed by code (ActionMode.finish()), action mode B can be shown, but the closing animation doesn't make it look like user is navigating back from B to A. So this solution is out of question.
So is there a way to open an action mode on top of another, or at least replace the menu layout of an action mode programatically then change it back?
Action mode A is actually the search action mode, from which the user can select results which opens action mode B if that can help to understand.
I think I reached desired behavior through postDelayed() from onDestroyActionMode of action mode B.
This is not very elegant solution, but it works.
My code snippet:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listView.onItemClickListener = AdapterView.OnItemClickListener { adapterView, view, p2, p3 ->
startActionModeA()
true
}
}
var actionModeA: ActionMode? = null
val actionModeCallbackA = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, p1: MenuItem?): Boolean {
Log.wtf("ACTION MODE", "onActionItemClicked")
actionModeB = startActionMode(actionModeCallbackB)
return true
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
Log.wtf("ACTION MODE", "onCreateActionMode")
val inflater = mode?.getMenuInflater()
inflater?.inflate(R.menu.context_menu, menu)
return true
}
override fun onPrepareActionMode(p0: ActionMode?, p1: Menu?): Boolean {
Log.wtf("ACTION MODE", "onPrepareActionMode")
return false
}
override fun onDestroyActionMode(p0: ActionMode?) {
Log.wtf("ACTION MODE", "onDestroyActionMode")
actionModeA = null
}
}
var actionModeB: ActionMode? = null
val actionModeCallbackB = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, p1: MenuItem?): Boolean {
Log.wtf("ACTION MODE 2", "onActionItemClicked")
return true
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
Log.wtf("ACTION MODE 2", "onCreateActionMode")
val inflater = mode?.getMenuInflater()
inflater?.inflate(R.menu.context_menu2, menu)
return true
}
override fun onPrepareActionMode(p0: ActionMode?, p1: Menu?): Boolean {
Log.wtf("ACTION MODE 2", "onPrepareActionMode")
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {
Log.wtf("ACTION MODE 2", "onDestroyActionMode")
actionModeB = null
listView.postDelayed({
startActionModeA()
}, 100)
}
}
private fun startActionModeA() {
actionModeA = startActionMode(actionModeCallbackA)
}
I have an Implementation of ActionMode to display the number of multi
selected items in a RecyclerView.
I would like to know when the back button in the actionMode is tapped so as to correspondingly reset the recyclerView but while implementing the ActionMode.Callback, i noticed that onDestroyActionMode is called whenever ActionMode is updated thus actionMode?.setTitle($selectedItems.size), which makes it impossible reset the recyclerView - remove selected items, remove overlay color and notify the recyclerview of data set changed.
Here's my Callback
inner class ActionModeCallback : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
when (item?.getItemId()) {
R.id.action_delete -> {
myAdapter?.deleteSelectedIds()
actionMode?.setTitle("") //remove item count from action mode.
actionMode?.finish()
return true
}
}
return false
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
val inflater = mode?.getMenuInflater()
inflater?.inflate(R.menu.action_mode_menu, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.findItem(R.id.action_delete)?.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {
Log.d(TAG, "onDestroyActionMode Called")
//myAdapter?.selectedIds?.clear()
//myAdapter?.notifyDataSetChanged()
actionMode = null
}
}
How Can i know when the ActionMode back button is tapped?
Full source code Here =>https://github.com/Edge-Developer/RecyclerViewMultiSelectExample
Holy Gosh. It was my fault, i was starting a New ActionMode each time an item is selected (through an interface on MainActivity) instead of checking if it has already been started before starting a new One.
Here was my code
actionMode = startActionMode(ActionModeCallback())
Here is the updated code
if (actionMode == null) actionMode = startActionMode(ActionModeCallback())
now, the onDestroyActionMode is called only once, after the actionMode is dismissed!
You can check the github repo on how's it was implemented
This problem was faced while implementing multiselection on a recyclerView.