简体   繁体   English

如何使用不同的 Fragments / Layouts 实现 ViewPager

[英]How to implement a ViewPager with different Fragments / Layouts

When I start an activity which implements viewpager, the viewpager created various fragments.当我启动一个实现 viewpager 的活动时,viewpager 创建了各种片段。 I want to use different layouts for each fragment, but the problem is that viewpager shows only two layouts at the max (second layout on all of the remaining fragments after 1).我想为每个片段使用不同的布局,但问题是 viewpager 最多只显示两个布局(1 之后所有剩余片段的第二个布局)。

Here is the code for SwipeActivity which implements the viewpager:这是实现 viewpager 的SwipeActivity的代码:

public class SwipeActivity extends FragmentActivity
{

    MyPageAdapter pageAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_swipe);
        pageAdapter = new MyPageAdapter(getSupportFragmentManager());
        ViewPager pager=(ViewPager)findViewById(R.id.pager);
        pager.setAdapter(pageAdapter);
        ActionBar bar = getActionBar();
        bar.setDisplayHomeAsUpEnabled(true);
    }
    /**
    * Custom Page adapter
    */
    private class MyPageAdapter extends FragmentPagerAdapter
    {
        public MyPageAdapter(FragmentManager fm)
        {
            super(fm);
        }
        @Override
        public int getCount()
        {
            return 5;
        }
        @Override
        public Fragment getItem(int position)
        {
            switch(position)
            {
                case 0: return new MyFragment();
                case 1: return SecondFragment.newInstance("asdasd");
                default : return RamFragment.newInstance("s");
            }
        }
     }
}

Here is the code for the fragments这是片段的代码

public class MyFragment extends Fragment
{
   @Override
   public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup,    Bundle paramBundle)
   {
     return paramLayoutInflater.inflate(R.layout.processorlayout, paramViewGroup, false);
   }
}

I used 5 fragments like this, all having different layouts, but the viewpager shows only 2 at the max.我使用了 5 个这样的片段,它们都有不同的布局,但 viewpager 最多只显示 2 个。

EDIT : code for SecondFragment编辑:SecondFragment 的代码

public class SecondFragment extends Fragment
{
   public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";

  public static final SecondFragment newInstance(String paramString)
  {
    SecondFragment f = new SecondFragment();
    Bundle localBundle = new Bundle(1);
    localBundle.putString("EXTRA_MESSAGE", paramString);
    f.setArguments(localBundle);
    return f;
  }

  @Override
  public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle)
  {
     return paramLayoutInflater.inflate(R.layout.motherboardlayout, paramViewGroup, false);
  }
}

As this is a very frequently asked question, I wanted to take the time and effort to explain the ViewPager with multiple Fragments and Layouts in detail.由于这是一个非常常见的问题,我想花时间和精力详细解释具有多个片段和布局的 ViewPager。 Here you go.干得好。

ViewPager with multiple Fragments and Layout files - How To具有多个片段和布局文件的 ViewPager - 如何

The following is a complete example of how to implement a ViewPager with different fragment Types and different layout files.下面是一个完整的例子,说明如何使用不同的fragment Types和不同的布局文件来实现一个ViewPager。

In this case, I have 3 Fragment classes, and a different layout file for each class.在这种情况下,我有 3 个 Fragment 类,每个类都有一个不同的布局文件。 In order to keep things simple, the fragment-layouts only differ in their background color .为了简单起见,片段布局仅在背景颜色上有所不同 Of course, any layout-file can be used for the Fragments.当然,任何布局文件都可以用于片段。

FirstFragment.java has a orange background layout, SecondFragment.java has a green background layout and ThirdFragment.java has a red background layout. FirstFragment.java 的背景布局为橙色,SecondFragment.java 的背景布局为绿色,而 ThirdFragment.java 的背景布局为红色 Furthermore, each Fragment displays a different text, depending on which class it is from and which instance it is.此外,每个 Fragment 显示不同的文本,具体取决于它来自哪个类以及它是哪个实例。

Also be aware that I am using the support-library's Fragment: android.support.v4.app.Fragment另请注意,我正在使用支持库的片段: android.support.v4.app.Fragment

