Android
ViewPager
Ricerca…
introduzione
ViewPager è un gestore di layout che consente all'utente di capovolgere a sinistra ea destra tra le pagine di dati. Viene spesso utilizzato insieme a Fragment, che è un modo conveniente per fornire e gestire il ciclo di vita di ciascuna pagina.
Osservazioni
Una cosa importante da notare sull'utilizzo di ViewPager è che ci sono due diverse versioni di FragmentPagerAdapter
e FragmentStatePagerAdapter
.
Se si utilizza android.app.Fragment
Frammenti nativi con un FragmentPagerAdapter o FragmentStatePagerAdapter, è necessario utilizzare le versioni di libreria di supporto V13 della scheda, ovvero android.support.v13.app.FragmentStatePagerAdapter
.
Se si sta utilizzando la libreria di supporto android.support.v4.app.Fragment
Fragments con FragmentPagerAdapter o FragmentStatePagerAdapter, è necessario utilizzare le versioni della libreria di supporto v4 dell'adattatore, ad esempio android.support.v4.app.FragmentStatePagerAdapter
.
Utilizzo di base ViewPager con frammenti
Un ViewPager
consente di mostrare più frammenti in un'attività che può essere esplorata ruotando verso sinistra o verso destra. Un ViewPager
deve essere alimentato con Views o Fragments usando un PagerAdapter
.
Esistono tuttavia due implementazioni più specifiche che troverete più utili in caso di utilizzo di Fragments che sono FragmentPagerAdapter
e FragmentStatePagerAdapter
. Quando un frammento deve essere istanziato per la prima volta, getItem(position)
sarà chiamato per ogni posizione che ha bisogno di istanziare. Il metodo getCount()
restituirà il numero totale di pagine in modo che ViewPager
sappia quanti frammenti devono essere mostrati.
Sia FragmentPagerAdapter
che FragmentStatePagerAdapter
conservano una cache dei Frammenti che il ViewPager
dovrà mostrare. Per impostazione predefinita, ViewPager
tenterà di memorizzare un massimo di 3 frammenti che corrispondono al frammento attualmente visibile e quelli accanto a destra e a sinistra. Anche FragmentStatePagerAdapter
manterrà lo stato di ciascuno dei tuoi frammenti.
Sappi che entrambe le implementazioni presuppongono che i tuoi frammenti manterranno le loro posizioni, quindi se mantieni un elenco dei frammenti invece di avere un numero statico di essi come puoi vedere nel metodo getItem()
, dovrai creare una sottoclasse di PagerAdapter
e sovrascrive almeno i metodi instantiateItem()
, destroyItem()
e getItemPosition()
.
Basta aggiungere un ViewPager nel layout come descritto nell'esempio di base :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vpPager">
</android.support.v4.view.ViewPager>
</LinearLayout>
Quindi definire l'adattatore che determinerà il numero di pagine esistenti e il frammento da visualizzare per ciascuna pagina dell'adattatore.
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;
}
}
}
Se stai usando android.app.Fragment
devi aggiungere questa dipendenza:
compile 'com.android.support:support-v13:25.3.1'
Se stai usando android.support.v4.app.Fragment
devi aggiungere questa dipendenza:
compile 'com.android.support:support-fragment:25.3.1'
ViewPager con TabLayout
Un TabLayout
può essere utilizzato per una navigazione più semplice.
È possibile impostare le schede per ciascun frammento nell'adattatore utilizzando il metodo TabLayout.newTab()
, ma esiste un altro metodo più conveniente e più semplice per questa attività, che è TabLayout.setupWithViewPager()
.
Questo metodo si sincronizza creando e rimuovendo le schede in base al contenuto dell'adattatore associato a ViewPager
ogni volta che viene chiamato.
Inoltre, imposterà una richiamata in modo che ogni volta che l'utente gira la pagina, verrà selezionata la scheda corrispondente.
Basta definire un layout
<?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>
Quindi implementa FragmentPagerAdapter
e applicalo a 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 con PreferenceFragment
Fino a poco tempo fa, l'utilizzo di android.support.v4.app.FragmentPagerAdapter
avrebbe impedito l'utilizzo di PreferenceFragment
come uno dei frammenti utilizzati in FragmentPagerAdapter.
Le ultime versioni della libreria di supporto v7 ora includono la classe PreferenceFragmentCompat
, che funzionerà con ViewPager e la versione v4 di FragmentPagerAdapter.
Esempio di frammento che estende 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) {
}
}
Ora puoi usare questo frammento in una sottoclasse 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;
}
}
// .......
}
Aggiunta di un ViewPager
Assicurati che la seguente dipendenza venga aggiunta al file build.gradle
dell'app in dipendenze:
compile 'com.android.support:support-core-ui:25.3.0'
Quindi aggiungi ViewPager
al tuo layout delle attività:
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Quindi definisci il tuo 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;
}
}
Infine, imposta ViewPager
nella tua attività:
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 con un indicatore di punti
Tutto ciò di cui abbiamo bisogno sono: ViewPager , TabLayout e 2 drawable per punti selezionati e predefiniti.
In primo luogo, dobbiamo aggiungere TabLayout
al nostro layout dello schermo e collegarlo a ViewPager
. Possiamo farlo in due modi:
TabLayout nidificato in 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>
In questo caso,
TabLayout
verrà automaticamente collegato aViewPager
, maTabLayout
sarà accanto aViewPager
, non su di lui.
TabLayout separato
<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"/>
In questo caso, possiamo mettere
TabLayout
ovunque, ma dobbiamo collegareTabLayout
conViewPager
a livello diViewPager
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);
Una volta creato il nostro layout, dobbiamo preparare i nostri punti. Quindi creiamo tre file: selected_dot.xml
, default_dot.xml
e 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>
Ora abbiamo bisogno di aggiungere solo 3 linee di codice a TabLayout
nel nostro layout xml e il gioco è fatto.
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
Imposta OnPageChangeListener
Se è necessario ascoltare le modifiche alla pagina selezionata, è possibile implementare il listener ViewPager.OnPageChangeListener
sul 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
}
});