You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android Studio中解决重复点击底部导航栏Fragment闪烁问题

解决重复点击底部导航栏Fragment闪烁的问题

我之前也碰到过这个情况——用默认的底部导航活动模板时,重复点击同一个菜单项,Fragment会出现明显的闪烁,本质原因是NavigationUI.setupWithNavController()在重复导航时会默认重建Fragment实例,导致onCreateView()重新执行,布局被重新加载。

下面分享两种亲测有效的解决办法:

方案一:拦截底部导航的重复点击事件

直接替换默认的导航绑定逻辑,自定义BottomNavigationView的点击监听,判断当前选中的item和点击的是否一致,如果是同一个就跳过导航操作:

public class MainActivity extends AppCompatActivity {
    private NavController navController;
    private BottomNavigationView navView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        navView = findViewById(R.id.nav_view);
        navController = Navigation.findNavController(this, R.id.nav_host_fragment);

        // 自定义底部导航选中事件
        navView.setOnItemSelectedListener(item -> {
            // 点击的是当前已选中的item,直接返回,不触发导航
            if (navView.getSelectedItemId() == item.getItemId()) {
                return true;
            }
            // 正常导航到对应目的地
            NavigationUI.onNavDestinationSelected(item, navController);
            return true;
        });

        // 保持ActionBar和导航控制器的关联
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
                .build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
    }
}

这种方式简单直接,从源头阻止了重复导航的触发,自然就不会有Fragment重建和闪烁的问题。

方案二:给Fragment设置singleTop启动模式(更优雅)

另一种更符合Navigation组件设计的方式是在导航图中给每个Fragment目的地设置launchMode="singleTop",这样当导航到已经处于返回栈顶部的Fragment时,会复用现有实例而不是重建:

打开你的res/navigation/nav_graph.xml,给每个fragment标签添加这个属性:

<fragment
    android:id="@+id/navigation_home"
    android:name="com.example.yourpackage.HomeFragment"
    android:label="@string/title_home"
    tools:layout="@layout/fragment_home"
    app:launchMode="singleTop"/> <!-- 添加这一行 -->

<fragment
    android:id="@+id/navigation_dashboard"
    android:name="com.example.yourpackage.DashboardFragment"
    android:label="@string/title_dashboard"
    tools:layout="@layout/fragment_dashboard"
    app:launchMode="singleTop"/>

<fragment
    android:id="@+id/navigation_notifications"
    android:name="com.example.yourpackage.NotificationsFragment"
    android:label="@string/title_notifications"
    tools:layout="@layout/fragment_notifications"
    app:launchMode="singleTop"/>

设置singleTop后,重复点击菜单项时不会重建Fragment,还会触发Fragment的onNewIntent()方法,如果你需要在重复点击时做一些额外操作(比如滚动到页面顶部),可以在Fragment中重写这个方法:

public class HomeFragment extends Fragment {
    private HomeViewModel homeViewModel;
    // 假设你的页面有滚动控件,比如RecyclerView或ScrollView
    private ScrollView homeScrollView;

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
        View root = inflater.inflate(R.layout.fragment_home, container, false);
        final TextView textView = root.findViewById(R.id.text_home);
        homeScrollView = root.findViewById(R.id.scroll_home); // 替换成你自己的滚动控件ID
        
        homeViewModel.getText().observe(getViewLifecycleOwner(), s -> textView.setText(s));
        return root;
    }

    @Override
    public void onNewIntent(@Nullable Intent intent) {
        super.onNewIntent(intent);
        // 重复点击时滚动到页面顶部
        if (homeScrollView != null) {
            homeScrollView.fullScroll(View.FOCUS_UP);
        }
    }
}

这样既解决了闪烁问题,又能满足用户重复点击时的交互预期,体验会更好。


内容的提问来源于stack exchange,提问作者Imam Faried

火山引擎 最新活动