Reputation: 5480
Although I can scroll in the ViewPager
, the physical fragments themselves are not visible for some reason.
FYI - I have an Activity with tabs using a ViewPager. Inside the first tab/fragment, I have the code below. So essentially, I have an App with a ViewPager controlling the tabs and there's another ViewPager inside one of the Tabs which is to control a bunch of images. I have tested the Fragment in question by putting it inside the top level view pager and it works perfectly fine! It's only when I put it inside the view pager in question does it not render anything...
So, this is the hierarchy for a better understanding:
MainActivity has a ...
ViewPager (3 fragments showing the tab content) has a ...
1st TabFragment has a ...
ViewPager (3 fragments showing images) <--- I can't see these, but I can swipe on them for some reason.
Unfortunately... None of the Fragments are visible, HOWEVER... I can still swipe for some reason to the last fragment...Just nothing is visibly shown...
Layout with the ViewPager inside:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Code with ViewPager
final List<Fragment> imageFragments = new ArrayList<>();
for (final UserImage userImage : user.getImages()) {
final SizeImage processed = userImage.getProcessed();
imageFragments.add(UserImageFragment.newInstance(processed.getFullsize()));
}
final ImagesPagerAdapter imagesAdapter = new ImagesPagerAdapter(getFragmentManager(), imageFragments);
viewPager.setAdapter(imagesAdapter);
The PagerAdapter:
public class ImagesPagerAdapter extends FragmentStatePagerAdapter {
@NonNull
private List<Fragment> fragments;
public ImagesPagerAdapter(@NonNull final FragmentManager fragmentManager,
@NonNull final List<Fragment> fragments) {
super(fragmentManager);
this.fragments = fragments;
}
@Override
public Fragment getItem(final int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
The Fragment:
public class UserImageFragment extends Fragment {
@BindView(R.id.image_view)
ImageView imageView;
public static UserImageFragment newInstance(final String url) {
final UserImageFragment fragment = new UserImageFragment();
Bundle args = new Bundle();
args.putString("url", url);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_user_image, container, false);
ButterKnife.bind(this, view);
final Bundle arguments = getArguments();
if (arguments != null) {
final String url = arguments.getString("url", null);
if (url != null) {
final Uri uri = Uri.parse(url);
Picasso.with(getActivity()).load(url).into(imageView, new Callback() {
@Override
public void onSuccess() {
Toast.makeText(getActivity(), "Success", Toast.LENGTH_SHORT).show();
}
@Override
public void onError() {
Toast.makeText(getActivity(), "Fail", Toast.LENGTH_SHORT).show();
}
});
}
}
return view;
}
}
And here is xml code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/md_red_900">
<ImageView
android:id="@+id/image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@color/md_yellow_500" />
</RelativeLayout>
Upvotes: 0
Views: 1294
Reputation: 2769
To show Fragments inside another Fragment, use getChildFragmentManager() instead of getFragmentManager()
final ImagesPagerAdapter imagesAdapter = new
ImagesPagerAdapter(getChildFragmentManager(), imageFragments);
viewPager.setAdapter(imagesAdapter);
Upvotes: 3
Reputation: 38223
It may not be obvious at first sight but don't try to cache or prepare fragments for a fragment adapter. Fragment(State)PagerAdapter.getItem
has to return a new item and when the method is called is managed internally by the adapter.
Let the fragment adapter have data it needs to construct fragments at the right time:
final List<UserImage> userImages = user.getImages();
final ImagesPagerAdapter imagesAdapter = new ImagesPagerAdapter(getFragmentManager(), userImages);
viewPager.setAdapter(imagesAdapter);
And implement the fragment adapter so that getItem
returns a new fragment:
public class ImagesPagerAdapter extends FragmentStatePagerAdapter {
@NonNull
private List<UserImage> userImages;
public ImagesPagerAdapter(@NonNull final FragmentManager fragmentManager,
@NonNull final List<UserImage> userImages) {
super(fragmentManager);
this.userImages = userImages;
}
@Override
public Fragment getItem(final int position) {
final UserImage userImage = userImages.get(position);
final SizeImage processed = userImage.getProcessed();
return UserImageFragment.newInstance(processed.getFullsize())
}
@Override
public int getCount() {
return userImages.size();
}
}
Here I see two options for improvement:
Replace List<UserImage>
with List<SizeImage>
or List<whatever getFullSize returns>
. The less implementation details you leak to the adapter the better.
If userImage.getProcessed().getFullsize()
takes time (accesses disk, performs computation) do that asynchronously in one of UserImageFragment
lifecycle methods - defer to when it's needed and don't block UI thread.
Neither FragmentPagerAdapter
nor FragmentStatePagerAdapter
are built with updates in mind so
userImages
list.Upvotes: 0