Używam ViewPager
do przesuwania między Fragments
, ale czy mogę używać ViewPager
do przesuwania między Views
prostym układem XML?
To jest moja strona Adapter
dla ViewPagera, który jest używany do przesuwania między fragmentami:
import java.util.List;
import com.app.name.fragments.TipsFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.ViewGroup;
public class PageAdapter extends FragmentPagerAdapter {
/**
*
*/
List<Fragment> fragments;
public PageAdapter(FragmentManager fm,List<Fragment> frags) {
super(fm);
fragments = frags;
}
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return TipsFragment.newInstance(0, 0);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return 4;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
super.destroyItem(container, position, object);
}
}
A oto moja wskazówka:
public class TipsFragment extends Fragment
{
public static TipsFragment newInstance(int image,int content)
{
TipsFragment fragment = new TipsFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tip_layout, null);
return view;
}
}
Jak mogę zmodyfikować kod, aby działał z widokami zamiast fragmentów?
ViewPager
naonDestroy
tym samym naonResume
działalność nie będzie potrzeby, aby pobrać wszystkie 3 fragmenty, które nie mogą już dostępny. Chciałem tylko wspomnieć o jednym z problemów.Odpowiedzi:
Musisz zastąpić te dwie metody, a nie
getItem()
:@Override public Object instantiateItem(ViewGroup collection, int position) { View v = layoutInflater.inflate(...); ... collection.addView(v,0); return v; } @Override public void destroyItem(ViewGroup collection, int position, Object view) { collection.removeView((View) view); }
źródło
ViewPager
w ogóle przesyłać do, ponieważ masz do czynienia zViewGroup
interfejsemSkorzystaj z tego przykładu
Możesz użyć pojedynczego układu XML zagnieżdżającego widoki podrzędne.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/page_one" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:text="PAGE ONE IN" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#fff" android:textSize="24dp"/> </LinearLayout> <LinearLayout android:id="@+id/page_two" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:text="PAGE TWO IN" android:layout_width="match_parent" android:layout_height="match_parent" android:textColor="#fff" android:textSize="24dp"/> </LinearLayout> </android.support.v4.view.ViewPager> </LinearLayout>
ALE ... musisz poradzić sobie z tym również za pomocą adaptera. Tutaj zwracamy znaleziony identyfikator widoku bez nadmuchiwania żadnego innego układu.
class WizardPagerAdapter extends PagerAdapter { public Object instantiateItem(ViewGroup collection, int position) { int resId = 0; switch (position) { case 0: resId = R.id.page_one; break; case 1: resId = R.id.page_two; break; } return findViewById(resId); } @Override public int getCount() { return 2; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { // No super } }
// Ustaw adapter ViewPager
źródło
return collection.findViewById(resId);
Jeśli nie chcesz przekazać instancji działania@Override public void destroyItem(ViewGroup container, int position, Object object) {}
Zbudowaliśmy bardzo prostą podklasę tego
ViewPager
, z którego czasami korzystamy./** * View pager used for a finite, low number of pages, where there is no need for * optimization. */ public class StaticViewPager extends ViewPager { /** * Initialize the view. * * @param context * The application context. */ public StaticViewPager(final Context context) { super(context); } /** * Initialize the view. * * @param context * The application context. * @param attrs * The requested attributes. */ public StaticViewPager(final Context context, final AttributeSet attrs) { super(context, attrs); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); // Make sure all are loaded at once final int childrenCount = getChildCount(); setOffscreenPageLimit(childrenCount - 1); // Attach the adapter setAdapter(new PagerAdapter() { @Override public Object instantiateItem(final ViewGroup container, final int position) { return container.getChildAt(position); } @Override public boolean isViewFromObject(final View arg0, final Object arg1) { return arg0 == arg1; } @Override public int getCount() { return childrenCount; } @Override public void destroyItem(final View container, final int position, final Object object) {} }); } }
Ta klasa nie potrzebuje adaptera, ponieważ ładuje widoki z układu. Aby użyć go w swoich projektach, po prostu użyj go zamiast
android.support.v4.view.ViewPager
.Wszystkie wymyślne rzeczy będą nadal działać, ale nie musisz przejmować się adapterami.
źródło
onAttachedToWindow()
sięonFinishInflate()
.Opierając się na poprzednich odpowiedziach, zrobiłem następujące zajęcia, aby osiągnąć to w sposób właściwy i jak najbardziej przejrzysty (mam nadzieję):
public class MyViewPagerAdapter extends PagerAdapter { ArrayList<ViewGroup> views; LayoutInflater inflater; public MyViewPagerAdapter(ActionBarActivity ctx){ inflater = LayoutInflater.from(ctx); //instantiate your views list views = new ArrayList<ViewGroup>(5); } /** * To be called by onStop * Clean the memory */ public void release(){ views.clear(); views = null; } /** * Return the number of views available. */ @Override public int getCount() { return 5; } /** * Create the page for the given position. The adapter is responsible * for adding the view to the container given here, although it only * must ensure this is done by the time it returns from * {@link #finishUpdate(ViewGroup)}. * * @param container The containing View in which the page will be shown. * @param position The page position to be instantiated. * @return Returns an Object representing the new page. This does not * need to be a View, but can be some other container of * the page. ,container */ public Object instantiateItem(ViewGroup container, int position) { ViewGroup currentView; Log.e("MyViewPagerAdapter", "instantiateItem for " + position); if(views.size()>position&&views.get(position) != null){ Log.e("MyViewPagerAdapter", "instantiateItem views.get(position) " + views.get(position)); currentView = views.get(position); } else{ Log.e("MyViewPagerAdapter", "instantiateItem need to create the View"); int rootLayout = R.layout.view_screen; currentView = (ViewGroup) inflater.inflate(rootLayout, container, false); ((TextView)currentView.findViewById(R.id.txvTitle)).setText("My Views " + position); ((TextView)currentView.findViewById(R.id.btnButton)).setText("Button"); ((ImageView)currentView.findViewById(R.id.imvPicture)).setBackgroundColor(0xFF00FF00); } container.addView(currentView); return currentView; } /** * Remove a page for the given position. The adapter is responsible * for removing the view from its container, although it only must ensure * this is done by the time it returns from {@link #finishUpdate(ViewGroup)}. * * @param container The containing View from which the page will be removed. * @param position The page position to be removed. * @param object The same object that was returned by * {@link #instantiateItem(View, int)}. */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View)object); } /** * Determines whether a page View is associated with a specific key object * as returned by {@link #instantiateItem(ViewGroup, int)}. This method is * required for a PagerAdapter to function properly. * * @param view Page View to check for association with <code>object</code> * @param object Object to check for association with <code>view</code> * @return true if <code>view</code> is associated with the key object <code>object</code> */ @Override public boolean isViewFromObject(View view, Object object) { return view==((View)object); } }
I musisz to ustawić w swojej aktywności:
public class ActivityWithViewsPaged extends ActionBarActivity { /** * The page Adapter: Manage the list of views (in fact here, its fragments) * And send them to the ViewPager */ private MyViewPagerAdapter pagerAdapter; /** * The ViewPager is a ViewGroup that manage the swipe from left * to right to left. * Like a listView with a gesture listener... */ private ViewPager viewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_with_views); // Find the viewPager viewPager = (ViewPager) super.findViewById(R.id.viewpager); // Instantiate the PageAdapter pagerAdapter = new MyViewPagerAdapter(this); // Affectation de l'adapter au ViewPager viewPager.setAdapter(pagerAdapter); viewPager.setClipToPadding(false); viewPager.setPageMargin(12); // Add animation when the page are swiped // this instanciation only works with honeyComb and more // if you want it all version use AnimatorProxy of the nineoldAndroid lib //@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ viewPager.setPageTransformer(true, new PageTransformer()); } } @Override protected void onStop() { super.onStop(); pagerAdapter.release(); }
Gdzie pliki XML są oczywiste view_screen.xml:
<xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/screen" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/txvTitle" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" android:shadowColor="#FF00FF" android:shadowDx="10" android:shadowDy="10" android:shadowRadius="5" android:textSize="32dp" android:textStyle="italic" android:background="#FFFFF000"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFF00F0"> <TextView android:id="@+id/txvLeft" android:layout_width="wrap_content" android:layout_gravity="left" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:layout_marginTop="5dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/txvRight" android:layout_width="wrap_content" android:layout_gravity="right" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:layout_marginTop="5dp"/> </LinearLayout> <Button android:id="@+id/btnButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"/> <ImageView android:id="@+id/imvPicture" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"/> </LinearLayout>
A ActivtyMain ma następujący układ:
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingLeft="24dp" android:paddingRight="24dp" android:id="@+id/viewpager" android:background="#FF00F0F0"> </android.support.v4.view.ViewPager>
Wielkie dzięki dla Briana i Nicholasa za odpowiedź. Mam nadzieję, że dodam kilka jasnych informacji i podkreślę kilka dobrych praktyk dotyczących tej funkcji.
źródło
Chciałbym tutaj dodać moje rozwiązanie. Biorąc pod uwagę, że nie trzeba używać fragmentów, nadal można utworzyć
PagerAdapter
który przywiązujeviews
zamiastfragments
doViewPager
.Rozszerz
PagerAdapter
zamiastFragmentPagerAdapter
public class CustomPagerAdapter extends PagerAdapter { private Context context; public CustomPagerAdapter(Context context) { super(); this.context = context; } @Override public Object instantiateItem(ViewGroup collection, int position) { LayoutInflater inflater = LayoutInflater.from(context); View view = null; switch (position){ case 0: view = MemoryView.getView(context, collection); break; case 1: view = NetworkView.getView(context, collection); break; case 2: view = CpuView.getView(context, collection); break; } collection.addView(view); return view; } @Override public int getCount() { return 3; } @Override public boolean isViewFromObject(View view, Object object) { return view==object; } @Override public void destroyItem(ViewGroup collection, int position, Object view) { collection.removeView((View) view); } }
Teraz musisz zdefiniować trzy klasy, które zwrócą wartość
views
zawyżoną wviewpager
. Podobnie jakCpuView
ty będziesz miećMemoryView
iNetworkView
zajęcia. Każdy z nich nadmuchuje swoje odpowiednie układy.public class CpuView { public static View getView(Context context, ViewGroup collection) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context .LAYOUT_INFLATER_SERVICE); return inflater.inflate(R.layout.debugger_cpu_layout, collection, false); } }
I wreszcie układ, który będzie zawyżany w każdym z widoków
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000000" android:text="CPU"/> </LinearLayout>
PS: Powodem, dla którego napisałem tę odpowiedź, jest to, że wszystkie przedstawione tutaj rozwiązania wydają się działać dobrze, ale powodują zawyżanie układów w samej klasie PagerAdapter. W przypadku dużych projektów jest to trudne do utrzymania, jeśli jest ich dużo kodu związanego z zawyżonymi układami. W tym przykładzie wszystkie widoki mają oddzielne klasy i osobne układy. Dzięki temu projekt można łatwo utrzymać.
źródło
Chciałbym rozwinąć odpowiedź @Nicholas, możesz uzyskać widoki według identyfikatora lub jeśli są one dynamicznie dodawane, po prostu uzyskaj widok bezpośrednio na podstawie jego pozycji
class WizardPagerAdapter extends PagerAdapter { public Object instantiateItem(View collection, int position) { View v = pager.getChildAt(position); return v; } @Override public int getCount() { return 3; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == ((View) arg1); } }
źródło
tak ... możesz użyć View zamiast Fragment w viewpager. Tutaj możesz znaleźć cały przykład, który pomoże Ci osiągnąć Viewpager bez fragmentów. Przejrzyj tę dokumentację.
https://www.bignerdranch.com/blog/viewpager-without-fragments/
źródło