android - 在片段的 OnViewCreated 中启动时,ActionMode 回调永远不会调用 onCreateActionMode
问题描述
@ExperimentalCoroutinesApi
class WeekdayTimesFragment @Inject constructor(viewModelFactory: SavedStateViewModelFactory.Factory)
:Fragment(R.layout.fragment_weekday_times), WeekdayAlarmTimesAdapter.OnWeekdayAlarmTimePressed, ActionModeListener {
private lateinit var weekdayAlarmTimesAdapter: WeekdayAlarmTimesAdapter
private val weekdayTimesViewModel
by viewModels<WeekdayTimesViewModel> { viewModelFactory.create(this) }
override val actionCallback = PrimaryActionCallback(this)
private var weekday: Int = 0
private val isActionModeActive: Boolean
get() = weekdayTimesViewModel.isActionModeActive
private val numSelected: Int
get() = weekdayTimesViewModel.selectedTimePositions.size
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
weekday = requireArguments().get("WEEKDAY") as Int
if(isActionModeActive) { //action mode may be active prior to rotation
startActionMode() //for some reason, starting action mode here does not work....
}
initRecyclerView() //will determine what recyclerview items are selected via the viewmodel
weekdayTimesViewModel.getTimesAndAlarmsForSelectedWeekday(Weekday[weekday])
.observe(viewLifecycleOwner) { times->
weekdayAlarmTimesAdapter.submitWeekdayTimes(times)
}
}
override fun alarmTimePressed(wasSelected: Boolean, position: Int, time: WeekdayTime) {
if(wasSelected) { //this item was selected prior to being selected, effectively unselecting it
weekdayTimesViewModel.selectedTimePositions.remove(position)
} else {
weekdayTimesViewModel.selectedTimePositions[position] =
Time(time.hour, time.minute, Weekday[weekday], time.alarm.alarmId, time.isDisabled, time.id)
}
if(numSelected == 0 && isActionModeActive) { //no more times are selected, turn off action mode
destroyActionMode() //need to de-select recyclerview items
} else {
if (!isActionModeActive) {
startActionMode()
} else {
actionCallback.changeTitle("$numSelected selected")
}
}
}
private fun startActionMode() {
actionCallback
.startActionMode(
requireView(),
R.menu.toolbar_contextual_menu,
"$numSelected selected")
//fragment hosting the viewpager
(requireParentFragment() as ActionModeListenerController).currentActionModeListener = this
weekdayTimesViewModel.isActionModeActive = true
}
override fun onActionItemClick(item: MenuItem?) {
item?.let {
when(it.itemId){
R.id.toolbar_disable_alarm-> {
requireContext().createGenericAlertDialog(
message = if(numSelected == 1) "Are you sure you want to disable this alarm?"
else "Are you sure you want to disable these alarms?",
positiveListener = { _, _ ->
weekdayTimesViewModel.disableSelectedTimes()
showUndoSnackbar(true)
}
).show()
}
R.id.toolbar_delete_alarms-> {
requireContext().createGenericAlertDialog(
message = if(numSelected == 1) "Are you sure you want to delete this alarm?"
else "Are you sure you want to delete these alarms?",
positiveListener = { _, _ ->
weekdayTimesViewModel.deleteSelectedTimes()
showUndoSnackbar(false)
}
).show()
}
}
}
}
//when we aren't destroying the view but need to end action mode (changing tab or after we confirm an action)
//we may want to do specific things specific to certain listeners, e.g. de-select certain recyclerview items.
override fun destroyActionMode() {
actionCallback.finishActionMode()
weekdayTimesViewModel.isActionModeActive = false
//also un-select all of the elements that have been selected
weekdayTimesViewModel.selectedTimePositions.clear()
//redraw recyclerview as well
rv_weekday_times.resetAdapterState()
}
private fun showUndoSnackbar(disablingTimes: Boolean){
val message =
if(disablingTimes) "Your alarm times have been disabled." else "Your alarm times have been deleted."
Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).setAction("UNDO"){
if(disablingTimes)
weekdayTimesViewModel.restoreDisabledTimes()
else
weekdayTimesViewModel.restoreDeletedTimes()
}.setActionTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary))
.setAnchorView(requireActivity().bottom_nav_view).show()
}
//when rotating screen or navigating we can just end action mode. The state of whether we are
//in action mode either doesn't matter (navigation) or is already persisted, along with the selected
//items in the viewmodel(rotation)
override fun onDestroyView() {
actionCallback.finishActionMode()
super.onDestroyView()
}
private fun initRecyclerView() {
weekdayAlarmTimesAdapter = WeekdayAlarmTimesAdapter(this, weekdayTimesViewModel.selectedTimePositions.keys)
rv_weekday_times.apply {
adapter = weekdayAlarmTimesAdapter
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}
weekdayAlarmTimesAdapter.selectedItems.clear()
//clears selected items as these items no longer remain consistently for the lifecycle of the view
}
}
因此,当我通过 recyclerview 的 OnBindViewHolder 中设置的单击侦听器获得回调 (alarmTimePressed) 时,我的 ActionMode 工作得很好。我启动了我的 ActionMode 并且效果很好,我保存了 ActionMode 在我的视图模型中是否处于活动状态,这在旋转时效果很好,就好像它在旋转之前处于活动状态一样,它仍然保持活动状态。正如您在我的 OnViewCreated 中看到的那样,当 ActionMode 应该处于活动状态时,我会调用 startActionMode()。问题是当我从那里启动它时,永远不会调用 onCreateActionMode 回调。这很奇怪,因为即使在旋转之后,如果我在 RecyclerView 中选择一个项目,它也会正确启动 ActionMode。我传递给 startActionMode 的视图在这两种情况下都是相同的。如果您需要 PrimaryActionCallback 的代码,请访问:https ://hastebin.com/vepujuhefe.m. 不认为这是非常必要的,但如果你觉得有必要看看:)。有人知道这里发生了什么吗?
解决方案
推荐阅读
- c# - 如何在构建时为 JetBrains Rider 转换 .Config?
- mysql - 如何将过时的 MySQL `SELECT * FROM table GROUP BY column1` 查询转换为更正 MySQL 8 语法?
- python - 将 JSON 文件转换为 CSV 文件
- sql - 如何获得返回总和的子查询的总和?
- python - 在 Amazon AWS 上安装 jupyter notebook
- amazon-web-services - 从命令行创建 Elastic Beanstalk 环境时,如何定义现有的自定义 VPC?
- javascript - Django:如何在 AJAX POST 请求中检索两个不同变量的值?
- java - Android SharedPreferences 和加密的 SharedPreferences
- reactjs - 如何修复错误扩展接口“请求”
' 错误 - dataframe - 在 pyspark 中删除重复项时进行聚合