web-dev-qa-db-fra.com

Restauration de l'état des fragments lors de la modification des fragments via la barre de navigation inférieure

J'ai la barre de navigation inférieure sur le clic de l'élément dans la barre de navigation je remplace les fragments. J'ai 3 fragments A, B, C donc sur le clic de l'élément b, le fragment B est chargé et dans B j'appelle 3-4 API. Alors maintenant, si je vais à C et que je reviens à B, une nouvelle instance de B Fragment est créée et à nouveau ces API sont appelées comment puis-je enregistrer l'état de l'instance de fragment et ne pas appeler à nouveau les API lors du changement de fragments. Ceci est mon code.

mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            int id = item.getItemId();
            Fragment currentLoaded = fgMan.findFragmentById(R.id.container_body);
            switch (id) {
                case R.id.nearby_fragment:
                    if (!(currentLoaded instanceof SpotFeedMapFragment)) {
                        removeScroll();
                        mNearByFragment = fgMan.findFragmentByTag(NEARBY_FRAGMENT_TAG) != null ? fgMan.findFragmentByTag(NEARBY_FRAGMENT_TAG) : mNearByFragment;
                        fgMan.beginTransaction().setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
                        fgMan.beginTransaction().replace(R.id.container_body, mNearByFragment, NEARBY_FRAGMENT_TAG).commit();
                        fgMan.executePendingTransactions();
                        getSupportActionBar().setTitle(getString(R.string.nearby_fragment));
                    }
                    break;
                case R.id.route_fragment:
                    if (!(currentLoaded instanceof BusLocationsFragment)) {
                        if (!inParent) {
                            mRl.removeView(fixLayout);
                            p.addRule(RelativeLayout.BELOW, toolbar.getId());
                            scrollView.setLayoutParams(p);
                            scrollView.addView(fixLayout);
                            mRl.addView(scrollView);
                            inParent = true;
                        }
                        //mFragment = new BusLocationsFragment();
                        mBusLocFragment = fgMan.findFragmentByTag(BUS_LOC_FRAGMENT_TAG) != null ? fgMan.findFragmentByTag(BUS_LOC_FRAGMENT_TAG) : mBusLocFragment;
                        fgMan.beginTransaction().setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
                        fgMan.beginTransaction().replace(R.id.container_body, mBusLocFragment, BUS_LOC_FRAGMENT_TAG).commit();
                        fgMan.executePendingTransactions();
                        getSupportActionBar().setTitle(getString(R.string.app_name));
                    }
                    break;
                case R.id.newsfeed_activity:
                    if (!(currentLoaded instanceof NewsFeedActivity)) {
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop_MR1) {
                            removeScroll();
                        }
                        mNewsFeedFragment = fgMan.findFragmentByTag(NEWSFEED_FRAGMENT_TAG) != null ? fgMan.findFragmentByTag(NEWSFEED_FRAGMENT_TAG) : mNewsFeedFragment;
                        fgMan.beginTransaction().setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
                        fgMan.beginTransaction().replace(R.id.container_body, mNewsFeedFragment, NEWSFEED_FRAGMENT_TAG).commit();
                        fgMan.executePendingTransactions();
                        getSupportActionBar().setTitle(getString(R.string.news));
                    }
                    break;
            }
            return true;
        }
    });

J'ai déjà initialisé les fragments des variables membres ci-dessus dans onCreateof MainActivity

15
user007

Vous devez utiliser un FragmentPagerAdapter pour lancer les fragments afin que lorsque vous souhaitez basculer entre eux, l'état des fragments sera enregistré.

CutomViewPager viewPager = (CustomViewPager) findViewById(R.id.viewpager1);
ViewPagerAdapter adapter = new ViewPagerAdapter (MainActivity.this.getSupportFragmentManager());
adapter.addFragment(new SpotFeedMapFragment(), "title");
adapter.addFragment(new BusLocationsFragment(), "title");
adapter.addFragment(new NewsFeedActivity(), "title");
viewPager.setAdapter(adapter);

puis dans la navigation inférieure sélectionnée, vous pouvez définir un fragment par simple commande

viewPager.setCurrentItem(n);

ma classe de viseur est la suivante:

public class CustomViewPager extends ViewPager {

private boolean isPagingEnabled;

public CustomViewPager(Context context) {
    super(context);
    this.isPagingEnabled = true;
}

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.isPagingEnabled = true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onTouchEvent(event);
}

//for samsung phones to prevent tab switching keys to show on keyboard
@Override
public boolean executeKeyEvent(KeyEvent event) {
    return isPagingEnabled && super.executeKeyEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}

public void setPagingEnabled(boolean enabled) {
    this.isPagingEnabled = enabled;
}
}

dans le xml au lieu d'une mise en page vide pour fragemnt u besoin:

<com.package.util.CustomViewPager
    Android:id="@+id/viewpager1"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" />

Code pour FragmentPagerAdapter personnalisé:

private class ViewPagerAdapter extends FragmentPagerAdapter {
    private final SparseArray<WeakReference<Fragment>> instantiatedFragments = new SparseArray<>();
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final Fragment fragment = (Fragment) super.instantiateItem(container, position);
        instantiatedFragments.put(position, new WeakReference<>(fragment));
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        instantiatedFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    @Nullable
    Fragment getFragment(final int position) {
        final WeakReference<Fragment> wr = instantiatedFragments.get(position);
        if (wr != null) {
            return wr.get();
        } else {
            return null;
        }
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}
11
Harsh Ganatra

J'ai utilisé bottom navigation bar et je l'ai fait en personnalisant le visualiseur et je désactive la navigation par balayage. Chaque fois que l'utilisateur clique sur l'élément inférieur, définissez le fragment approprié dans le visualiseur. Viewpager contrôle l'état du fragment, donc pas besoin de contrôler l'état.

ViewPager personnalisé

public class BottomNavigationViewPager extends ViewPager {

    private boolean enabled;

    public BottomNavigationViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    /**
     * Enable or disable the swipe navigation
     * @param enabled
     */
    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}

Si vous voulez toujours contrôler l'état du fragment, vous pouvez voir ma réponse dans ce lien Comment enregistrer l'état du fragment dans Android?

6
RoShan Shan