Android 如何复制YouTube';s应用程序导航逻辑
我想在我的应用程序中实现导航逻辑,就像在Youtube应用程序中一样。(BottomNavigationView+片段管理)。我想要这个,因为这些片段很重,所以我希望它们被延迟初始化,然后存储在backbackback中,我觉得YouTube就是这样做的。我已经实现了BottomNagivationView,但在片段管理方面存在问题 我的代码:Android 如何复制YouTube';s应用程序导航逻辑,android,android-fragments,fragment-backstack,Android,Android Fragments,Fragment Backstack,我想在我的应用程序中实现导航逻辑,就像在Youtube应用程序中一样。(BottomNavigationView+片段管理)。我想要这个,因为这些片段很重,所以我希望它们被延迟初始化,然后存储在backbackback中,我觉得YouTube就是这样做的。我已经实现了BottomNagivationView,但在片段管理方面存在问题 我的代码: bottomNavigationView.setOnTabSelectedListener { position, _ -> setFr
bottomNavigationView.setOnTabSelectedListener { position, _ ->
setFragment(OnlinePageFragment.Page.values()[position])
}
其中页面是枚举
enum class Page(index: Int, val klass: Class<*>) {
ONE(0, OnePageFragment::class.java),
TWO(1, TwoPageFragment::class.java),
THREE(2, ThreePageFragment::class.java)
}
它正在工作,但不如YouTube应用程序好。YouTube应用程序有一些神奇的行为,即每个片段只保留一个事务,而我的应用程序允许创建“无限”事务回溯。你知道它在YouTube应用程序中是如何工作的吗?我想最好的方法是使用
ViewPager
存储根片段。导航栏将更改ViewPager
的页面
根片段将内容片段存储在它们的childFragmentManager
中,并实现内容片段之间的导航逻辑
此外,您还需要实现从活动到根片段的委托backpress事件逻辑,以便在其backbackback中执行导航
UPD#1确保根片段未在ViewPager中销毁,请使用 UPD#2
如果您不想使用ViewPager,您可以使用其中的代码来管理根片段。如果不使用ViewPager,您可以管理它。 我已经实现了,请检查这个 如果有任何问题,请更新 这是一个分配片段的方法
public void addFragment(FragmentManager fragmentManager,
Fragment fragment,
int containerId,boolean isFromHome){
fragmentManager.popBackStack(null,FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
if(isFromHome){
fragmentTransaction.replace(containerId,fragment);
}else{
fragmentTransaction.add(new HomeFragment(),"Home");
fragmentTransaction.addToBackStack("Home");
}
fragmentTransaction.replace(containerId,fragment).commit();
}
这是您的导航项侦听器
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
addFragment(getSupportFragmentManager(), new HomeFragment(), R.id.frame, true);
}else{
getSupportFragmentManager().popBackStack();
}
return true;
case R.id.navigation_dashboard:
addFragment(getSupportFragmentManager(),new DashboardFragment(),R.id.frame,false);
return true;
case R.id.navigation_notifications:
addFragment(getSupportFragmentManager(),new NotificationFragment(),R.id.frame,false);
return true;
case R.id.navigation_setting:
addFragment(getSupportFragmentManager(),new SettingFragment(),R.id.frame,false);
return true;
}
return false;
}
};
反压法
@Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()>0){
navigation.setSelectedItemId(R.id.navigation_home);
}else {
super.onBackPressed();
}
}
因为按预期显示了片段,但有一些bug,每次更改片段时都会对HomeFragment调用onCreateView两次。另外,每次更改页面时,更改页面都会实例化新片段。因此,我使用并修改了我的
setPage
,它工作得很好
以下是如何:
private void setPage(Page page) {
FragmentManager fragmentManager = getSupportFragmentManager();
String tag = page.name();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// detach everything
for (Fragment fragment : fragmentManager.getFragments()) {
transaction.detach(fragment);
}
// Retrieve fragment instance, if it was already created
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment == null) { // If not, crate new instance and add it
try {
fragment = (Fragment) page.clazz.newInstance();
transaction.add(R.id.frame, fragment, tag);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
} else { // otherwise just attach it
transaction.attach(fragment);
}
transaction.commit();
}
OnBackpress实现
@Override
public void onBackPressed() {
if (!getSupportFragmentManager().findFragmentByTag(Page.HOME.name()).isDetached()) {
super.onBackPressed();
} else {
navigation.setSelectedItemId(R.id.navigation_home);
}
}
ViewPager是我当前的实现,我想更改它,因为它太重,无法一次加载3个片段。@StachuBarański如果它太重,无法一开始加载3个片段,则只加载第一个片段,如果用户滑动以查看它们,则其他片段将填充数据。@hardartcore我无法这样做,因为ViewPager需要加载所有3个片段,所以它们在刷卡时是可见的。@StachuBarański您可以这样做,只要听
setUserVisibleHint(布尔b)
,当b为真时触发内容加载(并且它没有加载或加载,或者在其他一些条件下)好的,很高兴知道:)无论如何,我选择了管理根片段,它工作得很好(Fragment只创建一次,onCreateView只调用一次,并且所有内容都是惰性初始化的)。请参阅接受的答案。我接受了此答案,因为它按预期显示了片段。但存在问题。每次切换Fragment HomeFragment时,都会创建两次。
@Override
public void onBackPressed() {
if (!getSupportFragmentManager().findFragmentByTag(Page.HOME.name()).isDetached()) {
super.onBackPressed();
} else {
navigation.setSelectedItemId(R.id.navigation_home);
}
}