MainActivity.java (Initializes the Viewpager and has the adapter for it as an inner class). MainActivity.java (初始化 Viewpager 并将其适配器作为内部类)。 Again have a look at the imports .再看看进口 I am using the android.support.v4 package.我正在使用android.support.v4包。

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class MainActivity extends FragmentActivity {

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

        ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
        pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
    }

    private class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int pos) {
            switch(pos) {

            case 0: return FirstFragment.newInstance("FirstFragment, Instance 1");
            case 1: return SecondFragment.newInstance("SecondFragment, Instance 1");
            case 2: return ThirdFragment.newInstance("ThirdFragment, Instance 1");
            case 3: return ThirdFragment.newInstance("ThirdFragment, Instance 2");
            case 4: return ThirdFragment.newInstance("ThirdFragment, Instance 3");
            default: return ThirdFragment.newInstance("ThirdFragment, Default");
            }
        }

        @Override
        public int getCount() {
            return 5;
        }       
    }
}

activity_main.xml (The MainActivitys .xml file) - a simple layout file, only containing the ViewPager that fills the whole screen. activity_main.xml (MainActivitys .xml 文件)——一个简单的布局文件,只包含填充整个屏幕的 ViewPager。

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/viewPager"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />

The Fragment classes, FirstFragment.java import android.support.v4.app.Fragment; Fragment 类, FirstFragment.java import android.support.v4.app.Fragment;

public class FirstFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.first_frag, container, false);

        TextView tv = (TextView) v.findViewById(R.id.tvFragFirst);
        tv.setText(getArguments().getString("msg"));

        return v;
    }

    public static FirstFragment newInstance(String text) {

        FirstFragment f = new FirstFragment();
        Bundle b = new Bundle();
        b.putString("msg", text);

        f.setArguments(b);

        return f;
    }
}

first_frag.xml first_frag.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_orange_dark" >

    <TextView
        android:id="@+id/tvFragFirst"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textSize="26dp"
        android:text="TextView" />
</RelativeLayout>

SecondFragment.java第二个片段.java

public class SecondFragment extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.second_frag, container, false);

    TextView tv = (TextView) v.findViewById(R.id.tvFragSecond);
    tv.setText(getArguments().getString("msg"));

    return v;
}

public static SecondFragment newInstance(String text) {

    SecondFragment f = new SecondFragment();
    Bundle b = new Bundle();
    b.putString("msg", text);

    f.setArguments(b);

    return f;
}
}

second_frag.xml第二个片段.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_green_dark" >

    <TextView
        android:id="@+id/tvFragSecond"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textSize="26dp"
        android:text="TextView" />

</RelativeLayout>

ThirdFragment.java第三个片段.java

public class ThirdFragment extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.third_frag, container, false);

    TextView tv = (TextView) v.findViewById(R.id.tvFragThird);      
    tv.setText(getArguments().getString("msg"));

    return v;
}

public static ThirdFragment newInstance(String text) {

    ThirdFragment f = new ThirdFragment();
    Bundle b = new Bundle();
    b.putString("msg", text);

    f.setArguments(b);

    return f;
}
}

third_frag.xml第三个片段.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_red_light" >

    <TextView
        android:id="@+id/tvFragThird"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textSize="26dp"
        android:text="TextView" />

</RelativeLayout>

The end result is the following:最终结果如下:

The Viewpager holds 5 Fragments, Fragments 1 is of type FirstFragment, and displays the first_frag.xml layout, Fragment 2 is of type SecondFragment and displays the second_frag.xml, and Fragment 3-5 are of type ThirdFragment and all display the third_frag.xml. Viewpager有5个Fragment,Fragment 1是FirstFragment类型,显示first_frag.xml布局,Fragment 2是SecondFragment类型,显示second_frag.xml,Fragment 3-5是ThirdFragment类型,都显示third_frag.xml .

在此处输入图片说明

Above you can see the 5 Fragments between which can be switched via swipe to the left or right.在上面你可以看到 5 个 Fragment,它们之间可以通过向左或向右滑动来切换。 Only one Fragment can be displayed at the same time of course.当然只能同时显示一个 Fragment。

Last but not least:最后但并非最不重要的:

I would recommend that you use an empty constructor in each of your Fragment classes.我建议您在每个 Fragment 类中使用一个空的构造函数

Instead of handing over potential parameters via constructor, use the newInstance(...) method and the Bundle for handing over parameters.不是通过构造函数传递潜在参数,而是使用newInstance(...)方法和Bundle来传递参数。

