View pager'ı görünümlerle kullanabilir miyim (parçalarla değil)


131

ViewPagerArasında geçiş yapmak için kullanıyorum Fragments, ancak basit XML düzeni ViewPagerarasında geçiş yapmak için kullanabilir miyim Views?

Bu, AdapterParçalar arasında geçiş yapmak için kullanılan ViewPager sayfam :

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

}

Ve bu benim ipucu parçam:

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

Kodumu Fragment yerine Görünümlerle çalışacak şekilde nasıl değiştirebilirim?


bu örneğe de bir göz atın stackoverflow.com/a/37916222/3496570
Zar E Ahmer

Neden parça kullanmıyorsunuz? Parçaları kullanırsak veya kullanmazsak neyi başarırız veya kaybederiz?
Eftekhari

@Eftekhari Fragments => Karmaşık Yaşam Döngüsü => Daha Fazla Hata => Kaos
Harshil Pansare

1
@HarshilPansare Evet, Şubat ayında bu soruları sorduktan sonra tüm bu felaketleri yaşadım ve artık projelerimde fragman kullanmayacağım. Bundan sonra tüm parçaları temizlemekten başka seçeneğim yoktu ViewPager, onDestroybu nedenle onResumeetkinlikten sonra artık mevcut olmayan 3 parçanın tümünü geri almaya gerek kalmayacak. Sorunlardan birinden bahsetmek istedim.
Eftekhari

Parçasız yaşama şerefe!
Harshil Pansare

Yanıtlar:


95

Aşağıdakilerden ziyade bu iki yöntemi geçersiz kılmanız gerekir 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);
}

5
güzel bir .. bana çok yardım et ... FragmentPageAdapter yerine PageAdapter'ı genişlettim ........ şimdi işi iyi .....
ranjith

3
Tam bir çalışma örneği için, bu soruda bulunan koda bakın: stackoverflow.com/q/7263291
Tiago

7
Merak ediyorum, neden addView gerekli? Parça bağdaştırıcısı, görünümü döndürmesini istedi.
Amit Gupta

2
Arayüzle ViewPageruğraşırken hiç yayınlamanıza gerek yokViewGroup
Dori

2
@AmitGupta görünümü konteynere eklemeniz gerekir, çünkü görünümü buradan geri veremeyebilirsiniz. instantiateItem, isterseniz farklı bir nesne olabilecek bu görünümle ilişkili bir nesne döndürmelidir; bu bir anahtar. Ne iade ederseniz edin, sadece isViewFromObject uygulamanızın iki up, key ile eşleşebileceğinden emin olun. Bununla birlikte, en yaygın uygulama, görünümü de anahtar olarak döndürmektir. FragmentPageAdapter, sizin için tüm anahtar-görüntüleme öğelerini yönetir ve bu nedenle sizden bunun yerine bir parça oluşturmanızı ister.
themightyjon

66

Bu örneği kullanın

Alt görünümleri iç içe geçiren tek bir XML düzeni kullanabilirsiniz.

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

AMA ... bunu bir adaptörle de halletmeniz gerekiyor. Burada bulunan görünüm kimliğini başka herhangi bir düzeni şişirmeden döndürüyoruz.

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

// ViewPager adaptörünü ayarlayın

WizardPagerAdapter adapter = new WizardPagerAdapter();
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);

2
@ user1672337 findViewById'e Activity sınıfından erişilebilir. Bu nedenle, Actvitiy'nizde dahili (statik olmayan) sınıf oluşturun. Ya da etkinlik örneğini adaptöre
geçirmeniz gerekir

7
ViewPager'ın 2'den fazla alt görünümü varsa, bu işe yaramıyor gibi görünüyor. Örneğin, ViewPager'ımda üç RelativeLayouts varsa ve ardından üçüncü sayfaya kaydırmaya çalışırsam, üçüncü sayfa boş görünür. Ne verir bir fikriniz var mı?
Nathan Walters

15
@NathanWalters, bugün aynı sorunu yaşadım, bu sorunu ViewPager'ın OffscreenPageLimit özelliğini artırarak çözdüm. Muhtemelen bu bilgilerle bir cevabı güncellemeye değer.
Mikhail

2
Kullanabileceğiniz return collection.findViewById(resId);bir etkinliğin örneğini geçmek istemiyorsanız
Aksiom

3
Lütfen bu kodu ekleyin@Override public void destroyItem(ViewGroup container, int position, Object object) {}
Volodymyr Kulyk

11

ViewPagerBazen kullandığımızın çok basit bir alt sınıfını oluşturduk .

/**
 * 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) {}
        });
    }

}

Bu sınıf, görünümleri yerleşimden yükleyeceği için bir adaptöre ihtiyaç duymaz. Projelerinizde kullanmak için, sadece android.support.v4.view.ViewPager.

Tüm süslü şeyler yine de işe yarayacak, ancak adaptörlerle uğraşmanıza gerek yok.


1
Bu neredeyse benim için çalıştı, ama değiştirmek zorunda onAttachedToWindow()için onFinishInflate().
ehehhh

@Eftekhari Parçacıklar olmadan daha kolaydır ve daha az kod yazarsınız, bu da daha sonra okunması ve anlaşılması daha kolay ve hatalara daha az eğilimli olduğu anlamına gelir
Sabo

11

Önceki cevaplara dayanarak, bunu doğru ve en net bir şekilde başarmak için aşağıdaki sınıfı yaptım (umarım):

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

Ve bunu aktivitenizde ayarlamalısınız:

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

XML dosyalarının bariz view_screen.xml olduğu yerlerde:

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

Ve ActivtyMain aşağıdaki düzene sahiptir:

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

Cevabınız için Brian ve Nicholas'a çok teşekkür ederim, umarım bazı açık bilgiler eklerim ve bu özellik için bazı iyi uygulamaları öne çıkarırım.


1
Pek iyi değil, oluşturulan tüm görünümleri kaydediyorsunuz. Yalnızca görünen görünümleri kaydetmesi daha iyi olur. (listview'daki convertview'e benzer)
htafoya

4

@Nicholas cevabını detaylandırmak istiyorum, görünümleri id'ye göre alabilir veya dinamik olarak eklenmişlerse, doğrudan konumuna göre görünümü alabilirsiniz.

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

4

Çözümümü buraya eklemek istiyorum. Eğer kullanım parçaları gerekmez göz önüne alındığında, yine de oluşturabilir PagerAdapterverdiği hangi viewsyerine fragmentskadar ViewPager.

Uzatın PagerAdapteryerineFragmentPagerAdapter

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

Şimdi views, içinde şişirilecek olanı döndürecek üç sınıf tanımlamanız gerekiyor viewpager. CpuViewSize benzer MemoryViewve NetworkViewdersler alacaksınız . Her biri kendi düzenlerini şişirecek.

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

Ve son olarak, görünümlerin her birinde şişirilecek bir düzen

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

Not: Bu cevabı yazmamın nedeni, burada sağlanan tüm çözümlerin iyi çalışıyor gibi görünmesi, ancak PagerAdapter sınıfının kendisindeki mizanpajları şişirmeleridir. Büyük projeler için, şişirilmiş düzenlerle ilgili çok sayıda kod varsa, sürdürmek zorlaşır. Şimdi bu örnekte tüm görünümlerin ayrı sınıfları ve ayrı düzenleri vardır. Böylece projenin bakımı kolayca yapılabilir.


IMO, aktivitelerin kullanımı daha kolay
Denny

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.