3

我有一个包含许多片段的活动(使用喷气背包导航)。在我的第一个片段上,我有一个 recyclerview。如果我在第一个片段上滚动然后导航到另一个片段,该片段将保留滚动位置,我不希望那样。一个例子如下:

即假设我有两个片段 A 和 B,当我的应用程序启动时,它从 A 开始。假设我开始在 A 上滚动,然后导航到 B。我的应用程序保留 B 上的滚动位置,这不是我想要的。我希望片段 B 从顶部开始。然后当它返回到片段 A 时,我希望它保留之前滚动的滚动位置。

片段 A.xml

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

<data>

    <import type="android.view.View" />

    <variable
        name="ViewModel"
        type="....AccountViewModel" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/Layout_Fragment_Account"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <!--
       Recyclerview
    -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RecyclerView_Account"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="@{ViewModel.accountListVisibility? View.VISIBLE : View.GONE}"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:visibility="gone" />


    <!--
        Empty Views and group
    -->
    <androidx.constraintlayout.widget.Group
        android:id="@+id/Empty_View"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="@{ViewModel.accountEmptyViewVisibility? 

View.VISIBLE : View.GONE}"
            app:constraint_referenced_ids="Empty_View_Illustration,Empty_View_Title,Empty_View_Subtitle" />

    <ImageView
        android:id="@+id/Empty_View_Illustration"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toTopOf="@+id/Empty_View_Title"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed"
        app:srcCompat="@drawable/il_account" />

    <TextView
        android:id="@+id/Empty_View_Title"
        style="@style/Locky.Text.Title6"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        android:text="@string/text_title_emptyView_accounts"
        android:textAlignment="center"
        app:layout_constraintBottom_toTopOf="@id/Empty_View_Subtitle"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/Empty_View_Illustration"
        app:layout_constraintVertical_chainStyle="packed"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent=".8" />

    <TextView
        android:id="@+id/Empty_View_Subtitle"
        style="@style/Locky.Text.Subtitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        android:layout_marginBottom="?attr/actionBarSize"
        android:text="@string/text_subtitle_emptyView_accounts"
        android:textAlignment="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.6"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/Empty_View_Title"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent=".8" />

    <!--
        Progress Bar
    -->
    <include
        android:id="@+id/Progress_Bar"
        layout="@layout/custom_view_list_loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="@{ViewModel.loadingStatus? View.VISIBLE : View.GONE}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

片段 A.kt:

class AccountFragment : Fragment() {

private var _binding: FragmentAccountBinding? = null
private var _viewModel: AccountViewModel? = null
private var _lastClickTime: Long = 0

private val binding get() = _binding!!
private val viewModel get() = _viewModel!!

companion object {
    const val TAG = "ACCOUNT_FRAGMENT_DEBUG"
}

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    _binding = FragmentAccountBinding.inflate(inflater, container, false)
    // Fetch view model
    _viewModel = ViewModelProvider(this).get(AccountViewModel::class.java)
    //Bind view model to layout
    binding.viewModel = _viewModel
    // Bind lifecycle owner
    binding.lifecycleOwner = this

    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    /* Hides the soft keyboard */
    hideSoftKeyboard(binding.root)

    /* Observe snack bar events */
    observeSnackBarEvent()

    /* Observe the account list changes */
    observeAccounts()

    /* Observe back stack entry result after navigating from sort sheet */
    observeBackStackEntryForSortSheet()
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setHasOptionsMenu(true)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    inflater.inflate(R.menu.menu_toolbar_filter, menu)
    super.onCreateOptionsMenu(menu, inflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.Toolbar_Filter -> {
            navigateToSort()
            true
        }
        else -> false
    }
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

/*
* My Functions
*/
private fun observeBackStackEntryForSortSheet() {
    val navController = findNavController()
    // After a configuration change or process death, the currentBackStackEntry
    // points to the dialog destination, so you must use getBackStackEntry()
    // with the specific ID of your destination to ensure we always
    // get the right NavBackStackEntry
    val navBackStackEntry = navController.getBackStackEntry(R.id.Fragment_Account)

    // Create our observer and add it to the NavBackStackEntry's lifecycle
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains(KEY_ACCOUNTS_SORT)
        ) {

            viewModel.sortChange(
                navBackStackEntry.savedStateHandle.get<AccountSort>(
                    KEY_ACCOUNTS_SORT
                )!!
            )

            navBackStackEntry.savedStateHandle.remove<AccountSort>(KEY_ACCOUNTS_SORT)
        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })
}

private fun observeSnackBarEvent() {
    viewModel.showSnackBarEvent.observe(viewLifecycleOwner, Observer {
        if (it != null) {
            snackBarAction(it)
        }
    })
}

