提问人:A. Cedano 提问时间:11/14/2023 更新时间:11/14/2023 访问量:24
防止 ScrollView 在应用进入后台时返回顶部
Prevent ScrollView from returning to top when app goes to background
问:
我在一个片段中有一个 ScrollView,当应用程序进入后台并重新打开它时,它总是回到顶部。
根据这个答案,我试图用 来防止这种情况,但问题仍然存在。android:descendantFocusability="blocksDescendants"
我怎样才能防止它总是去顶部,停留在文本视图的部分,当应用程序进入后台时?
是什么导致了这种行为?我有另一个相同的布局,我将其加载到另一个片段中,并且没有出现问题。为什么它只发生在这个片段中?
布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".core.presentation.today.TodayFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:background="@color/textBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.deiverbum.app.util.ZoomTextView
android:id="@+id/tv_Zoomable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:contentDescription="@string/app_name" />
</LinearLayout>
</ScrollView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="200dp"
android:indeterminate="true"
android:minWidth="200dp"
android:minHeight="70dp"
android:progress="0" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
片段
@AndroidEntryPoint
class TodayFragment : BaseFragment<FragmentTodayBinding>() {
private val mViewModel: TodayViewModel by viewModels()
private lateinit var mTextView: ZoomTextView
private var progressBar: ProgressBar? = null
private var seekBar: SeekBar? = null
private var isReading = false
private var isVoiceOn = false
private var hasInvitatory = false
private var sbReader: StringBuilder? = null
private var audioMenu: Menu? = null
private var voiceItem: MenuItem? = null
private var mTtsManager: TtsManager? = null
private var mainMenu: Menu? = null
private var mActionMode: ActionMode? = null
private lateinit var todayRequest: TodayRequest
override fun constructViewBinding(): ViewBinding =
FragmentTodayBinding.inflate(layoutInflater)
override fun init(viewBinding: ViewBinding) {
setMenu()
setConfiguration()
fetchData()
}
val mActionModeCallback: ActionMode.Callback = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
val menuItem = item.itemId
if (menuItem == R.id.audio_play) {
readText()
audioMenu?.findItem(R.id.audio_pause)?.isVisible = true
audioMenu?.findItem(R.id.audio_stop)?.isVisible = true
item.isVisible = false
return true
}
if (menuItem == R.id.audio_pause) {
mTtsManager?.pause()
audioMenu?.findItem(R.id.audio_resume)?.isVisible = true
item.isVisible = false
return true
}
if (menuItem == R.id.audio_resume) {
mTtsManager?.resume()
audioMenu?.findItem(R.id.audio_pause)?.isVisible = true
item.isVisible = false
return true
}
if (menuItem == R.id.audio_stop) {
mTtsManager?.stop()
audioMenu?.findItem(R.id.audio_play)?.isVisible = true
audioMenu?.findItem(R.id.audio_pause)?.isVisible = false
audioMenu?.findItem(R.id.audio_resume)?.isVisible = false
item.isVisible = false
return true
}
return false
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.contextual_action_bar, menu)
audioMenu = menu
@SuppressLint("InflateParams") val view: View =
LayoutInflater.from(context).inflate(R.layout.seekbar, null)
mode.customView = view
seekBar = view.findViewById(R.id.seekbar)
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
mActionMode = null
cleanTTS()
setPlayerButton()
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false
}
}
private fun fetchData() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
mViewModel.uiState.collect { state ->
when (state) {
is TodayViewModel.TodayUiState.Loaded -> onLoaded(state.itemState)
is TodayViewModel.TodayUiState.Error -> showError(state.message)
else -> showLoading()
}
}
}
}
}
private fun onLoaded(todayItemUiState: TodayItemUiState) {
todayItemUiState.run {
getViewBinding().progressBar.visibility = View.GONE
if (todayResponse.success) {
getViewBinding().tvZoomable.text = todayResponse.dataModel.getAllForView(todayRequest)
//mTextView.text = todayResponse.dataModel.getAllForView(false,false)
if (isVoiceOn) {
sbReader = todayResponse.dataModel.getAllForRead()
}
} else {
val msgNoData = activity?.resources?.getString(R.string.err_no_data)
getViewBinding().tvZoomable.text = msgNoData
}
}
}
private fun showLoading() {
mTextView.text = PACIENCIA
}
private fun showError(stringRes: String) {
mTextView.text = stringRes
Toast.makeText(requireContext(), stringRes, Toast.LENGTH_SHORT).show()
}
private fun setMenu() {
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.toolbar_menu, menu)
mainMenu = menu
voiceItem = menu.findItem(R.id.item_voz)
voiceItem!!.isVisible = isVoiceOn
if (isReading) {
voiceItem!!.isVisible = false
}
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
android.R.id.home -> {
val navController =
NavHostFragment.findNavController(requireParentFragment())
navController.popBackStack()
true
}
R.id.item_voz -> {
if (mActionMode == null) {
mActionMode =
requireActivity().startActionMode(mActionModeCallback)
}
readText()
isReading = true
voiceItem?.isVisible = false
requireActivity().invalidateOptionsMenu()
true
}
else -> {
val navController =
NavHostFragment.findNavController(requireParentFragment())
NavigationUI.onNavDestinationSelected(menuItem, navController)
}
}
}
}, viewLifecycleOwner)
}
private fun setConfiguration() {
val args: TodayFragmentArgs by navArgs()
mTextView = getViewBinding().tvZoomable
progressBar = getViewBinding().progressBar
val sp = PreferenceManager.getDefaultSharedPreferences(requireActivity().applicationContext)
val fontSize = sp?.getString("font_size", "18")!!.toFloat()
val fontFamily = String.format(
Locale("es"),
"fonts/%s",
sp.getString("font_name", "robotoslab_regular.ttf")
)
val tf = Typeface.createFromAsset(requireActivity().assets, fontFamily)
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize)
mTextView.typeface = tf
hasInvitatory = sp.getBoolean("invitatorio", false)
isVoiceOn = sp.getBoolean("voice", true)
todayRequest =
TodayRequest(pickOutDate(), args.hourId, isNightMode(), hasInvitatory)
mViewModel.loadData(todayRequest)
}
private fun setPlayerButton() {
voiceItem!!.isVisible = isVoiceOn
}
private fun readText() {
mTtsManager = TtsManager(
context,
sbReader.toString(),
Constants.SEPARADOR
) { current: Int, max: Int ->
seekBar!!.progress = current
seekBar!!.max = max
}
seekBar!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (mTtsManager == null) return
mTtsManager!!.changeProgress(progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
mTtsManager!!.start()
}
private fun cleanTTS() {
mTtsManager?.close()
}
private fun pickOutDate(): Int {
val bundle = arguments
val mDate = if (bundle != null && bundle.containsKey("FECHA")) {
bundle.getInt("FECHA")
} else {
Utils.hoy.toInt()
}
val actionBar = (requireActivity() as AppCompatActivity).supportActionBar
actionBar?.subtitle = Utils.formatDate(mDate.toString(), "yyyyMMdd", "d '-' MMMM yyyy")
return mDate
}
override fun onDestroyView() {
super.onDestroyView()
if (mActionMode != null) {
mActionMode!!.finish()
}
cleanTTS()
}
}
答: 暂无答案
评论
android:id
ScrollView
android:descendantFocusability="blocksDescendants"
LinearLayout
ScrollView