导航抽屉的片段管理
Posted
技术标签:
【中文标题】导航抽屉的片段管理【英文标题】:Navigation Drawer's Fragment Management 【发布时间】:2018-12-21 19:56:08 【问题描述】:
我正在开发一个应用程序,我只使用 1 个主要活动和多个片段,包括 ViewPager
、自定义视频/图片库、全屏片段(没有工具栏或底部导航按钮)。我不确定这是否是好的做法,但我面临的问题很少。
上图是实际的应用层次结构。关注我面临的问题。
-
当按下返回按钮或通过单击按钮或某些链接前进时,工具栏不会更改片段的标题。
如果我通过
using: getSupportActionBar().setDisplayHomeAsUpEnabled(true);
更改为后退箭头,导航汉堡会继续显示,然后后退箭头会打开抽屉,但不会返回到最后一个片段。
按下后退按钮或直接跳转到某个片段时片段状态丢失。
使用单个 Activity
完成 Fragment
内的所有任务是否是一种好习惯。
我也在使用单个工具栏整个应用程序。 工具栏.xml
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@color/primary"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
android:fitsSystemWindows="true"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<LinearLayout
android:layout_
android:layout_
android:id="@+id/toolbar_connections"
android:visibility="visible"
android:orientation="horizontal">
<ImageView
android:layout_
android:layout_
android:id="@+id/appLogo"
android:layout_gravity="center_vertical" />
<TextView
android:layout_
android:layout_
android:layout_gravity="center_vertical|center_horizontal"
android:textSize="22sp"
android:id="@+id/activityTitle"
android:textColor="@color/primary_text"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/toolbar_chat"
android:layout_
android:layout_
android:visibility="gone"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_
android:layout_
android:layout_gravity="center_vertical"
android:layout_marginRight="5dp"
android:src="@drawable/baby"
android:id="@+id/User_Image_Toolbar"/>
<LinearLayout
android:layout_
android:layout_
android:orientation="vertical">
<TextView
android:layout_
android:layout_
android:id="@+id/User_Name_Toolbar"
android:textSize="17sp"
android:textStyle="bold"
android:layout_marginBottom="5dp"
android:text="My Name"
/>
<TextView
android:layout_
android:layout_
android:text="Online"
android:textStyle="italic"
android:id="@+id/User_Online_Status_Toolbar"
android:layout_marginBottom="5dp"
android:layout_below="@+id/User_Name_Toolbar" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
导航抽屉(所有Fragment的父级的单个Activity)
public class Navigation_Drawer extends AppCompatActivity implements UserData
Toolbar toolbar;
DrawerLayout drawerLayout;
NavigationView navigationView;
String navTitles[];
TypedArray navIcons;
RecyclerView.Adapter recyclerViewAdapter;
ActionBarDrawerToggle drawerToggle;
public static final String TAG = "###Navigation Drawer###";
boolean nextScreen;
//Header
ImageView headerImage,headerUserImage;
TextView userName,userViews;
Context context = this;
//Setting Tabs
ViewPager viewPager;
TabAdapter tabAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.navigation_drawer);
//Initialise Views
drawerLayout = findViewById(R.id.Navigation_Drawer_Main);
navigationView = findViewById(R.id.nvView);
setupToolbar();
navigationView.setItemIconTintList(null);
setupDrawerContent(navigationView);
settingHeaderItems();
drawerToggle = setupDrawerToggle();
getSupportActionBar().setHomeButtonEnabled(true);
drawerLayout.addDrawerListener(drawerToggle);
viewPager = findViewById(R.id.Navigation_Drawer_ViewPager);
tabAdapter = new TabAdapter(getFragmentManager(), this, false);
viewPager.setAdapter(tabAdapter);
public void setupToolbar()
toolbar = findViewById(R.id.Navigation_Drawer_toolbar);
setSupportActionBar(toolbar);
private ActionBarDrawerToggle setupDrawerToggle()
// NOTE: Make sure you pass in a valid toolbar reference. ActionBarDrawToggle() does not require it
// and will not render the hamburger icon without it.
//return new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
return new ActionBarDrawerToggle(this, drawerLayout,toolbar, R.string.drawer_open, R.string.drawer_close);
@Override
public boolean onCreateOptionsMenu(Menu menu)
MenuInflater inflater = getMenuInflater();
// inflater.inflate(R.menu.main_menu, menu);
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
//Handle Item Selection
return super.onOptionsItemSelected(item);
private void setupDrawerContent(NavigationView navigationView)
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener()
@Override
public boolean onNavigationItemSelected(MenuItem menuItem)
selectDrawerItem(menuItem);
return true;
);
public void ChangeFragment_ViewPager(int position, boolean outside)
if (outside)
Log.d(TAG, "Change Fragment Calling From Outside");
tabAdapter = new TabAdapter(getFragmentManager(), this, false);
viewPager.setAdapter(tabAdapter);
viewPager.setCurrentItem(position);
@Override
public void onBackPressed()
super.onBackPressed();
showSystemUI();
Log.d(TAG, "On Back Pressed");
public void showSystemUI()
if (getWindow() != null)
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getSupportActionBar().show();
else
return;
public void selectDrawerItem(MenuItem menuItem)
// Create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
switch (menuItem.getItemId())
case R.id.HeaderImageView:
fragment = new EditProfile();
break;
case R.id.home_Fragment:
Log.d(TAG,"Home Fragment Pressed ");
getFragmentManager().popBackStack(null, android.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
ChangeFragment_ViewPager(0,false);
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.ppl_Fragment:
Log.d(TAG,"PPL Fragment Pressed ");
ChangeFragment_ViewPager(1,false);
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.message_Fragment:
Log.d(TAG,"Message Fragment Pressed ");
fragment = new Messages_Fragment();
break;
case R.id.addMedia_Fragment:
Log.d(TAG,"Add Media Fragment Pressed ");
fragment = new UserProfile_Photos();
break;
case R.id.invite_Fragment:
Log.d(TAG,"Invite Fragment Pressed ");
//fragmentClass = fragment_1.class;
onInviteClicked();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.setting_Fragment:
Log.d(TAG,"Setting Fragment Pressed ");
fragment = new Setting_NavigationDrawer();
break;
case R.id.help_Fragment:
Log.d(TAG,"Help Fragment Pressed ");
//fragmentClass = fragment_1.class;
fragment=new FullScreen_WebView();
Bundle urlToSend=new Bundle();
urlToSend.putString("webViewURL","http://boysjoys.com/test/Android/Data/help.php");
//urlToSend.putString("webViewURL",chat_wrapper.getGoogleSearch().get(2));
fragment.setArguments(urlToSend);
FragmentTransaction transaction=((Activity)context).getFragmentManager().beginTransaction();
//fragmentTrasaction.replace(R.id.Chat_Screen_Main_Layout,gallery);
//transaction.replace(R.id.Chat_Screen_Main_Layout,fullScreen_webView);
transaction.replace(R.id.Navigation_Main_Layout,fragment);
transaction.addToBackStack(null);
transaction.commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.signOut_Fragment:
new CheckLoginStatus(this, 0).execute();
new Send_Session_Logout(this).execute();
drawerLayout.closeDrawers();
return;
FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.Navigation_Main_Layout, fragment);
fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
private void settingHeaderItems()
View HeaderLayout = navigationView.inflateHeaderView(R.layout.navigation_header_image);
//Main Screen Tabs With VIew Pager
headerImage = HeaderLayout.findViewById(R.id.HeaderImageView);
headerImage.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.Navigation_Main_Layout, new EditProfile());
fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
drawerLayout.closeDrawers();
);
headerUserImage = HeaderLayout.findViewById(R.id.HeaderProfilePicture);
userName = HeaderLayout.findViewById(R.id.myImageViewText);
userViews = HeaderLayout.findViewById(R.id.profileViews);
if (Session.getUserCover().equals("Invalid Image"))
headerImage.setBackgroundResource(R.drawable.cam_icon);
else
Log.d(TAG,"Path Of Cover Photo "+Session.getUserCover());
Bitmap coverPhoto= BitmapFactory.decodeFile(Session.getUserCover());
headerImage.setImageBitmap(coverPhoto);
// Glide.with(context).load(Session.getUserCover()).apply(new RequestOptions().skipMemoryCache(true).onlyRetrieveFromCache(false).diskCacheStrategy(DiskCacheStrategy.NONE)).into(holder.HeaderImage);
Bitmap bitmap = BitmapFactory.decodeFile(Session.getUserImage());
userName.setText(Session.getUserFname()+" "+Session.getUserLname());
headerUserImage.setImageBitmap(bitmap);
if (Session.getProfileCounter().equals("0"))
userViews.setText("No Profile VIsits");
else
userViews.setText("Profile views: "+ Session.getProfileCounter());
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState)
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
@Override
public void onConfigurationChanged(Configuration newConfig)
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
我很累解决这个问题,经过几个月的谷歌搜索和***,我仍然陷入同样的问题。
第 1 点的问题示例:- 当导航抽屉首先加载时一切看起来都不错,视图寻呼机会根据片段更改标题。然后如果我点击导航抽屉的菜单,它也会打开另一个片段(例如:最近的消息)。然后标题更改成功,但是当我按下返回按钮或尝试按下调用 viewpager 的主页按钮时,标题保持与以前相同,即最近的消息。
像这样在每个片段中设置标题。
toolbar = (Toolbar) getActivity().findViewById(R.id.Navigation_Drawer_toolbar);
ImageView appLogo = toolbar.findViewById(R.id.appLogo);
TextView fragmentTitle = toolbar.findViewById(R.id.activityTitle);
appLogo.setImageResource(DrawableImage);
fragmentTitle.setText(Title);
【问题讨论】:
尝试与 popbackstack 一起使用:***.com/questions/25932761/fragment-popbackstack @urvijoshi 我试过popbackstack
但popbackstack
它并没有解决我面临的问题
那么当你带着片段返回时,你的第一个问题是设置标题?
@Man 是的,当我按返回按钮返回时,即使返回多次,标题仍然保持不变。我也有其他问题,请也看一下。谢谢
我对你的第三个问题没听懂?按下后退按钮或直接跳转到某个片段时片段状态丢失。?
【参考方案1】:
如果应用程序必须使用应出现在所有视图中的导航抽屉,则应使用片段。这不是一个坏习惯。
-
工具栏不改变片段的标题,当按下返回按钮或
点击按钮或链接继续前进。
在 Base Activity 中创建一个方法
public void setFragmentTitle(String title)
if(!TextUtils.isEmpty(title))
mTitleText.setText(title);
从onCreateView
中的各个片段访问此方法
((LandingActivity) getActivity()).setFragmentTitle(getActivity().getString(R.string.fragment_title));
如果我使用以下方法更改为后退箭头,导航汉堡会继续显示:getSupportActionBar().setDisplayHomeAsUpEnabled(true);然后返回箭头打开抽屉,但不返回到最后一个片段。
点击android.R.id.home
使用onOptionItemSelected
,弹出当前Fragment
按下后退按钮或直接跳转到某个片段时片段状态丢失
您必须提及需要保留并重新填充的值。
public class ActivityABC....
private String mFName;
private TableSelectFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState != null)
mFragment=(TableSelectFragment)fm.getFragment(savedInstanceState,"TABLE_FRAGMENT");
mFName = savedInstanceState.getString("FNAMETAG");
else
mFragment = new TableSelectFragment();
fm.beginTransaction().add(R.id.content_frame,mFragment,"TABLE_FRAGMENT").commit();
@Override
protected void onSaveInstanceState(Bundle outState)
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState,"TABLE_FRAGMENT",mFragment);
在你的片段中
TableSelectFragment
....
private String mFName;
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setRetainInstance(true);
@Override
public void onSaveInstanceState(@NonNull Bundle outState)
outState.putString("FNAMETAG", mFName);
super.onSaveInstanceState(outState);
编辑 1:对于片段标题在 BackButton 按下时未更新
在将 Fragment
添加到 backstack 时,请执行以下操作。
在您的父活动中
FragmentManager fragMan = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMan.beginTransaction();
LandingFrag landingFrag = LandingFrag.newInstance();
fragTrans.replace(R.id.landing_view, landingFrag,"LandingFrag");
fragTrans.addToBackStack(null);
fragTrans.commit();
landingFrag.setUserVisibleHint(true);
现在覆盖父 Activity 中的 onBackPressed
@Override
public void onBackPressed()
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START);
else
.. POP Fragment Backstack here
Fragment fragment = getActiveFragment();
if(fragment instanceof LandingFrag)
LandingFrag landingFrag = (LandingFrag)fragment;
landingFrag.setUserVisibleHint(true);
public Fragment getActiveFragment()
if (getSupportFragmentManager().getBackStackEntryCount() == 0)
return null;
Fragment fragment=null;
int trackBackValue = 1;//INCREASE OR DECREASE ACCORDING TO YOUR BACK STACK
try
fragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - trackBackValue);
catch (Exception e)
return fragment;
现在在 LandingFrag 中
public class LandingFrag...
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setUserVisibleHint(false);
.....
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState)
super.onViewStateRestored(savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
................
((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser)
try
((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
catch (Exception e)
e.printStackTrace();
【讨论】:
我尝试通过主要活动设置标题,如您所说,但出现了同样的问题,工具栏上出现了所需的标题,但是当我按下返回按钮时它保持不变。当我按下返回按钮时,它不会更新工具栏标题。 我也更新了逻辑。看看这个。编码快乐! 您好,抱歉回复晚了。我已经实施了您的解决方案,但几乎没有问题。onBackPressed
中的 getFragments
方法要求 API 26 表示奥利奥。那么对于早期的 API/平台,如 JB 或 lolipop,是否有任何解决方案。【参考方案2】:
在 Fragment 中完成所有任务是否是一种好习惯 单一活动。
与抽屉式导航、选项卡或底部导航一起使用时,使用片段是一种很好的做法。 除此之外,对于具有不同数据的可重用 UI,Fragment 更受青睐。
您正在使用 Single Activity 执行片段内的所有任务,因为您使用的是导航绘图和选项卡,所以这是一个很好的做法,我想说。
工具栏不会改变片段的标题,当按下返回按钮或 点击按钮或链接继续前进。
每当您添加/替换新片段时,您都需要手动设置片段的标题或 在后按(返回堆栈更改)时,仅通过 Fragment 或使用 docs 中提到的 OnBackStackChangedListener。
您只是在单击导航项时设置它们,而不是在单击按钮或某些链接时
如果我更改为后退箭头,导航汉堡会继续显示 使用:getSupportActionBar().setDisplayHomeAsUpEnabled(true);然后 后退箭头打开抽屉,但不返回到最后一个片段。
您也需要手动处理。在点击 android.R.id.home 项目时使用 onOptionItemSelected。 就像从堆栈中弹出片段一样。
您的标题持久化的原因是从 Activity 设置标题。
即使用这个setTitle(menuItem.getTitle());
而不是通过 Fragment 设置它们,或者如果你是通过从selectDrawerItem
方法中删除 Fragment 来设置它们。
同样在selectDrawerItem
方法的末尾,您使用的是fragmentTransaction.add
,而不是使用fragmentTransaction.replace
【讨论】:
对不起,我没有提到我在每个片段中设置标题。请检查更新的答案 你还需要在用片段按下时管理标题 这只是将标题变成片段的解决方案吗? 没关系,如果你有更多动作要从片段传递给活动,你可以使用接口作为回调 你能解释一下你的解决方案吗?以上是关于导航抽屉的片段管理的主要内容,如果未能解决你的问题,请参考以下文章