Reputation: 173
Is it possible to perform a long press on a menu item to perform a certain action? I'm trying to have a menu dropdown when I long press a certain item.
Here's the menu xml
<item
android:id="@+id/add_item"
android:icon="@drawable/ic_add_black_24dp"
android:showAsAction="ifRoom"
android:title="Add Item">
</item>
<item
android:id="@+id/open_menu"
android:icon="@drawable/ic_menu_black_24dp"
android:showAsAction="ifRoom|withText"
android:title="Open Menu">
</item>
I want to have a dropdown appear when the first item is long pressed
Upvotes: 5
Views: 8550
Reputation: 1
Remie's answer is perfect for me. Thanks!
In my case, implemented into Fragment with MenuHost.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val menuHost: MenuHost = requireActivity() as MenuHost
menuHost.addMenuProvider(
object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.your_menu, menu)
menu.findItem(R.id.your_item_id_in_your_menu_resource).setOnTextTapEventListener(
onTap = { /** do something **/ },
onLongTap = { /** do something **/ },
)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
// Not required because it was overwritten in onTap above.
// When you call `menu.performIdentifierAction` in `actionView.setOnClickListener, you can handle here, maybe.
// R.id.your_item_id_in_your_menu_resource -> { }
android.R.id.home -> {
findNavController().navigateUp()
true
}
else -> false
}
}
},
viewLifecycleOwner
)
}
Here is my extension of MenuItem inspired by Remie's answer.
import android.view.MenuItem
import com.google.android.material.button.MaterialButton
fun MenuItem.setOnTextTapEventListener(
onTap: () -> Unit,
onLongTap: () -> Unit,
) {
setActionView(R.layout.your_action_view)
// It's enough to use `this.title` in "my" case.
actionView.findViewById<MaterialButton>(R.id.menu_action_text_button).text = this.title
actionView.setOnLongClickListener {
onLongTap.invoke()
true
}
actionView.setOnClickListener {
onTap.invoke()
}
}
Upvotes: 0
Reputation: 177
Easy with Kotlin (and keeping the same style as other icons):
fun MenuItem.onMenuItemLongClickListener(menu: Menu, function: () -> (Unit)) {
setActionView(R.layout.view_action_button)
actionView.find<ImageButton>(R.id.item).setImageDrawable(icon)
actionView.setOnLongClickListener {
function()
true }
actionView.setOnClickListener { menu.performIdentifierAction(itemId, 0) }
}
view_action_button.xml
:
<?xml version="1.0" encoding="utf-8"?>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item"
style="?android:attr/actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Usage:
menu.findItem(R.id.your_item).onMenuItemLongClickListener(menu) { anyFunction() }
Just change R.id.your_item
and anyFunction()
Upvotes: 3
Reputation: 498
Here is another solution to your question. I have used a menu in res/menu/menu.xml as below:
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_send"
android:orderInCategory="100"
android:title="@string/send_menu"
app:showAsAction="always" />
</menu>
And here is my activity class. I have added a imagebutton to the menu item and set a image resource to it. Backgroud is set to null to have a transparent menuItem.
public class MyActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem item = menu.findItem(R.id.action_send);
ImageButton imageButton = new ImageButton(this);
imageButton.setImageResource(R.drawable.ic_send_white_24dp);
imageButton.setBackground(null);
item.setActionView(imageButton);
item.getActionView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.d("Send Button", "Long pressed");
Toast.makeText(MainActivity.this, "Send button long pressed", Toast.LENGTH_LONG).show();
onSendMenuItemLongClick();
return true;
}
});
item.getActionView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onSendMenuItemClick(item);
}
});
return super.onCreateOptionsMenu(menu);
}
private void onSendMenuItemLongClick() {
}
private void onSendMenuItemClick(MenuItem item) {
Toast.makeText(this, "Send button clicked", Toast.LENGTH_LONG).show();
}
}
Upvotes: 0
Reputation: 21736
You can do this with Handler
and Runnable
. Inside run()
method, get the View
of your desired MenuItem
and set onLongClick
listener to View
.
Here is the working code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
new Handler().post(new Runnable() {
@Override
public void run() {
final View view = findViewById(R.id.add_item);
if (view != null) {
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// Do something...
Toast.makeText(getApplicationContext(), "Long pressed", Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
});
return super.onCreateOptionsMenu(menu);
}
OUTPUT:
Upvotes: 9