Jak zaimplementować ViewPager z różnymi fragmentami / układami

191

Kiedy rozpoczynam działanie, które implementuje viewpager, viewpager tworzył różne fragmenty. Chcę używać różnych układów dla każdego fragmentu, ale problem polega na tym, że przeglądarka pokazuje maksymalnie dwa układy na maksimum (drugi układ na wszystkich pozostałych fragmentach po 1).

Oto kod SwipeActivity, który implementuje przeglądarkę:

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");
            }
        }
     }
}

Oto kod fragmentów

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

Użyłem 5 takich fragmentów, wszystkie o różnych układach, ale przeglądarka pokazuje tylko 2 maksymalnie.

EDYCJA : kod dla 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);
  }
}
Haxor
źródło
Otrzymuję błąd niedopasowania typu. Czy możesz spojrzeć na mój post? stackoverflow.com/questions/28334800/…
Schardt12
Jaki jest więc problem Twojego kodu?
user1510006
Cześć, możesz przeczytać ten post bardzo prostą odpowiedź z pełnym kodem.
Nirmal Dhara

Odpowiedzi:

517

Ponieważ jest to bardzo często zadawane pytanie, chciałem poświęcić trochę czasu i wysiłku, aby wyjaśnić ViewPager szczegółowo wieloma fragmentami i układami. Proszę bardzo.

ViewPager z wieloma fragmentami i plikami układów - jak to zrobić

Poniżej znajduje się pełny przykład implementacji programu ViewPager z różnymi typami fragmentów i różnymi plikami układu.

W tym przypadku mam 3 klasy fragmentów i inny plik układu dla każdej klasy. W celu uproszczenia układy fragmentów różnią się jedynie kolorem tła . Oczywiście do Fragmentów można użyć dowolnego pliku układu.

FirstFragment.java ma pomarańczowy układ tła, SecondFragment.java ma zielony układ tła, a ThirdFragment.java ma czerwony układ tła. Ponadto każdy fragment wyświetla inny tekst, w zależności od tego, z której klasy pochodzi i w jakiej instancji jest.

Pamiętaj również, że korzystam z fragmentu biblioteki wsparcia: android.support.v4.app.Fragment

MainActivity.java (Inicjuje Viewpager i ma dla niego adapter jako klasę wewnętrzną). Ponownie spójrz na import . Korzystam z android.support.v4pakietu.

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 (plik .xml MainActivitys) - prosty plik układu, zawierający tylko ViewPager, który wypełnia cały ekran.

<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"
    />

Klasy fragmentów, 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

<?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

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 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

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 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>

Wynik końcowy jest następujący:

Viewpager zawiera 5 Fragmentów, Fragmenty 1 są typu FirstFragment i wyświetla układ first_frag.xml, Fragment 2 jest typu SecondFragment i wyświetla second_frag.xml, a Fragment 3-5 są typu ThirdFragment i wszystkie wyświetlają trzeci_frag.xml .

wprowadź opis zdjęcia tutaj

Powyżej widać 5 fragmentów, między którymi można przełączać przesuwając palcem w lewo lub w prawo. Oczywiście tylko jeden fragment może być wyświetlany jednocześnie.

Nie mniej ważny:

Polecam użycie pustego konstruktora w każdej z klas Fragment.

Zamiast przekazywać potencjalne parametry przez konstruktor, użyj newInstance(...)metody iBundle do przekazania parametrów.

W ten sposób po odłączeniu i ponownym podłączeniu stan obiektu można zapisać za pomocą argumentów. Podobnie jak Bundlesprzywiązany do Intents.

Philipp Jahoda
źródło
7
@PhilippJahoda świetna odpowiedź, dzięki. Chciałbym jednak wspomnieć o jednej rzeczy, jeśli ViewPager jest zdefiniowany we fragmencie niż getSupportChildFragmentManager () powinien być używany zamiast getSupportFragmentManager () podczas tworzenia adaptera. W przeciwnym razie kod ulegnie awarii, gdy nastąpi zmiana orientacji.
guy.gc
5
Tak to jest poprawne. Ale w moim przykładzie ViewPager jest zdefiniowany w działaniu, dlatego właściwość getSupportFragmentManager () jest odpowiednia. Ponadto metoda getSupportChildFragmentManager () nie istnieje, zakładam, że odwołujesz się do getChildFragmentManager ().
Philipp Jahoda
1
Podczas korzystania z pakietu obsługi v13 można używać ViewPager z natywnymi fragmentami. developer.android.com/reference/android/support/v13/app/…
Philipp Jahoda
1
Czy w przypadku Androida Lollipop 5.0 jest to nadal aktualne?
Orkun Ozen,
5
W metodzie MyPagerAdapter -> getItem (int pos) zawsze otrzymujesz nową instancję fragmentu docelowego (na podstawie wartości pos). Za każdym razem, gdy obracasz urządzenie (zmiana orientacji), wywoływana jest metoda getItem, a fragmenty są tworzone od nowa. Ale są one zapisywane w menedżerze fragmentów po utworzeniu. Myślę, że powinieneś sprawdzić, czy są już w menedżerze fragmentów, ponieważ jeśli nie marnujesz pamięci. Zobacz pastebin.com/0bJc9mHA
rekt0x
8

Utwórz tablicę widoków i zastosuj ją do: 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);
    }

}
akash ingle
źródło
Możemy nadmuchać układ w ViewPager, tworząc tablicę widoków.
akash ingle
6

Kod dodawania fragmentu

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;
}

Utwórz plik xml dla każdego fragmentu powiedzmy dla Fragment1, użyj fragment_one.xml jako pliku układu, użyj poniższego kodu w pliku Java Fragment1.

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;

    }
}

Później możesz wprowadzić niezbędne poprawki. To zadziałało dla mnie.

sushh
źródło
4

Podstawowy przykład ViewPager

Ta odpowiedź jest uproszczeniem dokumentacji , tego samouczka i przyjętej odpowiedzi . Jego celem jest ViewPagerjak najszybsze uruchomienie i uruchomienie. Następnie można wprowadzić dalsze zmiany.

wprowadź opis zdjęcia tutaj

XML

Dodaj układy xml dla głównej aktywności i każdej strony (fragmentu). W naszym przypadku używamy tylko jednego układu fragmentów, ale jeśli masz różne układy na różnych stronach, po prostu utwórz po jednym dla każdego z nich.

Activity_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

<?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>

Kod

To jest kod głównej aktywności. Obejmuje PagerAdapteri FragmentOnejako klasy wewnętrzne. Jeśli będą zbyt duże lub ponownie wykorzystasz je w innych miejscach, możesz przenieść je do osobnych klas.

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;
        }
    }
}

Skończone

Jeśli skopiowałeś i wkleiłeś trzy powyższe pliki do swojego projektu, powinieneś być w stanie uruchomić aplikację i zobaczyć wynik w powyższej animacji.

Dziać się

Jest wiele rzeczy, które możesz zrobić z ViewPagers. Aby rozpocząć, zobacz następujące łącza:

Suragch
źródło
3

To też dobrze:

<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>
Ashutoshg
źródło
0

Twórz nowe instancje w swoich fragmentach i rób to podobnie w swojej Aktywności

 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;
    }
Mwongera808
źródło