18

UPDATED : Can I use the following layout to implement 3 textviews in Viewpager :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

       <TextView
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:text="view 1"/>
       <TextView
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:text="view 2"/>
       <TextView
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:text="view 3"/>

    </android.support.v4.view.ViewPager>
</LinearLayout>

I want to implement the ViewPager for these 3 views. and i want to have viewpager and those 3 views in single xml file. Each page contains each textview. I have seen some examples but each page was implement using separate xml layout file.

How can I implement the viewpager for these 3 views in a single xml file. If possible please provide me a sample code or example.

Dileep Perla
  • 1,865
  • 7
  • 33
  • 54

9 Answers9

55

You can use a single XML layout nesting the children views.

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

BUT... you need handle this with an adapter also. Here we return the finded view ID without inflate any other layout.

    class WizardPagerAdapter extends PagerAdapter {

        public Object instantiateItem(View 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 == ((View) arg1);
        }
    }



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

My question is... Some Guru here can teach me if is possible that the ViewPager read the children from XML and auto build the pages without use the instantiateItem()?

stephenspann
  • 1,823
  • 1
  • 16
  • 31
jjalonso
  • 691
  • 5
  • 17
  • 12
    You'll need to override method destroyItem : @Override public void destroyItem(View arg0, int arg1, Object arg2) { } – Kowlown Apr 28 '13 at 16:01
  • 1
    to make the child be auto builded you can add a constructor in the adapter which take the pager as parameter. inside instantiate item you can now return pager.getChildAt(position); while in the getCount() you can return pager.getChildCount() – Fabio Marcolini Mar 05 '14 at 11:43
  • Works like a charm. RecyclerView in a pager item saves its state automatically with this solution. (E.g. scroll position is retained.) – László Kustra Feb 10 '15 at 21:42
  • It recycles , so u need to set viewpager to default value on each bindView – Ioane Sharvadze Jul 14 '15 at 14:13
  • Add @Override public void destroyItem(ViewGroup parent, int position, Object object) { View view = (View) object; parent.removeView(view); } – Alberto Anderick Jr Mar 10 '16 at 19:12
3

Update

This answer will show optimised and managed way to set ViewPager pages inside layout.

Step 1

First make two pages Layouts XML layout_page_1.xml and layout_page_2.xml.

Step 2

Now include all pages layout in your parent layout ViewPager.

<androidx.viewpager.widget.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include
        android:id="@+id/page_one"
        layout="@layout/layout_page_1" />

    <include
        android:id="@+id/page_two"
        layout="@layout/layout_page_2" />

</androidx.viewpager.widget.ViewPager>

Step 3

Now from your code, set adapter in simple steps

// find views by id
ViewPager viewPager = findViewById(R.id.viewpager);

CommonPagerAdapter adapter = new CommonPagerAdapter();

// insert page ids
adapter.insertViewId(R.id.page_one);
adapter.insertViewId(R.id.page_two);

// attach adapter to viewpager
viewPager.setAdapter(adapter);

That's All! You need only a common adapter for all ViewPagers.

CommonPagerAdapter.java class

public class CommonPagerAdapter extends PagerAdapter {
    private List<Integer> pageIds = new ArrayList<>();

    public void insertViewId(@IdRes int pageId) {
        pageIds.add(pageId);
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        return container.findViewById(pageIds.get(position));
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView((View) object);
    }

    @Override
    public int getCount() {
        return pageIds.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }
}

Important Note

It is better to use Fragments instead of Views. You should create Fragments and use FragmentStatePagerAdapter to maintain stack, lifecycle and states. You can see @this answer for complete code of using FragmentStatePagerAdapter.

Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
  • In case looking for a proper example from google: https://github.com/googlesamples/android-media-controller/blob/5525c7f2da75803fe53269d5bc445205676caea1/mediacontroller/src/main/res/layout/activity_media_app_testing.xml – Shailendra Yadav Sep 22 '20 at 07:27
1

thats impossible .you can do it like these

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/pager"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />

then create seperate xml file and do it like this.for eg:i am gonna use the xml file name is ios_frag.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="50sp"/>
 </LinearLayout>
1

Just if anyone faces the same problem, I've solved it with an adapter which extracts the page views from an arbitrary viewgroup that you pass to it.

    package com.packagename;

import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class ViewGroupPagerAdapter extends PagerAdapter {
    public ViewGroupPagerAdapter(ViewGroup viewGroup) {
        while (viewGroup.getChildCount() > 0) {
            views.add(viewGroup.getChildAt(0));
            viewGroup.removeViewAt(0);
        }
    }

    private List<View> views = new ArrayList<View>();

    @Override
    public Object instantiateItem(ViewGroup parent, int position) {
        View view = views.get(position);
        ViewPager.LayoutParams lp = new ViewPager.LayoutParams();
        lp.width = ViewPager.LayoutParams.FILL_PARENT;
        lp.height = ViewPager.LayoutParams.FILL_PARENT;
        view.setLayoutParams(lp);
        parent.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup parent, int position, Object object) {
        View view = (View) object;
        parent.removeView(view);
    }

    @Override
    public int getCount() {
        return views.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}

Usage:

ViewPager viewPager=findViewById(...); // Retrieve the view pager
viewPager.setAdapter(new ViewGroupPagerAdapter(findViewById(R.id.id_of_your_view_group_where_you_store_the_pages)));
Aron Lorincz
  • 1,677
  • 3
  • 19
  • 29
1

You can subclass ViewPager and override onInflate.
Moreover, you will get a preview of the first ViewPager page in the Layout Editor.
All views are kept in memory so for performance reasons you should only use this with a small number of pages.

@Override protected void onFinishInflate() {
    int childCount = getChildCount();
    final List<View> pages = new ArrayList<>(childCount);
    for (int i = 0; i < childCount; i++) {
        View child = getChildAt(i);
        Class<?> clazz = child.getClass();
        if (clazz.getAnnotation(DecorView.class) == null) {
            pages.add(child);
        }
    }
    for (View page : pages) {
        removeView(page);
    }
    setAdapter(new PagerAdapter() {
        @Override public int getCount() {
            return pages.size();
        }

        @Override public Object instantiateItem(ViewGroup container, int position) {
            container.addView(pages.get(position));
            return position;
        }

        @Override public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(pages.get((Integer)object));
        }

        @Override public boolean isViewFromObject(View view, Object object) {
            return pages.get((Integer)object) == view;
        }
    });
    super.onFinishInflate();
}
tango24
  • 464
  • 2
  • 11
1
    viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
    viewPager.setAdapter(new MyPagerAdapter(rootView));
    viewPager.setOffscreenPageLimit(3); //or whatever you like

it caches it and shows perfectly.

Alp Altunel
  • 3,324
  • 1
  • 26
  • 27
0

add this in your xml layout file

<android.support.v4.view.ViewPager 
    android:id="@+id/view_pager"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

create 3 Fragments and add each TextView for every fragment. Then create an adapter that subclassed PagerAdapter

A good example can be found here

chip
  • 1,779
  • 1
  • 22
  • 34
  • 1
    In this example fragments and viewpager are maintained in separate xml files. I want both to be maintained in single xml file – Dileep Perla Sep 06 '12 at 07:53
  • what are you trying to accomplish? how about editing your question and add some information that we might find it helpful? – chip Sep 06 '12 at 08:09
0

How can I implement the viewpager for these 3 views in a single xml file.

Sorry, but that is not possible.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
-3

Simply : add a ViewPager in your file and put inside your 3 TextView...

arnouf
  • 790
  • 2
  • 7
  • 16
  • let me try. Actually i haven't implemented yet. I have just seen examples how to implement it and observed that page code and Viewpager code(xml) are implemented in separate files. – Dileep Perla Sep 06 '12 at 07:52