NavigationDrawer片段工具栏图标随机消失

时间:2018-10-23 11:23:01

标签: android android-fragments android-toolbar android-navigation-drawer

我有一个带有 NavigationDrawer 和许多片段的应用程序。我现在遇到的问题是,有时图标在工具栏中不可见。有时候他们在那里。我找不到重现此问题的正确方法。

我录制了一段视频来演示这种行为。如您所见,图标消失了,直到我关闭应用程序并重新打开它。

Video showing the effect of disappearing icons

查看右上角的工具栏。首先,没有图标。关闭应用程序并重新打开之后,图标就出现了。当我切换片段或进行其他活动并返回片段时,它们也会随机消失。

编辑:有时仅搜索图标消失,有时两个图标消失。

如上所述,这是一个带有片段的导航抽屉。每当我从导航抽屉中更改片段时,图标也必须根据显示的片段进行更改。

明智的代码如下:

MainActivity.java

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {

    ...

    /**
     * {@link AppCompatActivity#onCreate(Bundle)}
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        sharedPreferences = getSharedPreferences(Preferences.CINEMAN, Context.MODE_PRIVATE);
        editor = sharedPreferences.edit();

        // Compatibility with older android versions
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);


        // restore the saved instance state
        resolvingGoogleAPIClientError = (savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false));

        fragmentStack = new HashMap<>();
        currentFragmentBackStackCount = 0;

        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        setSupportActionBar(toolbar);

        decorView = this.getWindow().getDecorView();
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        navigationView.setNavigationItemSelectedListener(this);

        profilePictureImageView = navigationView.getHeaderView(0).findViewById(R.id.profilePictureImageView);
        drawerHeaderMainLabel = navigationView.getHeaderView(0).findViewById(R.id.drawerHeaderMainLabel);
        drawerHeaderSubLabel = navigationView.getHeaderView(0).findViewById(R.id.drawerHeaderSubLabel);

        getSupportFragmentManager().addOnBackStackChangedListener(
                () -> {
                    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                        drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                        toolbar.setNavigationOnClickListener(v -> onBackPressed());
                    } else {
                        drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
                        toolbar.setNavigationOnClickListener(v -> drawer.openDrawer(GravityCompat.START));
                    }
                    if (getSupportFragmentManager().getBackStackEntryCount() < currentFragmentBackStackCount) {
                        List<Fragment> fragments = getSupportFragmentManager().getFragments();
                        for (Fragment fragment : fragments) {
                            if (fragment != null && fragment.isVisible()) {
                                activeFragment = (AppFragment) fragment;
                                updateUIForActiveFragment();
                                break;
                            }
                        }

                    }
                    currentFragmentBackStackCount = getSupportFragmentManager().getBackStackEntryCount();
                });

        formatNavigationDrawerElements();
    }   


    /**
     * {@link NavigationView.OnNavigationItemSelectedListener#onNavigationItemSelected(MenuItem)}
     */
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_showtimes_by_movie) {
            fragmentClass = ShowtimesByMovieFragment.class;
        } else if (id == R.id.nav_showtimes_by_time) {
            fragmentClass = ShowtimesByTimeFragment.class;
        } else if (id == R.id.nav_showtimes_by_watchlist) {
            fragmentClass = ShowtimesByWatchlistFragment.class;
        } else if (id == R.id.nav_theatres) {
            fragmentClass = TheatresFragment.class;
        } else if (id == R.id.nav_articles) {
            fragmentClass = ArticlesFragment.class;
        } else if (id == R.id.nav_movies) {
            fragmentClass = MoviesFragment.class;
        } else if (id == R.id.nav_watchlist) {
            fragmentClass = MoviesWatchlistFragment.class;
        } else if (id == R.id.nav_settings) {
            fragmentClass = SettingsFragment.class;
        }

        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStackImmediate();
        }

        showAppFragmentOfClass(fragmentClass, false);

        return true;
    }

    /**
     * Show a new app fragment of class X
     *
     * @param appFragmentClass The class of the app fragment to show
     * @param pushOnStack      Flag defining if the new fragment should be pushed on the navigation stack
     */
    void showAppFragmentOfClass(Class appFragmentClass, boolean pushOnStack, boolean isAnimatedTransition) {
        fragmentClass = appFragmentClass;
        showAppFragmentOfClass(appFragmentClass, pushOnStack, null, isAnimatedTransition);
    }

    void showAppFragmentOfClass(Class appFragmentClass, boolean pushOnStack) {
        fragmentClass = appFragmentClass;
        showAppFragmentOfClass(appFragmentClass, pushOnStack, null, false);
    }

    void showAppFragmentOfClass(Class appFragmentClass, boolean pushOnStack, AppFragment useThisInstance) {
        fragmentClass = appFragmentClass;
        showAppFragmentOfClass(appFragmentClass, pushOnStack, useThisInstance, false);
    }

    /**
     * Show a new app fragment of class X
     *
     * @param appFragmentClass The class of the app fragment to show
     * @param pushOnStack      Flag defining if the new fragment should be pushed on the navigation stack
     * @param useThisInstance  If this is set, the instance will be used and not one created
     */
    void showAppFragmentOfClass(Class appFragmentClass, boolean pushOnStack, AppFragment useThisInstance, boolean isAnimatedTransition) {
        if (!CinemanApplication.getCurrentAppInstance().isActivityVisible()) {
            return;
        }

        // do not reload the already active fragment
        if (activeFragment != null && activeFragment.getClass().equals(appFragmentClass)) {
            if (drawer.isDrawerOpen(GravityCompat.START)) {
                drawer.closeDrawer(GravityCompat.START);
            }
            return;
        }

        try {
            if (appFragmentClass != null) {
                AppFragment fragment = null;

                if (useThisInstance != null) {
                    fragment = useThisInstance;
                } else {
                    if (fragmentStack.containsKey(appFragmentClass.toString())) {
                        fragment = fragmentStack.get(appFragmentClass.toString());
                    } else {
                        try {
                            fragment = (AppFragment) appFragmentClass.newInstance();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

                if (fragment != null) {
                    if (!fragmentStack.containsKey(appFragmentClass.toString()) && useThisInstance == null) {
                        fragmentStack.put(appFragmentClass.toString(), fragment);
                    }

                    if (fragment.shouldBeStoredAsLastActivity()) {
                        SharedPreferences sharedPreferences = getSharedPreferences(Preferences.CINEMAN, Context.MODE_PRIVATE);
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putString(Preferences.LAST_ACTIVE_FRAGMENT, appFragmentClass.toString());
                        editor.apply();
                    }

                    // Insert the fragment by replacing any existing fragment
                    FragmentManager fragmentManager = getSupportFragmentManager();

                    if (pushOnStack) {
                        FragmentTransaction ft = fragmentManager.beginTransaction();
                        ft.addToBackStack(appFragmentClass.toString());
                        if (isAnimatedTransition) {
                            ft.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_out_up);
                        }
                        ft.replace(R.id.content_main, fragment, appFragmentClass.toString());
                        ft.commit();
                    } else {
                        fragmentManager.beginTransaction().replace(R.id.content_main, fragment, appFragmentClass.toString()).commit();
                    }
                    fragmentManager.executePendingTransactions();
                    if (activeFragment != null) {
                        if (fragment.displayCloseButton()) {
                            activeFragment.doNotTrack();
                        } else {
                            activeFragment.allowTracking();
                        }
                    }
                    activeFragment = fragment;
                    updateUIForActiveFragment();
                }
            }

            if (drawer.isDrawerOpen(GravityCompat.START)) {
                drawer.closeDrawer(GravityCompat.START);
            }
        } catch (Exception e) {
            Utils.registerAppCrash(getApplicationContext());
            Utils.reportAppCrash(e);
        }
    }

    /**
     * {@link AppCompatActivity#onOptionsItemSelected(MenuItem)}
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (activeFragment != null) {
            return activeFragment.onOptionsItemSelected(item);
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (activeFragment != null) {
            activeFragment.setMenu(menu, getMenuInflater());
        }
        return super.onPrepareOptionsMenu(menu);
    }

    /**
     * Helper method handling UI changes if the active fragment changes
     */
    private void updateUIForActiveFragment() {
        invalidateOptionsMenu();

        activeFragment.allowTracking();

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
        if (activeFragment.forcePortraitMode()) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
        }

        if (activeFragment.hasToolbarSpinner()) {
            getSupportActionBar().setTitle(null);
            toolbarSpinner.setAdapter(buildToolbarSpinnerMenuAdapter());
            toolbarSpinner.setOnItemSelectedListener(activeFragment);
            toolbarSpinner.setVisibility(View.VISIBLE);
        } else {
            toolbarSpinner.setAdapter(null);
            toolbarSpinner.setOnItemSelectedListener(null);
            toolbarSpinner.setVisibility(View.GONE);

            if (activeFragment.getToolbarTitle() != null) {
                getSupportActionBar().setTitle(activeFragment.getToolbarTitle());
            }
        }

        if (activeFragment.getNavigationDrawerMenuId() >= 0) {
            if (navigationView.getMenu().findItem(activeFragment.getNavigationDrawerMenuId()).isCheckable()) {
                navigationView.getMenu().findItem(activeFragment.getNavigationDrawerMenuId()).setChecked(true);
                navigationView.setCheckedItem(activeFragment.getNavigationDrawerMenuId());
            }
        }

        setHomeButtonEnabled(true);

        tabLayout.removeAllTabs();
        tabLayout.clearOnTabSelectedListeners();
        if (activeFragment.addTabs(tabLayout)) {
            tabLayout.addOnTabSelectedListener(activeFragment);
            tabLayout.setVisibility(View.VISIBLE);
        } else {
            tabLayout.setVisibility(View.GONE);
        }

        if (activeFragment.wantsFullscreenLayout()) {
            drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
            getSupportActionBar().hide();
            CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mainContentFrame.getLayoutParams();
            layoutParams.setMargins(0, 0, 0, 0);
            mainContentFrame.setLayoutParams(layoutParams);
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = getWindow();
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(colorPrimaryDark);
            }
            drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
            getSupportActionBar().show();
            CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mainContentFrame.getLayoutParams();
            TypedValue typedValue = new TypedValue();
            getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true);
            layoutParams.setMargins(0, (int) getResources().getDimension(typedValue.resourceId), 0, 0);
            mainContentFrame.setLayoutParams(layoutParams);
        }
    }

    ...
}

