ActionMode
The ActionMode mode is to generate a floating control similar to the ActionBar on the page, floating above the ActionBar, which can increase the function entry without occupying the page space. ActionMode has two modes
- Primary Action: The control overlay appears on the upper ActionBar
- Floating Action: The control floats around any View
Primary Action | Floating Action |
---|---|
Start method
startActionMode
Start by the method of Activity or View , and accept two parameters: ActionMode.Callback
、ActionMode.Type
public ActionMode startActionMode(android.view.ActionMode.Callback callback, int type)
ActionMode.Callback defines the life cycle callback of ActionMode:
public interface Callback {
// AcionMode创建
boolean onCreateActionMode(ActionMode var1, Menu var2);
// AcionMode状态变化时(无效、或者项目更新)
boolean onPrepareActionMode(ActionMode var1, Menu var2);
// AcionMode菜单项被选中时
boolean onActionItemClicked(ActionMode var1, MenuItem var2);
// AcionMode销毁
void onDestroyActionMode(ActionMode var1);
}
ActionMode.Type defines the two ActionMode types introduced earlier
public abstract class ActionMode {
public static final int TYPE_FLOATING = 1;
public static final int TYPE_PRIMARY = 0;
︙
}
Encapsulate ActionModeController
We encapsulate the ActionModeController class to simplify the ActionMode experience
class ActionModeController(
// menu的resId
@MenuRes private val resId: Int,
// ActionMode 类型
private val type: Int,
// menu选择后回调
private val onAction : (MenuItem) -> Unit
) {
// 从Activiy启动
fun startActionMode(activity: Activity) {
activity.startActionMode(createActionModeCallback(), type)
}
// 从View启动
fun startActionMode(view: View) {
view.startActionMode(createActionModeCallback(), type)
}
private fun createActionModeCallback(): ActionMode.Callback {
return object: ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(resId, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
override fun onDestroyActionMode(mode: ActionMode) {
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
onAction.invoke(item)
mode.finish()
return true
}
}
}
}
Next, take a look at the actual use effect
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/first"
android:title="@string/first"
android:icon="@drawable/ic_done"
/>
<item
android:id="@+id/second"
android:title="@string/second"
android:icon="@drawable/ic_close"
/>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
tools:context=".MainFragment"
android:orientation="vertical">
<Button
android:id="@+id/primary_action_mode_activity_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="PRIMARY ACTION MODE (ACTIVITY)"/>
<Button
android:id="@+id/primary_action_mode_view_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="PRIMARY ACTION MODE (VIEW)"/>
<Button
android:id="@+id/floating_action_mode_activity_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="FLOATING ACTION MODE (ACTIVITY)"/>
<Button
android:id="@+id/floating_action_mode_view_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="FLOATING ACTION MODE (VIEW)"/>
</LinearLayout>
class MainFragment : Fragment(R.layout.fragment_main) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Primary Action
val primaryActionModeController = ActionModeController(R.menu.action_menus, ActionMode.TYPE_PRIMARY) {
when (it.itemId) {
R.id.first -> {
Toast.makeText(context, "FIRST", Toast.LENGTH_SHORT).show()
}
R.id.second -> {
Toast.makeText(context, "SECOND", Toast.LENGTH_SHORT).show()
}
}
}
// Floating Action
val floatingActionModeController = ActionModeController(R.menu.action_menus, ActionMode.TYPE_FLOATING) {
when (it.itemId) {
R.id.first -> {
Toast.makeText(context, "FIRST", Toast.LENGTH_SHORT).show()
}
R.id.second -> {
Toast.makeText(context, "SECOND", Toast.LENGTH_SHORT).show()
}
}
}
// Activity 启动 Primary Action
primary_action_mode_activity_button.setOnClickListener {
primaryActionModeController.startActionMode(requireActivity())
}
// View 启动 Primary Action
primary_action_mode_view_button.setOnClickListener {
primaryActionModeController.startActionMode(it)
}
// Activity 启动 Floating Action
floating_action_mode_activity_button.setOnClickListener {
floatingActionModeController.startActionMode(requireActivity())
}
// View 启动 Floating Action
floating_action_mode_view_button.setOnClickListener {
floatingActionModeController.startActionMode(it)
}
}
}
More Kotlin-style packaging
ActionModeController is suitable for use in Java or Kotlin. If we only use it for Kotlin, we can build a more Kotlin style based on ActionModeController:
fun Activity.startActionMode(@MenuRes resId: Int, type: Int, onAction: (MenuItem) -> Unit) =
ActionModeController(resId, type, onAction).startActionMode(this)
Through the extension function, ActionModeController
the definition and call are completely hidden , which is very concise.