You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何点击Preference控件时AppBarLayout的elevation会改变?

问题:点击Preference时AppBarLayout出现闪烁

我仅在Android Studio的Basic Views Activity模板中添加了一个PreferenceScreen,点击Preference时AppBarLayout会出现闪烁现象,搭配其他可点击元素时不会出现。通过快照检查发现,原因是点击Preference时elevation发生变化:向下滚动状态下,点击Preference时elevation变为0.0,再次选中时又会快速改变。

AppBarLayout闪烁现象

相关代码

activity_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.kt

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>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var binding: ActivityMainBinding
    private var isMenuVisible = true // 默认显示菜单

    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, _ ->
            // 根据当前页面判断是否显示菜单
            val shouldMenuBeVisible = destination.id != R.id.SettingsFragment
            if (shouldMenuBeVisible != isMenuVisible) {
                isMenuVisible = shouldMenuBeVisible
                invalidateOptionsMenu() // 触发菜单更新
            }
        }

        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 {
        // 仅在需要时加载菜单
        if (isMenuVisible) {
            menuInflater.inflate(R.menu.menu_main, menu)
        }
        return true
    }

    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        super.onPrepareOptionsMenu(menu)
        // 清空现有菜单并重新加载
        menu.clear()
        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()
    }
}

解决方案

这个问题是Preference点击事件触发了系统窗口过渡动画,导致AppBarLayout的elevation被意外修改。以下是几种可行的解决方法:

方法1:固定AppBarLayout的elevation并禁用状态动画

在AppBarLayout的XML属性中添加以下配置,强制固定elevation值,并禁用状态变化时的动画:

<com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    app:elevation="4dp"
    android:stateListAnimator="@null">

方法2:自定义Preference点击逻辑

在SettingsFragment中为所有Preference设置自定义点击监听器,消费掉默认事件,避免触发影响AppBar的动画:

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
    setPreferencesFromResource(R.xml.preferences, rootKey)
    preferenceScreen.forEach { preference ->
        preference.setOnPreferenceClickListener {
            // 处理开关逻辑(如果是SwitchPreferenceCompat)
            if (it is SwitchPreferenceCompat) {
                it.isChecked = !it.isChecked
            }
            true // 返回true表示消费事件,阻止默认行为
        }
    }
}

方法3:使用自定义Preference主题

在styles.xml中定义一个禁用焦点动画的Preference主题:

<style name="AppPreferenceTheme" parent="@style/PreferenceThemeOverlay">
    <item name="android:selectableItemBackground">@null</item>
    <item name="android:stateListAnimator">@null</item>
</style>

然后在SettingsFragment中应用该主题:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val view = super.onCreateView(inflater, container, savedInstanceState)
    view?.setTheme(R.style.AppPreferenceTheme)
    return view
}

内容的提问来源于stack exchange,提问作者Brendan B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:00:22