以及在导航抽屉中选择它时显示的片段:

MoviesFragment.java

public class MoviesFragment extends AppFragment {

    ...

    /**
     * {@link AppFragment#setMenu(Menu, MenuInflater)}
     */
    @Override
    boolean setMenu(Menu menu, MenuInflater menuInflater) {
        menuInflater.inflate(R.menu.movies_options_menu, menu);

        filterListViewMenuItem = menu.findItem(R.id.filter_list);
        filterListViewMenuItem.setVisible(true);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
        searchViewMenuItem = menu.findItem(R.id.search);
        searchViewMenuItem.setVisible(false);
        searchView = (SearchView) MenuItemCompat.getActionView(searchViewMenuItem);
        searchView.setMaxWidth(Integer.MAX_VALUE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
        searchView.setOnQueryTextListener(this);
        searchView.setSubmitButtonEnabled(false);
        searchView.setIconifiedByDefault(true);
        searchView.setQueryHint(getString(R.string.movies_search));

        updateMenu(menu);

        return true;
    }


    @Override
    public void updateMenu(Menu menu) {
        BadgeStyle badgeStyle = new BadgeStyle(BadgeStyle.Style.DEFAULT, R.layout.custom_menu_action_item_badge, Color.parseColor("#ffffff"), Color.parseColor("#ffffff"), Color.parseColor("#b0152d"));
        badgeStyle.setStroke(6);
        badgeStyle.setStrokeColor(Color.parseColor("#e41e3d"));
        if (selectedMovieGenreList != null && selectedMovieGenreList.size() > 0) {
            ActionItemBadge.update(getActivity(), menu.findItem(R.id.filter_list), iconFilterList, badgeStyle, selectedMovieGenreList.size());
        } else {
            ActionItemBadge.update(getActivity(), menu.findItem(R.id.filter_list), iconFilterList, badgeStyle, null);
        }
    }

    /**
     * {@link AppFragment#onOptionsItemSelected(MenuItem)}
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.filter_list:
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        openGenreFilter();
                    }
                }, 60);
                return true;
            default:
                return false;
        }
    }

}

movies_options_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <item
        android:id="@+id/share_movie"
        android:icon="@drawable/ic_share_white_24px"
        android:title="@string/movie_toolbar_share_title"
        android:visible="false"
        app:showAsAction="always"
        tools:ignore="AppCompatResource" />

    <item
        android:id="@+id/search"
        android:icon="@android:drawable/ic_menu_search"
        android:showAsAction="always"
        android:title="@string/movies_search"
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="always"
        tools:ignore="AppCompatResource" />

    <item
        android:id="@+id/filter_list"
        android:icon="@drawable/ic_filter"
        android:showAsAction="always"
        android:title="@string/filter_genre_title_selector"
        app:actionLayout="@layout/custom_menu_action_item_badge"
        app:showAsAction="always"
        tools:ignore="AppCompatResource" />

</menu>

当片段到达前台时,我会打电话给invalidateOptionsMenu(),因此据我了解,图标应显示在工具栏中。

我想不出我想念的是图标在那里一直显示而不是随机显示的原因。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

请记住要在片段的setHasOptionsMenu(true);方法内调用onCreate(),因为通过调用updateUIForActiveFragment()使invalidateOptionsMenu();内部的选项菜单无效了

答案 1 :(得分:-1)

尝试实现该片段具有自己的菜单项的片段。

例如:

创建一个Util类并添加这两个方法。

public static View addRemoveViewFromToolbar(FragmentActivity fragmentActivity, int resourceId) {
        Toolbar toolbar = removeViewFromToolbar(fragmentActivity);
        if (resourceId == 0) {
            return null;
        } else {
            View view = LayoutInflater.from(fragmentActivity).inflate(resourceId, toolbar, false);
            toolbar.addView(view);
            return view;
        }
    }


    public static Toolbar removeViewFromToolbar(FragmentActivity fragmentActivity) {
        Toolbar toolbar = fragmentActivity.findViewById(R.id.toolbar);
        if (toolbar.getChildCount() > 1) {
            for (int i = 1; i <= toolbar.getChildCount(); i++) {//not remove navigation hamburger icon 
                toolbar.removeViewAt(1);
            }
        }
        return toolbar;
    }

在您的片段类中:

View toolbarView = Util.addRemoveViewFromToolbar(getActivity(), R.layout.toolbar_filter); // create toolbar_filter xml and add search and filter images
        Imageview search = toolbarView.findViewById(R.id.img_search_view); // get widget view 

您应该在此小部件中添加点击或其他事件。