FragmentPagerAdapter 到 ViewPager
FragmentPagerAdapter to ViewPager
我不久前开始使用 Android Studio 并学习 Java,现在坚持将适配器应用于不同的 ViewPager。我自己没有足够的知识来解决此类组件的行为问题,非常感谢您的帮助。 (对不起我的英语)
思路是:
1) 一列记录(如 Instagram),可以上下滚动;
2) 每条记录都有图片块,可以左右滚动,还有一个文本块;
它是如何组织的(另见截图):
1) (main.xml) 在主布局(ConstraintLayout) 上有nestedScrollView,其中我包含了LinearLayout (records.xml)。这是记录栏。
2) LinearLayout 循环填充记录(record.xml)。每条记录都是ConstraintLayout,其中包含ViewPager和TextView。
3) 在每个新添加的记录中,我尝试找到 ViewPager,我使用 setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager())) 将适配器设置为它。
4) MyFragmentPagerAdapter 在调用 getItem 时 RecordImageFragment.newInstance,创建新片段 (RecordImageFragment.java)。
5) 每个RecordImageFragment放置FrameLayout(record_images_pager.xml),在里面找到ImageView,把图片放在那里
截图:
app running
project structure
问题是:
所有作品,但图片只能在第一条记录中看到。
创建记录时,我还在那里找到了 TextView (record.xml) 并为其设置了文本。文本因记录而异(这很好),但只有第一条记录中的第一个 ViewPager 有图片。虽然适配器 (MyFragmentPagerAdapter) 在每个 ViewPager 中工作,但 OnPageChangeListener 调用,跟踪位置:0-2。经过研究发现 RecordImageFragment 认为第一条记录是他的 ViewGroup.getRootView().getRootView() (不是适配器设置到的记录)。直到现在我试图弄清楚,为什么片段(RecordImageFragment.java)的内容(record_images_pager.xml)没有添加到适配器设置的 ViewPager,而是添加到第一个。
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;
}
}
终于,经过数小时的搜索和尝试。我找到了答案。问题很微妙。问题出在您的适配器上,您在适配器中使用 FragmentManager
来管理片段。在随后的(第二行或第三行)中,我认为 FragmentPagerAdapter
不会将 getItem()
方法返回的项目视为新片段。所以你根本看不到它们。这可能是因为您使用相同的 FragmentManager
来管理适配器。
解决方案是通过使用基本 PagerAdapter
并自己实现 instantiateItem()
和 destroyItem()
来完全取消 FragmentManager。这消除了对 Fragments 的需求,您可以自己简单地扩充图像视图。
这是您需要用来代替 MyFragmentPagerAdapter
的新 MyPagerAdapter
。
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);
}
}
最后确保替换 pager.setAdapter(new MyFragmentPagerAdapter());
通过 pager.setAdapter(new MyPagerAdapter());
您也不需要 RecordImageFragment
。
在 Android Studio 中测试。
我阅读了 this 作为参考。
提示 - 使用带有自定义适配器的 ListView
而不是简单的 LinearLayout
来放置所有 viewpager 以实现平滑滚动。
我不久前开始使用 Android Studio 并学习 Java,现在坚持将适配器应用于不同的 ViewPager。我自己没有足够的知识来解决此类组件的行为问题,非常感谢您的帮助。 (对不起我的英语)
思路是:
1) 一列记录(如 Instagram),可以上下滚动;
2) 每条记录都有图片块,可以左右滚动,还有一个文本块;
它是如何组织的(另见截图):
1) (main.xml) 在主布局(ConstraintLayout) 上有nestedScrollView,其中我包含了LinearLayout (records.xml)。这是记录栏。
2) LinearLayout 循环填充记录(record.xml)。每条记录都是ConstraintLayout,其中包含ViewPager和TextView。
3) 在每个新添加的记录中,我尝试找到 ViewPager,我使用 setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager())) 将适配器设置为它。
4) MyFragmentPagerAdapter 在调用 getItem 时 RecordImageFragment.newInstance,创建新片段 (RecordImageFragment.java)。
5) 每个RecordImageFragment放置FrameLayout(record_images_pager.xml),在里面找到ImageView,把图片放在那里
截图:
app running
project structure
问题是:
所有作品,但图片只能在第一条记录中看到。 创建记录时,我还在那里找到了 TextView (record.xml) 并为其设置了文本。文本因记录而异(这很好),但只有第一条记录中的第一个 ViewPager 有图片。虽然适配器 (MyFragmentPagerAdapter) 在每个 ViewPager 中工作,但 OnPageChangeListener 调用,跟踪位置:0-2。经过研究发现 RecordImageFragment 认为第一条记录是他的 ViewGroup.getRootView().getRootView() (不是适配器设置到的记录)。直到现在我试图弄清楚,为什么片段(RecordImageFragment.java)的内容(record_images_pager.xml)没有添加到适配器设置的 ViewPager,而是添加到第一个。
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;
}
}
终于,经过数小时的搜索和尝试。我找到了答案。问题很微妙。问题出在您的适配器上,您在适配器中使用 FragmentManager
来管理片段。在随后的(第二行或第三行)中,我认为 FragmentPagerAdapter
不会将 getItem()
方法返回的项目视为新片段。所以你根本看不到它们。这可能是因为您使用相同的 FragmentManager
来管理适配器。
解决方案是通过使用基本 PagerAdapter
并自己实现 instantiateItem()
和 destroyItem()
来完全取消 FragmentManager。这消除了对 Fragments 的需求,您可以自己简单地扩充图像视图。
这是您需要用来代替 MyFragmentPagerAdapter
的新 MyPagerAdapter
。
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);
}
}
最后确保替换 pager.setAdapter(new MyFragmentPagerAdapter());
通过 pager.setAdapter(new MyPagerAdapter());
您也不需要 RecordImageFragment
。
在 Android Studio 中测试。
我阅读了 this 作为参考。
提示 - 使用带有自定义适配器的 ListView
而不是简单的 LinearLayout
来放置所有 viewpager 以实现平滑滚动。