뷰 페이저를 뷰와 함께 사용할 수 있습니까 (조각이 아님)


131

내가 사용하고 ViewPager사이에 강타를 위해 Fragments,하지만 난 사용할 수 있습니다 ViewPager사이에 슬쩍에 Views간단한 XML 레이아웃?

이것은 AdapterFragments 사이를 스 와이프하는 데 사용되는 ViewPager의 내 페이지 입니다.

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

}

그리고 이것은 내 팁 조각입니다.

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

Fragment 대신 Views와 함께 작동하도록 코드를 수정하려면 어떻게해야합니까?


이 예제도 살펴보십시오 stackoverflow.com/a/37916222/3496570
Zar E Ahmer

왜 프래그먼트를 사용하지 않습니까? 프래그먼트를 사용하거나 사용하지 않으면 무엇을 얻거나 잃을 것인가?
Eftekhari

@Eftekhari 조각 => 복합 LifeCycle의 => 더 많은 버그 => 카오스
Harshil Pansare

1
@HarshilPansare 예, 2 월에이 질문을 한 후에이 모든 재난을 겪었고 더 이상 프로젝트에서 조각을 사용하지 않을 것입니다. 나는에서 선택의 여지가 있지만, 모든 조각을 청소 없었다 ViewPageronDestroy에 따라서 onResume3 개 조각을 검색 할 필요가 없을 것입니다 활동이 더 이상 사용할 수있다. 문제 중 하나를 언급하고 싶었습니다.
Eftekhari

조각없는 삶을 응원합니다!
Harshil Pansare

답변:


95

이 두 가지 방법을 재정의해야합니다 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
좋은 하나 .. 많은 도움이 ... 난 FragmentPageAdapter 대신 PageAdapter를 확장 ........ 이제는 잘 작동합니다 .....
ranjith

3
완전한 작업 예제를 보려면이 질문에있는 코드를 확인하십시오. stackoverflow.com/q/7263291
Tiago

7
호기심 때문에 addView가 필요한 이유. 조각 어댑터가 방금 뷰를 반환하도록 요청했습니다.
Amit Gupta

2
인터페이스를 ViewPager다룰 때 전혀 캐스트 할 필요가 없습니다ViewGroup
Dori

2
@AmitGupta 여기서 뷰를 반환하지 않을 수 있으므로 컨테이너에 뷰를 추가해야합니다. instantiateItem은 해당 뷰와 관련된 객체를 반환해야합니다. 원하는 경우 다른 객체가 될 수 있습니다. 열쇠입니다. 무엇을 반환하든, isViewFromObject의 구현이 두 개의 키와 일치하는지 확인하십시오. 그러나 가장 일반적인 구현은 뷰를 키로 만 반환하는 것입니다. FragmentPageAdapter는 모든 핵심 항목을 처리하므로 대신 조각을 만들도록 요청합니다.
themightyjon

66

이 예제를 사용하십시오

하위 뷰를 중첩하는 단일 XML 레이아웃을 사용할 수 있습니다.

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

그러나 ... 어댑터로도 처리해야합니다. 여기서는 다른 레이아웃을 팽창시키지 않고 찾은 뷰 ID를 반환합니다.

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 어댑터 설정

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

2
@ user1672337 findViewById는 Activity 클래스에서 액세스 할 수 있습니다. 따라서 Actvitiy에서 내부 (정적이 아닌) 클래스를 만드십시오. 또는 당신은 어댑터에 활동 인스턴스를 통과해야
RUX

7
ViewPager에 둘 이상의 자식 뷰가있는 경우 작동하지 않는 것 같습니다. 예를 들어 ViewPager에 3 개의 RelativeLayouts가 있고 세 번째 페이지로 스 와이프하려고하면 세 번째 페이지가 공백으로 표시됩니다. 어떤 아이디어가 있습니까?
Nathan Walters

15
@NathanWalters, 오늘 같은 문제가 발생하여 ViewPager의 OffscreenPageLimit 속성이 증가하는 문제를 해결했습니다. 이 정보로 답을 업데이트 할 가치가있을 것입니다.
Mikhail

2
return collection.findViewById(resId);액티비티 인스턴스를 전달하지 않으려 는 경우 사용할 수 있습니다
Aksiom

3
이 코드를 추가하세요@Override public void destroyItem(ViewGroup container, int position, Object object) {}
볼로디미르 쿨릭

11

우리는 ViewPager때때로 사용 하는 아주 간단한 서브 클래스를 만들었습니다.

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

}

이 클래스는 레이아웃에서 뷰를로드하므로 어댑터가 필요하지 않습니다. 프로젝트를 사용하려면 대신 대신 사용하십시오 android.support.v4.view.ViewPager.

모든 멋진 것들이 여전히 작동하지만 어댑터를 사용하지 않아도됩니다.


1
이것은 거의 나를 위해 일했지만,로 변경 onAttachedToWindow()해야했습니다 onFinishInflate().
ehehhh

@Eftekhari 조각이 없어도 쉬우 며 코드를 적게 작성하므로 나중에 읽고 이해하기 쉽고 버그가 적습니다.
Sabo

11

이전 답변을 바탕으로 다음 클래스를 적절하고 명확한 방법으로 달성했습니다.

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

그리고 당신은 당신의 활동에서 설정해야합니다 :

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 파일이 명백한 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>

ActivtyMain의 레이아웃은 다음과 같습니다.

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

귀하의 답변에 대한 Brian과 Nicholas에게 감사의 말씀을 전하며,이 기능에 대한 가장 명확한 정보를 추가하고 모범 사례를 강조하겠습니다.


1
별로 좋지는 않지만 생성 된 모든 뷰를 저장하고 있습니다. 보이는 뷰만 저장하는 것이 좋습니다. (listview에서 convertview와 유사)
htafoya

4

@Nicholas 답변에 대해 자세히 설명하고 싶습니다 .ID로 뷰를 얻거나 동적으로 추가 된 경우 위치를 직접 지정하면 뷰를 얻을 수 있습니다

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

여기에 솔루션을 추가하고 싶습니다. 당신이 사용 조각 할 필요가 없습니다 감안할 때, 당신은 여전히 만들 수 있습니다 PagerAdapter부착하는 views대신 fragments받는 사람을 ViewPager.

PagerAdapter대신 확장FragmentPagerAdapter

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

이제는 views에서 inflated을 반환하는 세 개의 클래스를 정의해야 합니다 viewpager. CpuView당신 MemoryView과 비슷한 NetworkView수업이 있습니다. 그들 각각은 각자의 레이아웃을 팽창시킵니다.

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

마지막으로 각 뷰에서 부풀려 질 레이아웃

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

추신 : 이 답변을 작성한 이유는 여기에 제공된 모든 솔루션이 제대로 작동하는 것 같지만 PagerAdapter 클래스 자체의 레이아웃을 팽창시키고 있기 때문입니다. 대규모 프로젝트의 경우 레이아웃과 관련된 많은 코드가 팽창하면 유지 관리가 어려워집니다. 이제이 예에서 모든 뷰에는 별도의 클래스와 별도의 레이아웃이 있습니다. 따라서 프로젝트를 쉽게 유지할 수 있습니다.


IMO, 활동이 더 사용하기 쉽습니다
Denny

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.