[英]Navigation Drawer's Fragment Management
I am developing an app where i am using only 1 Main Activity and Multiple fragment, Including
ViewPager
, Custom video/Image Gallery, Fullscreen Fragment(Without toolbar or bottom navigation button). 我正在开发一个应用程序,我只使用1个主要活动和多个片段,包括
ViewPager
,自定义视频/图像库,全屏片段(没有工具栏或底部导航按钮)。 I am not sure is it good practice or not but i am facing few issues cause of this. 我不确定这是好的做法,但我面临的问题很少。
Image above is actual App hierarchy. 上图是实际的App层次结构。 Following the issue i am facing.
在我面临的问题之后。
using: getSupportActionBar().setDisplayHomeAsUpEnabled(true);
using: getSupportActionBar().setDisplayHomeAsUpEnabled(true);
then back arrow opens drawers but not going back to last fragment. Fragment
with Single Activity
. Activity
在Fragment
执行所有任务是否是一种好习惯。 I am also using single Toolbar whole app. 我也在使用单个工具栏整个应用程序。 Toolbar.xml
Toolbar.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_width="match_parent"
android:layout_height="?attr/actionBarSize"
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_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/toolbar_connections"
android:visibility="visible"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="match_parent"
android:id="@+id/appLogo"
android:layout_gravity="center_vertical" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="5dp"
android:src="@drawable/baby"
android:id="@+id/User_Image_Toolbar"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/User_Name_Toolbar"
android:textSize="17sp"
android:textStyle="bold"
android:layout_marginBottom="5dp"
android:text="My Name"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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>
Navigation Drawer (Single Activity which parent of all Fragments) 导航抽屉(单个活动所有碎片的父级)
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);
}
}
I tired alot to resolve this issue and after months of googling and stackoverflow im still stuck in same issue. 我累了很多来解决这个问题,经过几个月的谷歌搜索和stackoverflow仍然陷入同样的问题。
Issue example of Point 1:- When navigation drawer load first everything looks good, view pager changes title as per fragment. 第1点的问题示例: - 当导航抽屉首先加载所有内容时,查看寻呼机会根据片段更改标题。 then if i click on Navigation Drawer's Menu which also open another fragment (For Ex: Recent Message).
然后如果我点击导航抽屉的菜单,它也会打开另一个片段(例如:最近的消息)。 then title change successfully but when i press back button or trying to press home button which calls viewpager then title remain same as before ie Recent Message.
然后标题更改成功但当我按下后退按钮或尝试按下调用viewpager的主页按钮时,标题保持与之前相同,即最近消息。
Setting Title in each fragment like this. 像这样在每个片段中设置标题。
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);
Whether is it good practice to doing all task within Fragment with Single Activity.
使用单一活动在Fragment中执行所有任务是否是一种好习惯。
It is a good practice to use fragments when you use with navigation drawers, tabs or bottom navigation. 使用导航抽屉,标签或底部导航时,最好使用碎片。
Other than that, fragments are mostly preferred for reusable UI with different data. 除此之外,片段最常用于具有不同数据的可重用UI。
You are doing all task within fragment with Single Activity because you are using navigation draw and tabs, so It is a good practice, I'd say. 你正在使用单一活动在片段内完成所有任务,因为你正在使用导航绘图和标签,所以这是一个很好的做法,我会说。
Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link.
工具栏不会更改片段的标题,按下后退按钮或通过单击按钮或某个链接前进。
You need to manually set the title for fragment whenever you are adding/replacing new fragment OR 无论何时添加/替换新片段OR,都需要手动设置片段的标题
on back press(backstack change), through Fragment only or using OnBackStackChangedListener as mentioned in docs . 在背面压(返回堆栈变化),通过仅片段或使用OnBackStackChangedListener如提到的文档 。
You are just setting them while you are clicking through navigation items and not while clicking button or some link 您只是在点击导航项时设置它们,而不是在单击按钮或某个链接时设置它们
Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true);
如果我使用以下方法更改为后退箭头,导航汉堡会继续显示:getSupportActionBar()。setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.
然后后退箭头打开抽屉,但不会回到最后一个片段。
That too you'd need to handle manually. 你也需要手动处理。 using onOptionItemSelected on click of android.R.id.home item.
单击android.R.id.home项目时使用onOptionItemSelected 。 Like poping fragments out from stack.
就像从堆栈中弹出片段一样。
The cause of your title persistence on back is setting title from Activity. 标题持久性的原因是从Activity设置标题。 ie using this
setTitle(menuItem.getTitle());
即使用此
setTitle(menuItem.getTitle());
instead set them through Fragment or if you are setting them trough Fragment remove from selectDrawerItem
method. 而是通过Fragment设置它们,或者如果你通过
selectDrawerItem
方法从Fragment中删除它们。
Also at the end of selectDrawerItem
method you are using fragmentTransaction.add
instead use fragmentTransaction.replace
同样在
selectDrawerItem
方法的末尾,您使用fragmentTransaction.add
而不是使用fragmentTransaction.replace
If application have to use Navigation Drawer which should be present in all views, then Fragment should be used. 如果应用程序必须使用应存在于所有视图中的导航抽屉,则应使用Fragment。 And its not a bad practice.
这不是一个坏习惯。
Create a method in Base Activity 在Base Activity中创建方法
public void setFragmentTitle(String title){
if(!TextUtils.isEmpty(title))
mTitleText.setText(title);
}
Access this method from your individual Fragments in onCreateView
从
onCreateView
各个片段访问此方法
((LandingActivity) getActivity()).setFragmentTitle(getActivity().getString(R.string.fragment_title));
Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); 如果我使用以下方法更改为后退箭头,导航汉堡会继续显示:getSupportActionBar()。setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.
然后后退箭头打开抽屉,但不会回到最后一个片段。
Use onOptionItemSelected
on click of android.R.id.home
, pop the current Fragment
单击
android.R.id.home
使用onOptionItemSelected
,弹出当前的Fragment
Fragment State Loss when pressed back button or jumping directly to some fragment 按下按钮或直接跳转到某个片段时的片段状态丢失
You have to mention the values which needs to be persisted and repopulate it. 你必须提到需要持久化的值并重新填充它。
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);
}
}
In your Fragment 在你的片段中
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);
}
}
EDIT 1: For Fragment Title not getting updated in BackButton press 编辑1:对于片段标题没有在BackButton按下更新
While adding Fragment
to backstack , do the following. 将
Fragment
添加到backstack时,请执行以下操作。
In your parent Activity 在您的父级活动中
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);
Now override onBackPressed in parent Activity 现在覆盖父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;
}
Now in LandingFrag 现在在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();
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.