Android
ViewPager
Szukaj…
Wprowadzenie
ViewPager to menedżer układu, który pozwala użytkownikowi przewijać strony danych w lewo i prawo. Najczęściej jest używany w połączeniu z Fragment, który jest wygodnym sposobem dostarczania i zarządzania cyklem życia każdej strony.
Uwagi
Jedną ważną rzeczą, na którą należy zwrócić uwagę przy korzystaniu z ViewPager, jest to, że istnieją dwie różne wersje zarówno FragmentPagerAdapter
jak i FragmentStatePagerAdapter
.
Jeśli używasz rodzimych fragmentów android.app.Fragment
z FragmentPagerAdapter lub FragmentStatePagerAdapter, musisz użyć wersji biblioteki obsługi v13 adaptera, tj. android.support.v13.app.FragmentStatePagerAdapter
.
Jeśli korzystasz z biblioteki obsługi android.support.v4.app.Fragment
Fragmenty z FragmentPagerAdapter lub FragmentStatePagerAdapter, musisz użyć wersji biblioteki wsparcia v4 adaptera, tj. android.support.v4.app.FragmentStatePagerAdapter
.
Podstawowe użycie ViewPager z fragmentami
ViewPager
pozwala pokazać wiele fragmentów w działaniu, którym można nawigować, przesuwając w lewo lub w prawo. ViewPager
musi być podawany jako widok lub fragment za pomocą PagerAdapter
.
Istnieją jednak dwie bardziej szczegółowe implementacje, które okażą się najbardziej przydatne w przypadku korzystania z Fragmentów, które są FragmentPagerAdapter
i FragmentStatePagerAdapter
. Kiedy Fragment musi zostać utworzony po raz pierwszy, getItem(position)
zostanie wywołany dla każdej pozycji, która wymaga utworzenia. Metoda getCount()
zwróci całkowitą liczbę stron, aby ViewPager
wiedział, ile fragmentów należy wyświetlić.
Zarówno FragmentPagerAdapter
jak i FragmentStatePagerAdapter
przechowują pamięć podręczną fragmentów, które ViewPager
będzie musiał wyświetlić. Domyślnie ViewPager
będzie próbował zapisać maksymalnie 3 Fragmenty, które odpowiadają aktualnie widocznemu Fragmentowi, i te obok prawej i lewej. FragmentStatePagerAdapter
zachowa stan każdego z twoich fragmentów.
Należy pamiętać, że obie implementacje zakładają, że twoje fragmenty zachowają swoje pozycje, więc jeśli getItem()
listę fragmentów zamiast mieć ich statyczną liczbę, jak widać w getItem()
, musisz utworzyć podklasę PagerAdapter
i przesłonić przynajmniej metody instantiateItem()
, destroyItem()
i getItemPosition()
.
Wystarczy dodać ViewPager do swojego układu, jak opisano w podstawowym przykładzie :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vpPager">
</android.support.v4.view.ViewPager>
</LinearLayout>
Następnie zdefiniuj adapter, który określi, ile stron istnieje i jaki fragment ma zostać wyświetlony dla każdej strony adaptera.
public class MyViewPagerActivity extends AppCompatActivity {
private static final String TAG = MyViewPagerActivity.class.getName();
private MyPagerAdapter mFragmentAdapter;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myActivityLayout);
//Apply the Adapter
mFragmentAdapter = new MyPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mViewPager.setAdapter(mFragmentAdapter);
}
private class MyPagerAdapter extends FragmentPagerAdapter{
public MyPagerAdapter(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
case 2:
return new Fragment3();
default:
return null;
}
}
// Returns total number of pages
@Override
public int getCount() {
return 3;
}
}
}
Jeśli używasz android.app.Fragment
, musisz dodać tę zależność:
compile 'com.android.support:support-v13:25.3.1'
Jeśli używasz android.support.v4.app.Fragment
, musisz dodać tę zależność:
compile 'com.android.support:support-fragment:25.3.1'
ViewPager z TabLayout
TabLayout
może służyć do łatwiejszej nawigacji.
Możesz ustawić tabulatory dla każdego fragmentu w adapterze, używając metody TabLayout.newTab()
, ale istnieje inna wygodniejsza i łatwiejsza metoda dla tego zadania, którą jest TabLayout.setupWithViewPager()
.
Ta metoda zostanie zsynchronizowana poprzez tworzenie i usuwanie kart zgodnie z zawartością adaptera powiązanego z ViewPager
każdym razem, gdy go wywołasz.
Ponadto ustawi oddzwonienie, więc za każdym razem, gdy użytkownik przewróci stronę, wybierana będzie odpowiednia karta.
Po prostu zdefiniuj układ
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
app:tabMode="scrollable" />
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1" />
</LinearLayout>
Następnie zaimplementuj FragmentPagerAdapter
i zastosuj go do ViewPager
:
public class MyViewPagerActivity extends AppCompatActivity {
private static final String TAG = MyViewPagerActivity.class.getName();
private MyPagerAdapter mFragmentAdapter;
private ViewPager mViewPager;
private TabLayout mTabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myActivityLayout);
// Get the ViewPager and apply the PagerAdapter
mFragmentAdapter = new MyPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mViewPager.setAdapter(mFragmentAdapter);
// link the tabLayout and the viewpager together
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.setupWithViewPager(mViewPager);
}
private class MyPagerAdapter extends FragmentPagerAdapter{
public MyPagerAdapter(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new Fragment1();
case 1:
return new Fragment2();
case 2:
return new Fragment3();
default:
return null;
}
}
// Will be displayed as the tab's label
@Override
public CharSequence getPageTitle(int position) {
switch(position) {
case 0:
return "Fragment 1 title";
case 1:
return "Fragment 2 title";
case 2:
return "Fragment 3 title";
default:
return null;
}
}
// Returns total number of pages
@Override
public int getCount() {
return 3;
}
}
}
ViewPager z PreferenceFragment
Do niedawna użycie android.support.v4.app.FragmentPagerAdapter
uniemożliwiało użycie PreferenceFragment
jako jednego z fragmentów używanych w FragmentPagerAdapter.
Najnowsze wersje biblioteki obsługi v7 zawierają teraz klasę PreferenceFragmentCompat
, która będzie współpracować z ViewPager i wersją v4 FragmentPagerAdapter.
Przykład fragmentu, który rozszerza PreferenceFragmentCompat
:
import android.os.Bundle;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.view.View;
public class MySettingsPrefFragment extends PreferenceFragmentCompat {
public MySettingsPrefFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.fragment_settings_pref);
}
@Override
public void onCreatePreferences(Bundle bundle, String s) {
}
}
Możesz teraz używać tego fragmentu w podklasie android.support.v4.app.FragmentPagerAdapter
:
private class PagerAdapterWithSettings extends FragmentPagerAdapter {
public PagerAdapterWithSettings(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new FragmentOne();
case 1:
return new FragmentTwo();
case 2:
return new MySettingsPrefFragment();
default:
return null;
}
}
// .......
}
Dodawanie ViewPager
Upewnij się, że do pliku build.gradle
aplikacji w zależnościach dodano następującą zależność:
compile 'com.android.support:support-core-ui:25.3.0'
Następnie dodaj ViewPager
do układu aktywności:
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Następnie zdefiniuj swój PagerAdapter
:
public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
public CustomPagerAdapter(Context context) {
mContext = context;
}
@Override
public Object instantiateItem(ViewGroup collection, int position) {
// Create the page for the given position. For example:
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.xxxx, collection, false);
collection.addView(layout);
return layout;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view) {
// Remove a page for the given position. For example:
collection.removeView((View) view);
}
@Override
public int getCount() {
//Return the number of views available.
return numberOfPages;
}
@Override
public boolean isViewFromObject(View view, Object object) {
// Determines whether a page View is associated with a specific key object
// as returned by instantiateItem(ViewGroup, int). For example:
return view == object;
}
}
Na koniec skonfiguruj ViewPager
w swojej aktywności:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new MyPagerAdapter(this));
}
}
ViewPager ze wskaźnikiem kropek
Potrzebujemy tylko: ViewPager , TabLayout i 2 drawable dla wybranych i domyślnych kropek.
Po pierwsze, musimy dodać TabLayout
do naszego układu ekranu i połączyć go z ViewPager
. Możemy to zrobić na dwa sposoby:
Zagnieżdżony TabLayout w ViewPager
<android.support.v4.view.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.view.ViewPager>
W takim przypadku
TabLayout
zostanie automatycznie połączony zViewPager
, aleTabLayout
będzie obokViewPager
, a nie nad nim.
Oddzielny tabLayout
<android.support.v4.view.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
W takim przypadku możemy umieścić
TabLayout
dowolnym miejscu, ale musimy połączyćTabLayout
zViewPager
programowo
ViewPager pager = (ViewPager) view.findViewById(R.id.photos_viewpager);
PagerAdapter adapter = new PhotosAdapter(getChildFragmentManager(), photosUrl);
pager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(pager, true);
Po stworzeniu naszego układu musimy przygotować nasze kropki. Tworzymy więc trzy pliki: selected_dot.xml
, default_dot.xml
i tab_selector.xml
.
selected_dot.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@color/colorAccent"/>
</shape>
</item>
</layer-list>
default_dot.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
</layer-list>
tab_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/selected_dot"
android:state_selected="true"/>
<item android:drawable="@drawable/default_dot"/>
</selector>
Teraz musimy dodać tylko 3 linie kodu do TabLayout
w naszym układzie xml i gotowe.
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
Skonfiguruj OnPageChangeListener
Jeśli trzeba nasłuchiwać zmian wybranego można wdrożyć stronie ViewPager.OnPageChangeListener
słuchacza na ViewPager:
viewPager.addOnPageChangeListener(new OnPageChangeListener() {
// This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
@Override
public void onPageSelected(int position) {
// Your code
}
// This method will be invoked when the current page is scrolled, either as part of
// a programmatically initiated smooth scroll or a user initiated touch scroll.
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Your code
}
// Called when the scroll state changes. Useful for discovering when the user begins
// dragging, when the pager is automatically settling to the current page,
// or when it is fully stopped/idle.
@Override
public void onPageScrollStateChanged(int state) {
// Your code
}
});