简体   繁体   English

导航抽屉的碎片管理

[英]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. 在我面临的问题之后。

  1. Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link. 工具栏不会更改片段的标题,按下后退按钮或通过单击按钮或某个链接前进。
  2. Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); 如果我使用以下方法更改为后退箭头,导航汉堡会继续显示using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment. 然后后退箭头打开抽屉,但不会回到最后一个片段。
  3. Fragment State Loss when pressed back button or jumping directly to some fragment. 按下按钮或直接跳转到某个片段时的片段状态丢失。
  4. Whether is it good practice to doing all task within Fragment with Single Activity . 使用单一ActivityFragment执行所有任务是否是一种好习惯。

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. 这不是一个坏习惯。

  1. Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link. 工具栏不会更改片段的标题,按下后退按钮或通过单击按钮或某个链接前进。

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));
  1. 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

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM