ActionMode
ActionMode模式为在页面产生一个悬浮的类似于ActionBar的控件,悬浮在ActionBar之上,可以在不占用页面空间的情况下增加功能入口。ActionMode有两种模式
- Primary Action :控件覆盖出现在上方ActionBar之上
- Floating Action:控件浮动出现在任意View的四周
Primary Action | Floating Action |
---|---|
启动方式
通过Activity或者View的startActionMode
方法启动,并接受两个参数:ActionMode.Callback
、ActionMode.Type
public ActionMode startActionMode(android.view.ActionMode.Callback callback, int type)
ActionMode.Callback定义了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定义了前面介绍的两种ActionMode类型
public abstract class ActionMode {
public static final int TYPE_FLOATING = 1;
public static final int TYPE_PRIMARY = 0;
︙
}
封装ActionModeController
我们封装ActionModeController类,简化ActionMode使用体验
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
}
}
}
}
接下来实际看一下使用效果
<?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)
}
}
}
更加Kotlin范儿的封装
ActionModeController适合在Java或者Kotlin中使用,如果我们只面向Kotlin使用,可以在ActionModeController基础上,分装的更加Kotlin范儿:
fun Activity.startActionMode(@MenuRes resId: Int, type: Int, onAction: (MenuItem) -> Unit) =
ActionModeController(resId, type, onAction).startActionMode(this)
通过扩展函数,完全隐去了对ActionModeController
的定义和调用,非常简洁。