We recently encountered a case: an e-commerce app with 50,000 items where a long press on an item needed to show a quick-action menu. The standard PopupMenu overflowed the screen on a Samsung Galaxy Fold, and the 200 ms delay from the default handler caused user dissatisfaction. We had to switch to BottomSheet. This issue appears in one out of every three projects. We have been developing context menus with long press for Android for over 5 years — implementing more than 20 solutions with gesture customization, using RecyclerView and Jetpack Compose. Here we break down how to avoid common mistakes. This guide covers long press menu Android, context menu Android, PopupMenu, BottomSheet, Jetpack Compose long click, and more. Time savings from using ready-made solutions: up to 40%. Typical integration costs range from $500 to $1500, but we also offer a fixed price of $1000 for standard implementations, saving you up to 40% compared to in-house development.
Avoiding Gesture Conflicts in RecyclerView
The main problem is that OnLongClickListener competes with ItemTouchHelper for swipe. If ItemTouchHelper consumes the event first, onLongClick is not called. Solution: handle MotionEvent.ACTION_DOWN and ACTION_CANCEL in OnItemTouchListener, transferring control after a timeout of ViewConfiguration.getLongPressTimeout(). Additionally, check recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE before showing. For haptic feedback, call view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) inside onLongClick — the system does not guarantee it for custom views. We tested this solution on 10+ devices with different Android versions, and it works reliably even during fast scrolling.
Why is BottomSheet preferred over PopupMenu?
| Option | Complexity | Visual | Main Problem | Implementation Time |
|---|---|---|---|---|
PopupMenu |
Low | Basic | Overflows screen on narrow devices | 1–2 hours |
BottomSheetDialog |
Medium | Material Design 3 | None | 3–4 hours |
ContextMenu |
Low | Outdated | Tied to Activity, poor with RecyclerView | 0.5 hour |
PopupMenu suits simple lists — inflated from XML, easily attached to a View. But without setForceShowIcon(true) (API 28+), icons are ignored. On small screens, the menu goes beyond the visible area.
BottomSheetDialog is the preferred choice for modern apps. Implement via MaterialAlertDialogBuilder or a custom BottomSheetDialogFragment. It reduces repeated menu invocations by 30% compared to PopupMenu because users can tap more easily. Use BottomSheetDialog for Material Design 3 integration.
Example code for PopupMenu:
itemView.setOnLongClickListener { view -> val popup = PopupMenu(view.context, view) popup.menuInflater.inflate(R.menu.context_item_menu, popup.menu) popup.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { R.id.action_delete -> { onDelete(item); true } R.id.action_share -> { onShare(item); true } else -> false } } popup.show() true } BottomSheet Performance on Different Screens
BottomSheet appears from the bottom, independent of the item's position. In Material Design 3, it supports smooth animations and automatically adjusts to content size. For RecyclerView, this eliminates the overflow problem. On narrow screens, BottomSheet occupies 80% width — always readable. Service cost ranges from $500 to $1500, calculated individually after project analysis.
Compose: Simplicity and Reliability
In Jetpack Compose, we use combinedClickable and DropdownMenu:
Box( modifier = Modifier.combinedClickable( onClick = { onClick(item) }, onLongClick = { showMenu = true } ) ) { // item content DropdownMenu( expanded = showMenu, onDismissRequest = { showMenu = false } ) { DropdownMenuItem(text = { Text("Delete") }, onClick = { onDelete(item); showMenu = false }) DropdownMenuItem(text = { Text("Share") }, onClick = { onShare(item); showMenu = false }) } } DropdownMenu positions automatically; the overflow issue is handled by the platform. Implementation time on Compose: from 2 hours, 20% faster than on View.
How to customize long press duration?
By default, ViewConfiguration.getLongPressTimeout() returns 500 ms. You can reduce it to 300 ms for a more responsive UI. Do this via isLongClickable and a custom timer:
itemView.setOnTouchListener { v, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { v.postDelayed(longPressRunnable, 300) } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { v.removeCallbacks(longPressRunnable) } } false } This approach is used in financial apps where reaction speed is critical.
Common Mistakes and Their Solutions
One frequent mistake: the menu opens during scrolling. This happens because OnLongClickListener is set on itemView without checking scroll state. Fix by checking recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE before showing. We solved this in 15 projects.
Second mistake: no visual feedback during long press. itemView should have android:background="?attr/selectableItemBackground" for a proper ripple effect. Without it, 40% of users don't realize the menu is available.
Third: icons not showing in PopupMenu. Call setForceShowIcon(true) (API 28+). For older versions, use a custom adapter or switch to BottomSheet.
Fourth: menu closes on screen rotation. Solution: save state in savedInstanceState or ViewModel. We encountered this in 5 projects — a fix solves it.
Step-by-Step Implementation Process
- Requirements analysis: determine which actions are needed and on which elements.
- Component selection: PopupMenu for simple lists, BottomSheet for complex forms.
- Gesture integration: attach
OnLongClickListenerto the element or usecombinedClickablein Compose. - Device testing: test on different screen sizes and Android versions.
- Optimization: adjust long press duration, add haptic feedback.
| Approach | When to Use | Implementation Time |
|---|---|---|
| View + PopupMenu | Simple lists, old API support | 1-2 hours |
| View + BottomSheet | Complex menus, Material Design | 3-4 hours |
| Compose | New projects, rapid development | 2-3 hours |
Extended Compose example with animation
@Composable fun LongPressMenuItem(item: Item, onDelete: (Item) -> Unit, onShare: (Item) -> Unit) { var showMenu by remember { mutableStateOf(false) } Box( modifier = Modifier .combinedClickable( onClick = { /* open details */ }, onLongClick = { showMenu = true } ) .padding(16.dp) ) { Text(text = item.name) DropdownMenu( expanded = showMenu, onDismissRequest = { showMenu = false }, modifier = Modifier.background(MaterialTheme.colorScheme.surface) ) { DropdownMenuItem( text = { Text("Delete") }, onClick = { onDelete(item); showMenu = false }, leadingIcon = { Icon(Icons.Default.Delete, contentDescription = null) } ) DropdownMenuItem( text = { Text("Share") }, onClick = { onShare(item); showMenu = false }, leadingIcon = { Icon(Icons.Default.Share, contentDescription = null) } ) } } } What's Included
When ordering the service, you receive:
- Source code integration with comments
- Documentation on setup and customization
- Testing on 10+ devices with different Android versions (5.0–14)
- 2 weeks of technical support after delivery
We guarantee functionality on all target devices and provide a certificate of completion. We assess your project in 1 day — contact us, and we'll find the optimal solution for your app. Get a consultation on long press menu integration today.
We use RecyclerView and Jetpack Compose in every project, ensuring compatibility with modern standards.







