Brendan B
Brendan B

Reputation: 27

Why is AppBarLayout's elevation changing when a preference is selected?

I only added a PreferenceScreen to Android Studio's Basic Views Activity template, and I don't know why the AppBarLayout flashes when a preference is clicked

enter image description here

This is not the behavior of any other clickable element with the AppBarLayout. Upon inspection of snapshots, it seems this is because there is an elevation change when the preference is clicked. While scrolled down, the elevation goes to 0.0 when a preference is clicked, and then rapidly changes when selected again.

activity_main.xml with the app bar and includes content_main.xml:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize" />

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

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_marginEnd="@dimen/fab_margin"
        android:layout_marginBottom="16dp"
        app:srcCompat="@android:drawable/ic_dialog_email"
        android:contentDescription="@string/fab_description" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

content_main.xml:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <fragment
        android:id="@+id/nav_host_fragment_content_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

SettingsFragment class:

class SettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences, rootKey)
    }
}

preferences.xml:

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

    <SwitchPreferenceCompat
        android:key="switch_preference_1"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_2"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_3"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_4"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_5"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_6"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_7"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_8"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_9"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_10"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_11"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_12"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_13"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_14"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />

    <SwitchPreferenceCompat
        android:key="switch_preference_15"
        android:title="Switch Preference"
        android:summary="An example that uses a switch" />
</PreferenceScreen>

And finally, my MainActivity class:

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var binding: ActivityMainBinding
    private var isMenuVisible = true // Default value true to show the menu initially

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

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.toolbar)

        val navController = findNavController(R.id.nav_host_fragment_content_main)
        appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController, appBarConfiguration)

        navController.addOnDestinationChangedListener { _, destination, _ ->
            // Determine if the menu should be visible based on the current destination
            val shouldMenuBeVisible = destination.id != R.id.SettingsFragment
            if (shouldMenuBeVisible != isMenuVisible) {
                // Only update the menu if the visibility has changed
                isMenuVisible = shouldMenuBeVisible
                invalidateOptionsMenu() // Trigger a call to onPrepareOptionsMenu
            }
        }

        binding.fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                .setAction("Action", null).show()
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        if (isMenuVisible) {
            menuInflater.inflate(R.menu.menu_main, menu)
        }
        return true
    }

    // For dynamically adjusting the contents of the options menu based on the current state or
    // configuration of the application (whether the current version of the application is taking
    // advantage of this function or not).
    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        super.onPrepareOptionsMenu(menu)
        // Clear the existing menu to ensure it reflects the current state
        menu.clear()
        // Conditionally inflate the menu based on the current state
        if (isMenuVisible) {
            menuInflater.inflate(R.menu.menu_main, menu)
        }
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.action_settings -> {
                findNavController(R.id.nav_host_fragment_content_main)
                    .navigate(R.id.action_global_settingsFragment)
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment_content_main)
        return navController.navigateUp(appBarConfiguration)
                || super.onSupportNavigateUp()
    }
}

Upvotes: 1

Views: 31

Answers (0)

Related Questions