private fun observeAccounts() {
    with(viewModel) {
        accounts.observe(viewLifecycleOwner, Observer {
            if (it != null) {
                //set loading flag to hide loading animation
                doneLoading()

                //Alternate visibility for account list and empty view
                alternateAccountListVisibility(it.size)

                //Submit the cards
                initiateAccounts().submitList(it)
            }
        })
    }
}

private fun initiateAccounts(): AccountAdapter {
    val adapter = AccountAdapter(
        AccountClickListener {
            navigateToSelectedAccount(it)
        },
        AccountOptionsClickListener { view, card ->
            view.apply {
                isEnabled = false
            }
            createPopupMenu(view, card)
        })

    binding.RecyclerViewAccount.apply {
        this.adapter = adapter
        setHasFixedSize(true)
    }

    return adapter
}

private fun createPopupMenu(view: View, account: Account) {
    requireContext().createPopUpMenu(
        view,
        R.menu.menu_moreoptions_account,
        PopupMenu.OnMenuItemClickListener {
            when (it.itemId) {
                R.id.Menu_CopyUsername -> copyToClipboardAndToast(account.username)
                R.id.Menu_CopyPass -> copyToClipboardAndToast(account.password)
                R.id.Menu_ShowPass -> triggerSnackBarEvent(account.password)
                else -> false
            }
        }, PopupMenu.OnDismissListener {
            view.apply {
                isEnabled = true
            }
        })
}

private fun navigateToSort() {
    if (SystemClock.elapsedRealtime() - _lastClickTime >= 800) {
        _lastClickTime = SystemClock.elapsedRealtime()
        navigateTo(AccountFragmentDirections.actionFragmentAccountToBottomSheetFragmentAccountFilter())
    }
}

private fun navigateToSelectedAccount(account: Account) {
    navigateTo(
        AccountFragmentDirections.actionFragmentAccountToFragmentViewAccount(
            account
        )
    )
}

private fun snackBarAction(message: String) {
    binding.LayoutFragmentAccount.snackbar(message) {
        action(getString(R.string.button_snack_action_close)) { dismiss() }
    }
    viewModel.doneShowingSnackBar()
}

private fun triggerSnackBarEvent(message: String): Boolean {
    viewModel.setSnackBarMessage(message)
    return true
}

private fun copyToClipboardAndToast(message: String): Boolean {
    copyToClipboard(message)
    toast(getString(R.string.message_copy_successful))
    return true
}

片段 B.xml

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

<data>

    <variable
        name="Account"
        type="....Account" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/Layout_Credential_View"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/Account_Logo"
        imageUrl="@{Account.logoUrl}"
        loadingResource="@{@drawable/ic_image_loading}"
        errorResource="@{@drawable/ic_account_placeholder}"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:src="@drawable/ic_account_placeholder" />

    <TextView
        android:id="@+id/Account_Name"
        style="@style/Locky.Text.Title5.Name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="32dp"
        android:textAlignment="center"
        android:text="@{Account.accountName}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/Account_Logo"
        tools:text="This can be a very very very long title toooooo" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RecyclerView_Credentials_Field"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="8dp"
        android:nestedScrollingEnabled="true"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/Account_Name" />

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

片段 B.kt

class ViewAccountFragment : Fragment() {

private var _binding: FragmentViewAccountBinding? = null
private var _viewModel: ViewAccountViewModel? = null
private lateinit var _account: Account

private val binding get() = _binding!!
private val viewModel get() = _viewModel!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    //Fetch the layout and do the binding
    _binding = FragmentViewAccountBinding.inflate(inflater, container, false)
    //Instantiate view model
    _viewModel = ViewModelProvider(this).get(ViewAccountViewModel::class.java)
    binding.lifecycleOwner = this

    //Fetch the account clicked on the previous screen
    _account = ViewAccountFragmentArgs.fromBundle(requireArguments()).parcelcredaccount

    with(_account) {

        //Bind the account to the layout for displaying
        binding.account = this

        //Submit the account details to the recyclerview
        initiateCredentialsFieldList().submitList(viewModel.fieldList(this))
    }

    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    /* Hides the soft keyboard */
    hideSoftKeyboard(binding.root)
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setHasOptionsMenu(true)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    inflater.inflate(R.menu.menu_credentials_actions, menu)
    super.onCreateOptionsMenu(menu, inflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.Action_Duplicate -> {
            /*
            * We set the account id to empty here
            * When the add screen receives it, it wil perceive it as a new account that needs to be
            * added to the database
            */
            navigateToEditScreen(_account.copy(accountID = generateUniqueID()))
            true
        }

        R.id.Action_Edit -> {
            navigateToEditScreen(_account)
            true
        }

        R.id.Action_Delete -> {
            deleteConfirmationDialog(_account.accountName)
            true
        }
        else -> false
    }
}

