Android: How to implement viewpager and views in single xml file - android

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.

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

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.

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>

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

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

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.

How can I implement the viewpager for these 3 views in a single xml file.
Sorry, but that is not possible.

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

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

Related

Image Slideshow using ViewPager

I want to implement the following screen :
In the screen shot you can see that below MyAdvisor TextView i have an image.On swiping this image different image will be displayed .To create Swipe Gallery i am using view pager here.I am using an Adapter which is providing images to display through view pager.
Adapter:
public class ImageAdapter extends PagerAdapter {
private Context context;
private int[] images = new int[]{R.drawable.imgone,
R.drawable.img2,
R.drawable.img3};
public ImageAdapter(Context context) {
this.context = context;
}
#Override
public int getCount() {
return images.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == (ImageView) object;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(context);
int padding = context.getResources().getDimensionPixelSize(R.dimen.activity_horizontal_margin);
imageView.setPadding(padding, padding, padding, padding);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setImageResource(images[position]);
((ViewPager) container).addView(imageView, 0);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((ImageView) object);
}
}
Below is the xml file of demo project of mine which contains two text view and a view pager.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello"
android:layout_above="#+id/txt"
android:layout_marginTop="15sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/txt"
android:text="Hello2"
android:layout_above="#+id/pager"
android:layout_marginTop="15sp"/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height = "wrap_content"
></android.support.v4.view.ViewPager>
My problem is that the view pager is having height as match_parent.Even after changing it as wrap_content ,the other views are not displayed .Please guide me how can i implement this screen.
I suggest you to use Heterogenous Layouts inside RecyclerView for that approach.If you're not familiar with the concept, go thru this tutorial.And for the viewpager part, there is this awesome library which comes up with so many built in features that you will absolutely love.Just inflate the Sliderlayout of this library inside onCreateViewHolder() of adapter and provide corresponding data.No need to write your own custom pageradapter and handle events.You just have to know how to use Recyclerview and you're pretty much done.

Put a button on a page from a ViewPager

