当前位置: 首页 > 知识库问答 >
问题:

通过底部导航栏更改片段时恢复片段状态

令狐俊风
2023-03-14

我有底部的导航栏,点击导航栏中的项目,我正在替换片段。我有3个片段A、B、C,所以点击B项B片段被加载,在B中我调用3-4个API。所以现在如果我转到C,然后再次转到B,将创建一个新的B片段实例,并再次调用这些API,那么如何保存片段实例状态,并且在更改片段时不再调用API。这是我的密码。

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;
        }
    });

我已经在MainActivity的onCreate中初始化了上面的片段成员变量

共有3个答案

法弘壮
2023-03-14

我使用了底部导航栏,通过自定义viewpager来实现,并禁用了滑动导航。每次用户单击底部项目时,在viewpager中设置相关片段。Viewpager控制片段的状态,所以不需要控制状态。

自定义ViewPager

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;
    }
}

如果你还想控制片段的状态,你可以在这个链接中看到我的答案如何在android中保存片段状态?

何聪
2023-03-14

要恢复/保留片段的状态,您应该使用ViewPager2,因为它是ViewPager的更新版本。

您将在我的GitHub存储库中获得代码,底部导航栏中有三个菜单项,具有更多功能。我还在下面的导航栏中提供了两个菜单项的简单描述。

分步指南(以恢复/保留EditText的状态为例):

步骤1:

在build.gradle(应用模块)文件中添加依赖项:

dependencies {

    def nav_version = "2.3.0"
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-ui:$nav_version"

    implementation 'androidx.viewpager2:viewpager2:1.0.0'

}

第二步:

将menu_bottom_navigation.xml添加到res/菜单:(您也可以将图标添加到菜单项)

<?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">
    <item
        android:id="@+id/menu_first"
        android:checked="true"
        android:title="First"
        app:showAsAction="always" />
    <item
        android:id="@+id/menu_second"
        android:checked="false"
        android:title="Second"
        app:showAsAction="always" />

</menu>

第三步:

添加activity\u main。xml到资源/布局:(将菜单添加到BottomNavigationView并放置ViewPager2)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:id="@+id/activityRoot"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom"
    android:orientation="vertical"
    android:animateLayoutChanges="true"
    tools:context=".MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottom_navigation"
        android:layout_alignParentTop="true"
        android:layout_weight="1"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:fitsSystemWindows="true"
        app:itemIconSize="20dp"
        android:background="#A8DD44"
        app:menu="@menu/menu_bottom_navigation" />

</LinearLayout>

步骤4:

首先添加fragment\u。xml到资源/布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="20dp"
    tools:context="com.example.rough.Fragment.FirstFragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="First Fragment"
        android:layout_centerInParent="true"
        android:textSize="30sp" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Write something &amp; it will stay"
        android:ems="13"/>

</LinearLayout>

第五步:

添加fragment_second.xml到res/布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:orientation="vertical"
    tools:context="com.example.rough.Fragment.SecondFragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Second Fragment"
        android:layout_centerInParent="true"
        android:textSize="30sp" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Write something &amp; it will stay"
        android:ems="13"/>

</LinearLayout>

步骤6:

ViewPagerAdapter。java:

public class ViewPagerAdapter extends FragmentStateAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public ViewPagerAdapter(@NonNull FragmentManager fragmentManager, Lifecycle b ) {
        super(fragmentManager,b);
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }

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

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

}

第7步:

FirstFragment.java:

public class FirstFragment extends Fragment {


    public FirstFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false);
    }

}

第8步:

第二ragment.java:

public class SecondFragment extends Fragment {


    public SecondFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false);
    }

}

步骤9:

主要活动。java:

public class MainActivity extends AppCompatActivity {

    BottomNavigationView bottomNavigationView;

    private ViewPager2 viewPager2;

    FirstFragment firstFragment;
    SecondFragment secondFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager2 = findViewById(R.id.viewpager2);
        bottomNavigationView = findViewById(R.id.bottom_navigation);