This way if detached and re-attached the object state can be stored through the arguments.这样,如果分离并重新附加,则可以通过参数存储对象状态。 Much like Bundles attached to Intents .很像附加到Intents Bundles

Create an array of Views and apply it to: container.addView(viewarr[position]);创建一个视图数组并将其应用于: container.addView(viewarr[position]);

public class Layoutes extends PagerAdapter {

    private Context context;
    private LayoutInflater layoutInflater;
    Layoutes(Context context){
        this.context=context;
    }
    int layoutes[]={R.layout.one,R.layout.two,R.layout.three};
    @Override
    public int getCount() {
        return layoutes.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return (view==(LinearLayout)object);
    }
    @Override
    public Object instantiateItem(ViewGroup container, int position){
        layoutInflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View one=layoutInflater.inflate(R.layout.one,container,false);
        View two=layoutInflater.inflate(R.layout.two,container,false);
        View three=layoutInflater.inflate(R.layout.three,container,false);
        View viewarr[]={one,two,three};
        container.addView(viewarr[position]);
        return viewarr[position];
    }
    @Override
    public void destroyItem(ViewGroup container, int position, Object object){
        container.removeView((LinearLayout) object);
    }

}

Code for adding fragment添加片段的代码

public Fragment getItem(int position) {

    switch (position){
        case 0:
            return new Fragment1();

        case 1:
            return new Fragment2();

        case 2:
            return new Fragment3();

        case 3:
            return new Fragment4();

        default:
            break;
    }

    return null;
}

Create an xml file for each fragment say for Fragment1, use fragment_one.xml as layout file, use the below code in Fragment1 java file.为每个片段创建一个 xml 文件,例如 Fragment1,使用 fragment_one.xml 作为布局文件,在 Fragment1 java 文件中使用以下代码。

public class Fragment1 extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_one, container, false);

        return view;

    }
}

Later you can make necessary corrections.. It worked for me.稍后您可以进行必要的更正..它对我有用。

Basic ViewPager Example基本 ViewPager 示例

This answer is a simplification of the documentation , this tutorial , and the accepted answer .此答案是对文档本教程已接受答案的简化。 It's purpose is to get a working ViewPager up and running as quickly as possible.它的目的是让工作的ViewPager启动并运行。 Further edits can be made after that.之后可以进行进一步的编辑。

在此处输入图片说明

XML XML

Add the xml layouts for the main activity and for each page (fragment).为主活动和每个页面(片段)添加 xml 布局。 In our case we are only using one fragment layout, but if you have different layouts on the different pages then just make one for each of them.在我们的例子中,我们只使用一种片段布局,但是如果您在不同的页面上有不同的布局,那么只需为每个页面制作一个。

activity_main.xml活动_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    tools:context="com.example.verticalviewpager.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

fragment_one.xml fragment_one.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textview"
        android:textSize="30sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Code代码

This is the code for the main activity.这是主要活动的代码。 It includes the PagerAdapter and FragmentOne as inner classes.它包括PagerAdapterFragmentOne作为内部类。 If these get too large or you are reusing them in other places, then you can move them to their own separate classes.如果它们变得太大或者您在其他地方重用它们,那么您可以将它们移动到它们自己的单独类中。

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class MainActivity extends AppCompatActivity {

    static final int NUMBER_OF_PAGES = 2;

    MyAdapter mAdapter;
    ViewPager mPager;

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

        mAdapter = new MyAdapter(getSupportFragmentManager());
        mPager = findViewById(R.id.viewpager);
        mPager.setAdapter(mAdapter);
    }

    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUMBER_OF_PAGES;
        }

        @Override
        public Fragment getItem(int position) {

            switch (position) {
                case 0:
                    return FragmentOne.newInstance(0, Color.WHITE);
                case 1:
                    // return a different Fragment class here
                    // if you want want a completely different layout
                    return FragmentOne.newInstance(1, Color.CYAN);
                default:
                    return null;
            }
        }
    }

    public static class FragmentOne extends Fragment {

        private static final String MY_NUM_KEY = "num";
        private static final String MY_COLOR_KEY = "color";

        private int mNum;
        private int mColor;

        // You can modify the parameters to pass in whatever you want
        static FragmentOne newInstance(int num, int color) {
            FragmentOne f = new FragmentOne();
            Bundle args = new Bundle();
            args.putInt(MY_NUM_KEY, num);
            args.putInt(MY_COLOR_KEY, color);
            f.setArguments(args);
            return f;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mNum = getArguments() != null ? getArguments().getInt(MY_NUM_KEY) : 0;
            mColor = getArguments() != null ? getArguments().getInt(MY_COLOR_KEY) : Color.BLACK;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_one, container, false);
            v.setBackgroundColor(mColor);
            TextView textView = v.findViewById(R.id.textview);
            textView.setText("Page " + mNum);
            return v;
        }
    }
}

