First of all, I'm not too sure that my usage of two ViewPagers and a TabLayout is correct. If you have a better way, please let me know!
I currently have a TabLayout sandwiched between the two ViewPagers. I want to be able to click on the fragment titles on the TabLayout, then have the top and bottom ViewPager change based on the selected fragment title. Currently, I only have one of the ViewPagers linked with the TabLayout, but I can't figure out how to link the other ViewPager.
Just as an example, say I have frg 1, frg 2, frg 3, frg 4, frg 5, frg 6. I click on "Tab 1" on the TabLayout --> frg 1 is shown on the top ViewPager, frg 2 is shown on the bottom ViewPager. I click on "Tab 2" on the TabLayout --> frg 3 is shown on the top ViewPager, frg 4 is shown on the bottom ViewPager. I click on "Tab 3" on the TabLayout --> frg 5 is shown on the top ViewPager, frg 6 is shown on the bottom ViewPager.
My FragmentPagerAdapter: I'm not too sure if I should have two ArrayLists of fragments or just use one.
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>(); // this line can cause crashes
private final List<String> titleList = new ArrayList<>();
private final List<Fragment> fragmentList2 = new ArrayList<>(); //not being used right now
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return titleList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public void AddFragment (Fragment fragment, String title) {
fragmentList.add(fragment); // this line can cause crashes
titleList.add(title);
}
public void ClearFragments () {
fragmentList.clear();
titleList.clear();
}
}
My MainActivity: Currently only puts stuff in the bottom ViewPager.
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
private TabLayout tabLayout;
private ViewPager viewPager;
private ViewPagerAdapter viewPagerAdapter;
private ArrayList<BloodSugar> listBloodSugar;
private ArrayList<Excercise> listExercise;
private GoogleMap map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SelectionActivity.lastActivity = MainActivity.class;
setContentView(R.layout.activity_main);
tabLayout = (TabLayout) findViewById(R.id.tabLayout_id);
viewPager = (ViewPager) findViewById(R.id.viewpager_id);
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.AddFragment(new FragmentSymptom(), "Symptoms"); //basically frg 2 in example
viewPagerAdapter.AddFragment(new FragmentBloodSugar(), "Blood Sugar"); //basically frg 4 in example
viewPagerAdapter.AddFragment(new FragmentExercise(), "Exercise"); //basically frg 6 in example
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
}
My MainActivity xml file: I'm attempting to have the top ViewPager vertically wrap content, the TabLayout vertically wrap content, and have the bottom ViewPager take up the remaining vertical space. However, I don't know how it will actually look like as my top ViewPager doesn't have anything inside.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:id="@+id/activity_main_relative_layout">
<androidx.appcompat.widget.Toolbar
android:theme="@style/AppTheme"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager_id2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorButtonBlue"
app:tabMode="fixed"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorAccent"
android:id="@+id/tabLayout_id">
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager_id"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
</RelativeLayout>
Please let me know if there's anything else you need. Thanks in advance!
viewPagerAdapter.addFragment()
is an anti-pattern because it will inevitably cause crashes after process death in production.
The correct way to implement a regular FragmentPagerAdapter is:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
if(position == 0) return new RulesFragment();
if(position == 1) return new TreeFragment();
if(position == 2) return new PredictionFragment();
throw new IllegalStateException("Unexpected position " + position);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
if(position == 0) return "TREE RULES";
if(position == 1) return "REGRESSION TREE";
if(position == 2) return "PREDICTION";
throw new IllegalStateException("Unexpected position " + position);
}
}
To get a reference to a Fragment created by a ViewPager, use the following findFragmentByTag
scheme:
Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)
If you need a dynamic FragmentPagerAdapter (which you do, according to your clear()
method), then you can do:
public class DynamicFragmentPagerAdapter extends PagerAdapter {
private static final String TAG = "DynamicFragmentPagerAdapter";
private final FragmentManager fragmentManager;
public static abstract class FragmentIdentifier implements Parcelable {
private final String fragmentTag;
private final Bundle args;
public FragmentIdentifier(@NonNull String fragmentTag, @Nullable Bundle args) {
this.fragmentTag = fragmentTag;
this.args = args;
}
protected FragmentIdentifier(Parcel in) {
fragmentTag = in.readString();
args = in.readBundle(getClass().getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(fragmentTag);
dest.writeBundle(args);
}
protected final Fragment newFragment() {
Fragment fragment = createFragment();
Bundle oldArgs = fragment.getArguments();
Bundle newArgs = new Bundle();
if(oldArgs != null) {
newArgs.putAll(oldArgs);
}
if(args != null) {
newArgs.putAll(args);
}
fragment.setArguments(newArgs);
return fragment;
}
protected abstract Fragment createFragment();
}
private ArrayList<FragmentIdentifier> fragmentIdentifiers = new ArrayList<>();
private FragmentTransaction currentTransaction = null;
private Fragment currentPrimaryItem = null;
public DynamicFragmentPagerAdapter(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
private int findIndexIfAdded(FragmentIdentifier fragmentIdentifier) {
for (int i = 0, size = fragmentIdentifiers.size(); i < size; i++) {
FragmentIdentifier identifier = fragmentIdentifiers.get(i);
if (identifier.fragmentTag.equals(fragmentIdentifier.fragmentTag)) {
return i;
}
}
return -1;
}
public void addFragment(FragmentIdentifier fragmentIdentifier) {
if (findIndexIfAdded(fragmentIdentifier) < 0) {
fragmentIdentifiers.add(fragmentIdentifier);
notifyDataSetChanged();
}
}
public void removeFragment(FragmentIdentifier fragmentIdentifier) {
int index = findIndexIfAdded(fragmentIdentifier);
if (index >= 0) {
fragmentIdentifiers.remove(index);
notifyDataSetChanged();
}
}
@Override
public int getCount() {
return fragmentIdentifiers.size();
}
@Override
public void startUpdate(@NonNull ViewGroup container) {
if (container.getId() == View.NO_ID) {
throw new IllegalStateException("ViewPager with adapter " + this
+ " requires a view id");
}
}
@SuppressWarnings("ReferenceEquality")
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
if (currentTransaction == null) {
currentTransaction = fragmentManager.beginTransaction();
}
final FragmentIdentifier fragmentIdentifier = fragmentIdentifiers.get(position);
// Do we already have this fragment?
final String name = fragmentIdentifier.fragmentTag;
Fragment fragment = fragmentManager.findFragmentByTag(name);
if (fragment != null) {
currentTransaction.attach(fragment);
} else {
fragment = fragmentIdentifier.newFragment();
currentTransaction.add(container.getId(), fragment, fragmentIdentifier.fragmentTag);
}
if (fragment != currentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (currentTransaction == null) {
currentTransaction = fragmentManager.beginTransaction();
}
currentTransaction.detach((Fragment) object);
}
@SuppressWarnings("ReferenceEquality")
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment) object;
if (fragment != currentPrimaryItem) {
if (currentPrimaryItem != null) {
currentPrimaryItem.setMenuVisibility(false);
currentPrimaryItem.setUserVisibleHint(false);
}
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
currentPrimaryItem = fragment;
}
}
@Override
public void finishUpdate(@NonNull ViewGroup container) {
if (currentTransaction != null) {
currentTransaction.commitNowAllowingStateLoss();
currentTransaction = null;
}
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return ((Fragment) object).getView() == view;
}
@Override
public Parcelable saveState() {
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("fragmentIdentifiers", fragmentIdentifiers);
return bundle;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
Bundle bundle = ((Bundle)state);
bundle.setClassLoader(loader);
fragmentIdentifiers = bundle.getParcelableArrayList("fragmentIdentifiers");
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.