        bottomNavigationView.setOnNavigationItemSelectedListener(
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.menu_first:
                                viewPager2.setCurrentItem(0,false);
                                break;
                            case R.id.menu_second:
                                viewPager2.setCurrentItem(1,false);
                                break;
                        }
                        return false;
                    }
                });

        viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels);

                switch (position) {
                    case 0:
                        bottomNavigationView.getMenu().findItem(R.id.menu_first).setChecked(true);
                        break;
                    case 1:
                        bottomNavigationView.getMenu().findItem(R.id.menu_second).setChecked(true);
                        break;
                }
            }
        });

        setupViewPager(viewPager2);

    }

    private void setupViewPager(ViewPager2 viewPager) {

        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle());

        firstFragment =new FirstFragment();
        secondFragment =new SecondFragment();

        adapter.addFragment(firstFragment);
        adapter.addFragment(secondFragment);

        viewPager.setAdapter(adapter);
    }

}
何禄
2023-03-14

您应该使用FragmentPagerAdapter来启动片段,以便在它们之间切换时,片段的状态将被保存。

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

然后在所选的底部导航中,您可以通过简单的命令设置片段

viewPager.setCurrentItem(n);

我的viewpager类如下:

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;
}
}

xml中,而不是空布局中,碎片u需要:

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

自定义FragmentPagerAdapter的代码:

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);
    }
}
 类似资料:
  • 我的主要活动中有一个底部导航栏。通过单击底部导航中的一个选项卡,我想更改视图中的片段。我有以下代码:主要活动: } 我的一个片段: 如果我单击其中一个选项卡,就会显示正确的片段,因此这是可行的。然而,当新片段出现时,我想单击另一个选项卡来显示另一个片段,这就行不通了。底部导航栏不会对单击做出反应。甚至日志。i语句不起作用,因此似乎没有调用导航项SelectedListener。 我对android

  • 我试图做恢复片段视图状态值(文本视图,... 我的活动。Java语言 ProductFragment。Java语言 在ProductFragment中,我将向文本视图添加值。当我从ReportFragment开始时,视图值将在ProductFragment中清除。

  • 我创建了一个带有“底部导航活动”的新项目: 这是生成的代码: 如何使用底部栏更改为新片段?例如,我有3个片段:Fragment1 Fragment2和Fragment3,我想用底部栏中的3个按钮更改为它们。我还想通过左右滑动手指来切换片段,我该怎么做?

  • 我正在创建和应用程序,到目前为止一切都很好。今天,我处理一个片段中的数据,以访问我的webservice并返回json,然后将该数据插入到我的sqlite中,然后在listview中显示该数据并逐秒更新数据。 一切都是正确的,直到我发现如果我在底部导航中单击片段中的项目的位置过快,它将在应用程序对片段执行事务时崩溃。只有当我在该片段和其他4个片段中的多个片段之间单击时,才会发生这种情况。 所以我的

  • 我试图设置一个显示3个片段的底部导航。 问题是,该应用程序完全适用于Android 5.0,但在Android 6.0及更高版本上抛出错误... SdkVersion 26-minSdkVersion 21-塔吉特SdkVersion 26- 可以肯定的是,我一直在使用这个例子来构建这个应用程序,在我的代码中实现了这个方法之后,仍然会抛出一个异常。 提前感谢您的帮助。 错误: 主要活动 主要活动X

  • 我试图理解在导航选项卡中使用片段时如何保持片段视图状态。在我的努力中,我遇到了两个我找不到合适解决方案的问题。 我有两个选项卡,Tab1和Tab2。Tab1的布局由碎片A定义,Tab2的布局由碎片B定义。我遵循了这里给出的方法(编辑:自从提出这个问题以来,文档已经发生了变化)。 第一个问题:即使我的视图有ID,当片段被重新附加时(在选项卡切换旋转之后),它们的状态也不会完全恢复。特别是:具有ID的