代码之家  ›  专栏  ›  技术社区  ›  Dominik

导航抽屉碎片工具栏图标随机消失

  •  1
  • Dominik  · 技术社区  · 7 年前

    我有一个应用程序 导航抽屉 还有一些碎片。我现在遇到的问题是,有时图标在工具栏中不可见。不过,有时他们也在那里。我找不到合适的方法来重现这个问题。

    我录了一段视频来演示这种行为。你可以看到图标消失了,直到我关闭应用程序并重新打开它。

    Video showing the effect of disappearing icons

    看看右上角的工具栏。首先,没有图标。关闭并重新打开应用程序后,图标就在那里。当我切换片段或转到另一个活动并返回片段时,它们也会随机消失。

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

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

    代码方面如下所示:

    main活动.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;
            }
        }
    
    }
    

    电影选项菜单.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 回复  |  直到 7 年前
        1
  •  0
  •   Gratien Asimbahwe    7 年前

    记得打电话给 setHasOptionsMenu(true); 在里面 onCreate() 方法,因为您正在使内部的选项菜单无效 updateUIForActiveFragment() 通过打电话 invalidateOptionsMenu();

        2
  •  -1
  •   Mitesh Vanaliya    7 年前

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

    例如:

    创建一个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 
    

    您应该在这个小部件中添加click或其他事件。。

    推荐文章