private fun initiateCredentialsFieldList(): CredentialsViewAdapter {
    val credentialsAdapter =
        CredentialsViewAdapter(
            CopyClickListener { data ->
                copyToClipboardAndToast(data)
            },
            ViewClickListener { data ->
                snackBarAction(data)
            })

    binding.RecyclerViewCredentialsField.apply {
        adapter = credentialsAdapter
        setHasFixedSize(true)
    }

    return credentialsAdapter
}

private fun deleteAndNavigateBackToAccountList() {
    with(_account) {
        viewModel.delete(accountID)
        toast(getString(R.string.message_credentials_deleted, accountName))
        findNavController().popBackStack()
    }
}

导航.xml

<fragment
    android:id="@+id/Fragment_Account"
    android:name="....AccountFragment"
    android:label="Accounts"
    tools:layout="@layout/fragment_account">
    <action
        android:id="@+id/action_Fragment_Account_to_Fragment_View_Account"
        app:destination="@id/Fragment_View_Account" />
    <action
        android:id="@+id/action_Fragment_Account_to_BottomSheet_Fragment_Account_Filter"
        app:destination="@id/BottomSheet_Fragment_Account_Filter" />
</fragment>

MainActivity.xml

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

<androidx.drawerlayout.widget.DrawerLayout
    android:id="@+id/Drawer_Main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.main.main.MainActivity">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/Layout_Coordinator_Main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/Toolbar_Main"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorOnSurface"
            android:outlineAmbientShadowColor="@color/colorShadowColor"
            android:outlineSpotShadowColor="@color/colorShadowColor">

            <TextView
                android:id="@+id/Toolbar_Main_Title"
                style="@style/Locky.Text.Title6.Toolbar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="@string/app_name" />

        </com.google.android.material.appbar.MaterialToolbar>

        <androidx.core.widget.NestedScrollView
            android:id="@+id/Nested_Scroll"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="?attr/actionBarSize"
            android:fillViewport="true">

            <fragment
                android:id="@+id/Navigation_Host"
                android:name="androidx.navigation.fragment.NavHostFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:defaultNavHost="true"
                app:navGraph="@navigation/navigation_drawer_main" />

        </androidx.core.widget.NestedScrollView>

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/FAB_Search"
            style="@style/Locky.FloatingActionButton.Mini"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:layout_marginBottom="85dp"
            app:layout_anchor="@id/FAB_Add"
            app:layout_anchorGravity="top|center_horizontal"
            app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
            app:srcCompat="@drawable/ic_search" />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/FAB_Add"
            style="@style/Locky.FloatingActionButton.Normal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
            app:srcCompat="@drawable/ic_add" />

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/Navigation_View"
        style="@style/Locky.Widget.Custom.NavigationView"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:clipToPadding="false"
        android:paddingStart="0dp"
        android:paddingEnd="16dp"
        app:headerLayout="@layout/drawer_header"
        app:itemTextAppearance="@style/Locky.Text.Body.Drawer"
        app:menu="@menu/menu_drawer_main" />

</androidx.drawerlayout.widget.DrawerLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {

private lateinit var _binding: ActivityMainBinding
private lateinit var _viewModel: MainActivityViewModel
private lateinit var _appBarConfiguration: AppBarConfiguration

//Fragments that can navigate with the drawer
private val _navigationFragments = setOf(
    R.id.Fragment_Card,
    R.id.Fragment_Account,
    R.id.Fragment_Device
)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    _binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    _viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

    _binding.lifecycleOwner = this

    //Set the support action bar to the toolbar
    setSupportActionBar(_binding.ToolbarMain)
    //Remove the default actionbar title
    supportActionBar?.setDisplayShowTitleEnabled(false)

    /* Updates the app settings*/
    updateAppSettings()

    //Setup the navigation components
    navigationUISetup()

    //Load FABs
    listenerForAddFab()

    listenerForSearchFab()

    //Scroll changes to adjust toolbar elevation accordingly
    setUpNestedScrollChangeListener()
}

override fun onOptionsItemSelected(item: MenuItem) =
    item.onNavDestinationSelected(findNavController(R.id.Navigation_Host)) || super.onOptionsItemSelected(
        item
    )

override fun onSupportNavigateUp() =
    findNavController(R.id.Navigation_Host).navigateUp(_appBarConfiguration)

override fun finish() {
    super.finish()

    ActivityNavigator.applyPopAnimationsToPendingTransition(this)
}