Finished完成的

If you copied and pasted the three files above to your project, you should be able to run the app and see the result in the animation above.如果您将上面的三个文件复制并粘贴到您的项目中,您应该能够运行该应用程序并在上面的动画中看到结果。

Going on继续

There are quite a few things you can do with ViewPagers.您可以使用 ViewPagers 做很多事情。 See the following links to get started:请参阅以下链接以开始使用:

This is also fine:这也很好:

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/viewPager"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />
public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
        pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));

    }
}


public class FragmentTab1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragmenttab1, container, false);
        return rootView;
    }
}

class MyPagerAdapter extends FragmentPagerAdapter{

    public MyPagerAdapter(FragmentManager fragmentManager){
        super(fragmentManager);

    }
    @Override
    public android.support.v4.app.Fragment getItem(int position) {
        switch(position){
            case 0:
                FragmentTab1 fm =   new FragmentTab1();
                return fm;
            case 1: return new FragmentTab2();
            case 2: return new FragmentTab3();
        }
        return null;
    }

    @Override
    public int getCount() {
        return 3;
    }
}
<RelativeLayout 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" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/Fragment1" />

</RelativeLayout>

Create new instances in your fragments and do like so in your Activity在您的片段中创建新实例并在您的 Activity 中执行此操作

 private class SlidePagerAdapter extends FragmentStatePagerAdapter {
    public SlidePagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch(position){
            case 0:
                return Fragment1.newInstance();
            case 1:
                return Fragment2.newInstance();
            case 2:
                return Fragment3.newInstance();
            case 3:
                return Fragment4.newInstance();


            default: break;

        }
        return null;
    }

2021 answer using Kotlin, ViewPager2, and RecyclerView.Adapter... 2021 年答案使用 Kotlin、ViewPager2 和 RecyclerView.Adapter...

RecyclerView.Adapter doesn't use getItem(), but has a method getItemViewType(). RecyclerView.Adapter 不使用 getItem(),但有一个方法 getItemViewType()。 You can override this method to inform onCreateViewHolder() which layout to use.您可以覆盖此方法以通知 onCreateViewHolder() 使用哪个布局。

class SettingsAdapter(val activity: AppCompatActivity): RecyclerView.Adapter<SettingsAdapter.SettingsViewHolder>()
{
    // Page names
    private val pageName = arrayOf("General", "Privacy Policy", "Terms of Use", "Feedback")
    private val pageResource = arrayOf(R.layout.fragment_general, R.layout.fragment_privacy, R.layout.fragment_terms, R.layout.fragment_feedback)
    private val pageCount = pageName.size

    override fun getItemCount(): Int {
        return pageCount
    }

    override fun getItemViewType(position: Int): Int {
        return position
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingsAdapter.SettingsViewHolder
    {
        val context = parent.context
        val inflater = LayoutInflater.from(context)
        val settingsView = inflater.inflate(pageResource[viewType], parent, false)
        return SettingsViewHolder(settingsView)
    }
}

Then you can handle each layout differently in the onBindViewHolder() method.然后您可以在 onBindViewHolder() 方法中以不同方式处理每个布局。

Kotlin code using FragmentStateAdapter Kotlin 代码使用 FragmentStateAdapter

  • Adapter Code适配器代码
class Adapter(activity: YourActivity):FragmentStateAdapter(activity) {

    override fun getItemCount(): Int {
        return 2  // number of Fragments to be displayed here: (0,1)
    }

    override fun createFragment(position: Int): Fragment = when (position) {
        0 -> Frag1.newInstance()
        1 -> Frag2.newInstance()
        else -> throw IllegalStateException("Invalid adapter position")
    }
} 
  • ViewPager2 XML code ViewPager2 XML代码
<androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:orientation="vertical"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_height="match_parent"
        android:layout_width="match_parent"/>

Only writing this for someone who comes by and needs latest code in Kotlin.只为路过并需要 Kotlin 最新代码的人写这篇文章。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM