Can I use view pager with views (not with fragments)
Solution 1
You need to override these two methods rather than 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);
}
Solution 2
Use this example
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(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
}
}
// Set the ViewPager adapter
WizardPagerAdapter adapter = new WizardPagerAdapter();
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
Solution 3
We have build a very simple subclass of the ViewPager
that we use sometimes.
/**
* 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) {}
});
}
}
This class does not need a adapter as it will load the views from the layout. In order to use it your projects, just use it instead of the android.support.v4.view.ViewPager
.
All the fancy stuff will still work, but you do not need to be bothered with the adapters.
Solution 4
Based on the previous answers, I made the following class to achieve that in a proper and clearest way (I hope):
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);
}
}
And you have to set it in your activity:
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();
}
Where the XML files are obvious 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>
And ActivtyMain has the following layout:
<?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>
Big thanks to Brian and Nicholas for your answer, I hope I add some clearest information and hightlight some good practices for this feature.
Solution 5
I would like to add my solution here. Given that you don't need to use fragments, you can still create a PagerAdapter
which attaches views
instead of fragments
to the ViewPager
.
Extend PagerAdapter
instead of 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);
}
}
Now you need to define three classes which will return the views
to be inflated in the viewpager
. Similar to CpuView
you will have MemoryView
and NetworkView
classes. Each of them will inflate their respective layouts.
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);
}
}
And finally a layout which will be inflated in each of the views
<?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>
P.S.: The reason I wrote this answer is because all the solutions provided here seems to be working fine, but they are inflating the layouts in the PagerAdapter class itself. For large projects it becomes difficult to maintain if their is a lot of code related to the layouts inflated. Now in this example all the views have separate classes and separate layouts. So the project can be easily maintained.
Related videos on Youtube
ranjith
Updated on July 08, 2022Comments
-
ranjith almost 2 years
I am using
ViewPager
for swiping betweenFragments
, but can I useViewPager
to swipe betweenViews
simple XML layout?This is my page
Adapter
for the ViewPager which is used to swipe between Fragments: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); } }
And this is my tip fragment:
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; } }
How can I modify my code to work with Views instead of Fragment?
-
Zar E Ahmer about 8 yearsalso have a look at this example stackoverflow.com/a/37916222/3496570
-
Eftekhari over 7 yearsWhy no using fragments? What will we achieve or lose if we use or don't use fragments?
-
Harshil Pansare almost 7 years@Eftekhari Fragments => Complex LifeCycle => More Bugs => Chaos
-
Eftekhari almost 7 years@HarshilPansare Yes, I went through all of these disasters after I asked this questions in February and I will not use fragments in my projects anymore. I had no choice but to clean all the fragments from the
ViewPager
ononDestroy
thus ononResume
activity there will be no need to retrieve all 3 fragments that may no longer available. Just wanted to mention one of the problems. -
Harshil Pansare almost 7 yearsCheers to fragments-free life!
-
-
ranjith almost 11 yearscan u add the full code for fragment page adapter... because i over ride this methods as u said.... but... the app got crash...
-
ranjith almost 11 yearshey frnd... the findViewById() method is not defined here
-
ranjith almost 11 yearsnice one.. help me a lot... i extended PageAdapter instead of FragmentPageAdapter........ now its work fine.....
-
ruX over 10 years@user1672337 findViewById is accessible from Activity class. So make internal (non-static) class in your Actvitiy. Or you have to pass activity instance to adapter
-
Bitcoin Cash - ADA enthusiast over 10 yearsFor a complete working example, check out the code found on this question: stackoverflow.com/q/7263291
-
McLan about 10 yearsmy app doesn't have fragments, how can i start my activity everytime I swipe a page ?
-
Nathan Walters about 10 yearsThis doesn't appear to work if the ViewPager has more than 2 child views. For example, if I have three RelativeLayouts in my ViewPager and then try to swipe to the third page, the third page shows up as blank. Any idea what gives?
-
Mikhail about 10 years@NathanWalters, I had the same issue today, have resolved it increasing OffscreenPageLimit property of ViewPager. Probably it worth to update an answer with this information.
-
Nathan Walters about 10 years@Mikhail that worked perfectly, thank you so much! This should definitely be added to the answer.
-
Roel almost 10 yearsI can find nothing on that link that has to do with this answer.
-
Amit Gupta over 9 yearsOut of curiosity, why addView is required. The fragment adapter just asked for it return the view.
-
Beloo over 9 years@Nathan Walters Beware of outofmemory error this solution could lead. If view pager have many pages and a big setOffscreenPageLimit value an exception could be thrown especially on low memory devices. I faced this on a typical guide viewpager with a several images. So i think a dynamic view creation/destroying or a FragmentPagerAdapter should are used in this case. developer.android.com/reference/android/support/v4/view/… also warns about that
-
Dori almost 9 yearsyou dont need to cast to
ViewPager
at all as you are dealing with theViewGroup
interface -
themightyjon almost 9 years@AmitGupta you're required to add the view to the container because you may not be returning the view here. instantiateItem must return an object associated with that view, which can be a different object if you like; it's a key. Whatever you return, you just make sure that your implementation of isViewFromObject can match the two up, key to view. However, the most common implementation is to just return the view as the key as well. FragmentPageAdapter handles all the key-to-view stuff for you and thus just asks you to create a fragment instead.
-
Iman Akbari over 8 yearsFrankly nothing but this works for me. The OffscreenPageLimit trick that @Mikhail suggested is also a must do for this to work. thank you both.
-
ehehhh over 8 yearsThis almost worked for me, but I had to change
onAttachedToWindow()
toonFinishInflate()
. -
htafoya about 8 yearsNot very good, you are saving all the created views. It would be better if it only saved the visible views. (similar to convertview in listview)
-
Aksiom about 8 yearsyou can use
return collection.findViewById(resId);
If you dont want to pass an activity instance -
Volodymyr Kulyk over 7 yearsPlease add this code
@Override public void destroyItem(ViewGroup container, int position, Object object) {}
-
Biraj Zalavadia over 7 years@Eftekhari Viewpager provides these two ways, you can choose any of them. Generally when there is only informative things and no user interaction you can use view else go with Fragments if there is so many user interactions and more code to manage.
-
Sabo over 7 years@Eftekhari It is easier without fragments and you write less code, which means that is easier to read and understand later on and less prone to bugs
-
Denny over 7 yearsIMO, activities are easier to use
-
hemanth kumar over 5 years@BirajZalavadia this was working when the compile sdk version is 15, but when it is set to 23, i get classcast exception saying the container cannot be cast to fragment. Could you tell me what can i change to make it work?
-
Biraj Zalavadia over 5 years@hemanthkumar you need to use latest(at least 23.x) supporting library/jar for viewpager.
-
Ahmed Elsayed about 3 yearsPlease how to make the height of the viewPager is equal to the heighst item in Pager Adapter ?
-
Swathi over 2 yearsHere text color is given as white and parent has no background, so not able to see the output, thought it was not working. Just remove the text color you will see your view pager, it will work