private fun navigationUISetup() {
    //Fetch the Nav Controller
    val navController = findNavController(R.id.Navigation_Host)
    //Setup the App Bar Configuration
    _appBarConfiguration = AppBarConfiguration(_navigationFragments, _binding.DrawerMain)

    //Use Navigation UI to setup the app bar config and navigation view
    NavigationUI.setupActionBarWithNavController(this, navController, _appBarConfiguration)
    NavigationUI.setupWithNavController(_binding.NavigationView, navController)

    //Set the mini FABs with navigation to navigate to fragments accordingly.
    Navigation.setViewNavController(_binding.FABAdd, navController)
    Navigation.setViewNavController(_binding.FABSearch, navController)

    //Add on change destination listener to navigation controller to handle fab visibility
    navigationDestinationChangeListener_FAB(navController)

    //Add on change destination listener to navigation controller to handle screen title visibility
    navigationDestinationChangeListener_ToolbarTitle(navController)
}

private fun setUpNestedScrollChangeListener() =
    _binding.NestedScroll.setOnScrollChangeListener { _, _, scrollY, _, _ ->
        if (scrollY > 0) {
            _binding.ToolbarMain.elevation = 12F
        } else {
            _binding.ToolbarMain.elevation = 0F
        }
    }

private fun navigationDestinationChangeListener_ToolbarTitle(navController: NavController) {
    navController.addOnDestinationChangedListener { _, nd, _ ->
        when (nd.id) {
            R.id.Fragment_Account -> updateToolbar(getString(R.string.text_title_screen_accounts))
            R.id.Fragment_Card -> updateToolbar(getString(R.string.text_title_screen_cards))
            R.id.Fragment_Device -> updateToolbar(getString(R.string.text_title_screen_devices))
            R.id.Fragment_Settings -> updateToolbar(getString(R.string.text_title_screen_settings))
            R.id.Fragment_Profile -> updateToolbar(getString(R.string.text_title_screen_profile))
            R.id.Fragment_About -> updateToolbar(getString(R.string.text_title_screen_about))
            R.id.Fragment_Donate -> updateToolbar(getString(R.string.text_title_screen_donate))
            else -> {
                //Show the toolbar
                updateToolbar(null)
            }
        }
    }
}

private fun navigationDestinationChangeListener_FAB(navController: NavController) {
    navController.addOnDestinationChangedListener { nc, nd, _ ->
        when (nd.id) {
            nc.graph.startDestination,
            R.id.Fragment_Card,
            R.id.Fragment_Device -> {
                _binding.DrawerMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)

                //Show all the FABs
                showFABs()
            }
            else -> {
                _binding.DrawerMain.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)

                //Hide all the FABs
                hideFABs()
            }
        }
    }
}

private fun getFadeNavOptions(): NavOptions? {
    return NavOptions.Builder()
        .setEnterAnim(R.anim.anim_fade_in)
        .setExitAnim(R.anim.anim_fade_out)
        .build()
}

private fun hideFABs() {
    _binding.FABSearch.hide()
    _binding.FABAdd.hide()
}

private fun showFABs() {
    _binding.FABSearch.show()
    _binding.FABAdd.show()

    showFABFromSlidingBehavior(_binding.FABSearch, _binding.FABSearch.isVisible)
    showFABFromSlidingBehavior(_binding.FABAdd, _binding.FABAdd.isVisible)
}

private fun showFABFromSlidingBehavior(fab: FloatingActionButton, isVisible: Boolean) {
    val layoutParams: ViewGroup.LayoutParams = fab.layoutParams
    if (layoutParams is CoordinatorLayout.LayoutParams) {
        val behavior = layoutParams.behavior
        if (behavior is HideBottomViewOnScrollBehavior) {
            if (isVisible) {
                behavior.slideUp(fab)
            } else {
                behavior.slideDown(fab)
            }
        }
    }
}

我附上了一个 gif 来演示这里的问题:

滚动问题

在 GIF 中,我从 3 个片段导航(片段 A > 片段 B > 片段 C)我在这里做错了什么吗?

4

1 回答 1

3

layoutmanager当您填充不同的片段时,这两个片段都相同;同样layoutmanager被称为。然后它会尝试恢复相同的位置,并考虑其相同的回收视图,当您考虑它时,这是一种功能。

来自文档:

RecyclerView当准备好根据以前的 恢复状态时调用RecyclerView。请注意,这可能会在实际布局之后发生,具体取决于 Adapter 更喜欢恢复状态的方式。看 RecyclerView.Adapter.getStateRestorationPolicy()

这意味着我们需要的不是恢复可以通过传递 PREVENT到的状态RecyclerView.Adapter.StateRestorationPolicy

解决方案1:在您的片段B适配器中只需调用 adapter.stateRestorationPolicy = PREVENT

解决方案2:为片段B创建一个不同layoutmanager的,以防你想恢复其他东西的位置。

编辑 :: QA :: 我如何将视图设置在顶部(靠近状态栏):

好吧,由于您在 a 中填充您的片段,因此当您导航到所需的片段时,NestedScrollView您应该调用 它,可能是通过在您的 内部等待 aNestedScrollView.scrollTo(0, 0);callbackaddOnDestinationChangedListenerMainActivity.kt

于 2020-06-09T11:50:24.480 回答