I've started using Android Studio and learning Java not so long ago and now stucked on applying adapters to differen ViewPager. I don't have enough knowledge to solve such components' behaviour problem myself, and will be grateful for your help. (Sorry for my English)
The idea is:
1) A column of records (like in Instagram), which can be scrolled up-down;
2) Each record has block of images, which can be scrolled left-right, and a text block;
How it is organised (see screenshot also):
1) (main.xml) On the main layout (ConstraintLayout) there is nestedScrollView, in which I included LinearLayout (records.xml). This is the column of records.
2) LinearLayout is filled with records in cycle (record.xml). Each record is ConstraintLayout, which contains ViewPager and TextView.
3) In each new added record I try to find ViewPager, whom I set adapter to with setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager())).
4) MyFragmentPagerAdapter when comes to getItem calls RecordImageFragment.newInstance, creating new fragment (RecordImageFragment.java).
5) Each RecordImageFragment places FrameLayout (record_images_pager.xml), finds ImageView in it, and places picture there.
Screenshots:
The problem is:
All works, but pictures are seen only in first record. When record is created, I also find TextView there (record.xml) and set text to it. Texts differs from record to record (that's good) , but only first ViewPager in first record has pictures. Though adapter (MyFragmentPagerAdapter) works in every ViewPager, OnPageChangeListener calls, tracing position: 0-2. After research it turned out that RecordImageFragment thinks that first record is his ViewGroup.getRootView().getRootView() (not the record to which adapter was set to). Till now I try to figure out, why the contents (record_images_pager.xml) of the fragment (RecordImageFragment.java) are added not to the ViewPager, to which adapter was set to, but to the first one.
MainActivity.java
package example;
import android.os.*;
import android.support.v4.app.*;
import android.support.v4.view.*;
import android.support.v7.app.AppCompatActivity;
import android.util.*;
import android.view.*;
import android.widget.*;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
addRecords();
}
public void addRecords()
{
for (int j = 1; j <= 10; j++ )
{
addNewRecord(j);
}
}
public void addNewRecord(int id)
{
LinearLayout records = (LinearLayout) findViewById(R.id.records);
// Add new record
LayoutInflater inflater = getLayoutInflater();
View record = inflater.inflate(R.layout.record, null, false);
records.addView(record);
// Set text to text field
TextView title_tv = (TextView) record.findViewById(R.id.title);
title_tv.setText("Запись " + id);
//Find ViewPager, add adapter and page change listener
ViewPager pager = (ViewPager) record.findViewById(R.id.pager);
pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager()));
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
@Override
public void onPageSelected(int position) { Log.d("example", "Картинка сменилась на: " + position);}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageScrollStateChanged(int state) {}
});
}
private class MyFragmentPagerAdapter extends FragmentPagerAdapter
{
int[] internalPicts = {R.drawable.pict1, R.drawable.pict2, R.drawable.pict3};
public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); }
@Override
public Fragment getItem(int pos) { return RecordImageFragment.newInstance(internalPicts[pos]); }
@Override
public int getCount() {
return internalPicts.length;
}
}
}
RecordImageFragment.java
package example;
import android.os.Bundle;
import android.support.v4.content.*;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
public class RecordImageFragment extends android.support.v4.app.Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layoutWithImage = inflater.inflate(R.layout.record_images_pager, container, false);
//Find ImageView on layout and place drawable there
ImageView image = (ImageView) layoutWithImage.findViewById(R.id.image);
int imgId = getArguments().getInt("img");
image.setImageDrawable(ContextCompat.getDrawable(getActivity(), imgId));
return layoutWithImage;
}
public static RecordImageFragment newInstance(int image) {
RecordImageFragment f = new RecordImageFragment();
Bundle b = new Bundle();
b.putInt("img", image);
f.setArguments(b);
return f;
}
}
Finally, after hours of searching and trying. I've found an answer. The problem is very subtle. The problem lies with your adapter, you're using a FragmentManager
in your adapter to manage the fragments. In the subsequent (second or third rows) I think the FragmentPagerAdapter
doesn't consider the items returned by getItem()
method as new fragments. So you don't see them at all. This could probably be because you're using the same FragmentManager
to manage the adapter.
The solution would be to completely do away with the FragmentManager by using the basic PagerAdapter
and implementing instantiateItem()
and destroyItem()
yourself. This eliminates the needs for Fragments to begin with and you can simply inflate the Image views yourself.
Here's the new MyPagerAdapter
you need to put in place of the MyFragmentPagerAdapter
.
private class MyPagerAdapter extends PagerAdapter {
int[] internalPicts = {R.drawable.dashboard, R.drawable.icon, R.drawable.mockup};
public MyPagerAdapter() {
super();
}
@Override
public int getCount() {
return internalPicts.length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup collection, int position) {
// Inflating layout
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.record_images_pager, null);
ImageView image = (ImageView) view.findViewById(R.id.image);
image.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), internalPicts[position]));
collection.addView(view, 0);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
At the end make sure you replace pager.setAdapter(new MyFragmentPagerAdapter());
by pager.setAdapter(new MyPagerAdapter());
You don't need RecordImageFragment
too.
Tested in Android Studio.
I read this for reference.
Tip - Use ListView
with a custom adapter instead of a simple LinearLayout
to place all your viewpagers for smooth scrolling.