I'm using ViewPager. I want to put a button on each page, but in doing so fills the entire page. I would like to determine the width and height of button but do not know how.
This is my code:
Pager Activity
public class PagerActivity extends Activity {
PagerContainer mContainer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContainer = (PagerContainer) findViewById(R.id.pager_container);
ViewPager pager = mContainer.getViewPager();
PagerAdapter adapter = new MyPagerAdapter();
pager.setAdapter(adapter);
//Necessary or the pager will only have one extra page to show
// make this at least however many pages you can see
pager.setOffscreenPageLimit(adapter.getCount());
//A little space between pages
pager.setPageMargin(15);
//If hardware acceleration is enabled, you should also remove
// clipping on the pager for its children.
pager.setClipChildren(false);
}
//Nothing special about this adapter, just throwing up colored views for demo
private class MyPagerAdapter extends PagerAdapter {
#Override
public Object instantiateItem(ViewGroup container, int position) {
TextView view = new TextView(PagerActivity.this);
view.setText("Item "+position);
view.setGravity(Gravity.CENTER);
view.setBackgroundColor(Color.argb(255, position * 50, position * 10, position * 50));
view.setTextColor(Color.parseColor("#CA2C68"));
Button buttonView = new Button(PagerActivity.this);
buttonView.setBackgroundResource(R.drawable.button_states_azul);
container.addView(buttonView);
return buttonView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
#Override
public int getCount() {
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#FF7CB8"
android:id="#+id/linear" >
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:background="#CA2C68"
android:layout_gravity="bottom"/>
</LinearLayout>
<com.example.slidee.PagerContainer
android:id="#+id/pager_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/linear"
android:layout_alignParentBottom="true"
android:layout_below="#+id/linear"
android:background="#29C5FF" >
<android.support.v4.view.ViewPager
android:layout_width="234dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="#29C5FF" />
</com.example.slidee.PagerContainer>
ViewPager expects the contained view to occupy the whole container.
Use some layout to contain a button:
LinearLayout lay = new LinearLayout(PagerActivity.this);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
buttonView.setLayoutParams(lp);
lay.addView(buttonView);
container.addView(lay);
an other way to do it is to make a new xml file and inflate it.
<?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">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/viewpager_button"
android:background="#drawable/button_states_azul"/>
</LinearLayout>
and in instantiateItem
LayoutInflater inflater = MainActivity.this.getLayoutInflater();
View pagerView = inflater.inflate(R.layout.viewpager_layout, null);
Button button = (Button) pagerView.findViewById(R.id.viewpager_button);
container.addView(button);
You are creating the button dynamically and hence by default it does a match_parent for width and height.
Add this line:
buttonView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
This is how i do it, create a xml layout you want to inflate. Add all the view you are intending. Then inside your adapter class, inside instantiateItem override do something like this. remember to adjust your xml views to fit parents width and height as you wish.
#Override
public Object instantiateItem(ViewGroup container, final int position) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.your_view, container, false);
// get reference to your button over here if you have one
Button b = (Button) view.findViewById(R.id.enter_button);
container.addView(view);
return view;
}

ViewPager of views (not fragments) as header of a gridview (Etsy's StaggeredGridView) in a fragment

So, I'm in a situation where I want to add a ViewPager of views (not fragments) as the header of a gridview in a fragment, but my ViewPager doesn't appear when I set it as my headerview. I'm currently using Etsy's StaggeredGridView to allow my gridview to have a header, and I'm using a PagerAdapter instead of FragmentStatePagerAdapter to be able to scroll through views instead of fragments. I was going to just use fragments, but I wasn't sure if this would be good since, I assume, that would be considered as having nested fragments, which are only supported in 4.2+ and through the support library: my app supports 4.0 and above, and at the moment, I'm using native fragments.
I also tried setting a view programatically, but still nothing shows.
I set a toast in the ViewPager to see if anything is actually getting created, and the toast shows up as expected, but still no header. The view that I'm attempting to inflate shouldn't be the problem because if I use it as a header on its own it shows. Here's what I have so far:
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//inflate fragment which contains the gridview. Have a pointer to the gridview.
View v = inflater.inflate(R.layout.fragment_menu, container, false);
mGridView = (StaggeredGridView) v.findViewById(R.id.dishesGridView);
View header = inflater.inflate(R.layout.view_pager_header, container, false);
ViewPager mPager = (ViewPager) header.findViewById(R.id.pager);
//list of views to test header
final List<View> views = new ArrayList<View>();
views.add(inflater.inflate(R.layout.menu_header, null));
mPager.setAdapter(new PagerAdapter() {
public View getView(int position) {
return views.get(position);
}
#Override
public Object instantiateItem(ViewGroup collection, int position) {
View v = getView(position);
((ViewPager)collection).addView(v);
Toast.makeText(getActivity(),
"Hello ViewPager",
Toast.LENGTH_SHORT).show();
return v;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == (View) arg1;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return views.size();
}
});
mGridView.addHeaderView(mPager);
return v;
}
Here's the view_pager_header.xml:
<?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" />
Here's the menu_header.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/resHeader"
android:layout_width="wrap_content"
android:layout_height="100dp" >
<com.platey.IonPlatey.RectangleImageView
android:id="#+id/restaurant_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<ImageView
android:src="#drawable/frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<TextView
android:id="#+id/resType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="15dp"
android:text="ResType Here"
android:textColor="#d82727"
android:textStyle="bold" />
</RelativeLayout>
Reason:
Basically the issue is caused by ViewPager android:layout_height="match_parent".
<?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" />
The match_parent is wrong here for sure, because you don't want the header to fill entire parent. But regardless of that - match_parent will not work here in StaggeredGridView.
This is the same as in standard ListView items etc. - match_parent is not allowed and it will be replaced with just wrap_content while performing layout.
Unfortunately wrap_content is not supported by ViewPager because ViewPager cannot wrap it's content (it is not aware of children size).
Solution:
You have two ways to properly display a ViewPager there:
Just specify a static height (for example 50dp)
Extend your ViewPager and perform your own measuring if you don't want static height.
Screenshots
Here is also a screenshots with match_parent. You can see that ViewPager is nor displayed (has zero height):
and with static height:
<?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="50dp" />

ViewPager not supporting layout_height = wrap_content

I'm building an android application with the following layout.
It's already known that layout_height="wrap_content" doesn't work for the ViewPager.
My question is how to change it dynamically. The content of the ViewPager is inflated from two xml layouts, vp_statistics.xml and vp_campaigns.xml.
here's the xml for the ViewPager
<LinearLayout
android:id="#+id/topcontent_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="#+id/viewpager_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Here's the code for my PagerAdapter
class MyPagerAdapter extends PagerAdapter{
#Override
public int getCount() {
// TODO Auto-generated method stub
return 2;
}
public Object instantiateItem(View collection, int pos){
LayoutInflater inflater = (LayoutInflater)collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
switch(pos){
case 0:
resId = R.layout.vp_statistics;
break;
case 1:
resId = R.layout.vp_campaigns;
break;
}
View view = inflater.inflate(resId, null);
((ViewPager)collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
((ViewPager)container).removeView((View)object);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == ((View)arg1);
}
#Override
public Parcelable saveState() {
// TODO Auto-generated method stub
return null;
}
}
and inside my onCreate() mthod of the Activity class:
MyPagerAdapter adapter = new MyPagerAdapter();
ViewPager viewPager = (ViewPager)findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(0);
Is there a way to get the height of the vp_statistics.xml and vp_campaigns.xml layouts and assign it dynamically to ViewPager (#id/viewpager) every time the instantiateItem() object gets called?
Add a weightSum=2 attribute to the parent LinearLayout, and set orientation=vertical.
Set the top child LinearLayout's layout_weight=1. Also, set layout_height=0dip
Wrap the ViewPager into another LinearLayout with layout_weight=1 and layout_height=0dip
I answered a similar question here.
The solution extends ViewPager to override onMeasure() to make wrap_content just work for the height.
use 0dp instead of wrap_content, and for dynamically change that
pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
In order to assign different screen real estate to each linear layout try using the layout_weight parameter. You can reassign this in-code to achieve this 'dynamic' weighting change. Overview here with plenty of Google-able examples of how to achieve the weight layouts in code...
Use RelativeLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="#+id/layout" >
</android.support.v4.view.ViewPager>
</RelativeLayout>

Android different widths of layouts in ViewPager

I want to create some scroll view using Horizontal View Pager. Left view must has full screen width, but right only a quarter of width (it will be a vertical panel like in Dolphin browser). It's possible to do that? I changed android:layout_width in right layout, but it didn't work.
My code:
public class TestActivity extends FragmentActivity {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
MyPagerAdapter adapter = new MyPagerAdapter();
ViewPager pager = (ViewPager) findViewById(R.id.panelPager);
pager.setAdapter(adapter);
pager.setCurrentItem(0);
}
}
main_view.xml
<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/panelPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MyPagerAdapter.java
public class MyPagerAdapter extends PagerAdapter {
#Override
public int getCount() {
return 2;
}
#Override
public Object instantiateItem(final View collection, final int position) {
LayoutInflater inflater =
(LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
switch (position) {
case 0:
resId = R.layout.left;
break;
case 1:
resId = R.layout.right;
break;
}
View view = inflater.inflate(resId, null);
((ViewPager) collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(final View arg0, final int arg1, final Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(final View arg0, final Object arg1) {
return arg0 == ((View) arg1);
}
left.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LEFT" />
</LinearLayout>
right.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="50dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/light_blue" >
<TextView
android:id="#+id/textView2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="RIGHT"/>
</LinearLayout>
Check Murphy's answer on this question. You need to override PagerAdapter's getPageWidth() method on your PagerAdapter class, like this for example:
#Override
public float getPageWidth(int page) {
if(page==0) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return (float)LEFT_FRAGMENT_PIXEL_WIDTH / size.x;
}
else
return super.getPageWidth(page);
}
Looking at the source for ViewPager, this isn't something it's designed to do; it uses its own width to calculate scroll distances etc, with the clear assumption that all children will have the same width as the ViewPager itself.
For your specific case there may be a hacky workaround, though. You can specify a margin between adjacent pages, and this margin can be negative. This may give the result you want, provided the Z-ordering of the ViewPager's children is appropriate. Give it a try, and see whether it does what you need.
Adrian is exactly right. ViewPager isn't designed to show a portion of the next post as a preview/teaser but it can do it. In my ViewPagerCursorAdapter extends PagerAdapter class I run this:
public Object instantiateItem(View collection, final int position) {
cursor.moveToPosition(position);
View newView = getPageView(cursor, collection);
if (cursor.getCount() > 1) {
((ViewPager)collection).setPageMargin(-overlapMargin);
if (! cursor.isLast()) { newView.setPadding(0, 0, overlapMargin, 0); }
}
((ViewPager) collection).addView(newView);
return newView; //returns the object reference as the tag for identification.
}
You will run into a strange z overlapping issue. The trick is to either apply the background only to ViewPager's background or to apply it to the view inside the newView you just set the padding for. Looks good and works great.

Categories

Resources