Android ScrollView inside ViewPager - how to make swiping more efficient - android

I'm developing application where I've got ViewPager, inside of which I've got ScrollView that contains TextView. Everything is working, but when I'm trying to scroll ViewPager, I must "draw" absolutely horizontal line to swipe a page. Otherwise, if drawn line is not perfectly horizontal, it will swap ScrollView instead.
Here's image where I'm trying to explain what is my problem. Red line represents user's swipe.
As you can see, the last one won't swipe ViewPager, but ScrollView. And there's problem. When you are holding phone in one hand, you are using your thumb to swipe and that means you are not drawing perfectly horizontal line, but rather line that is similar to line shown on last Nexus. So my question is - how to make this swiping more efficient in order to improve user experience?
Here's some of my code that I'm using:
fragment.xml
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/divider"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp" >
</android.support.v4.view.ViewPager>
CustomPagerAdapter.java
ScrollView scroll;
TextView text;
#Override
public Object instantiateItem(ViewGroup container, int position) {
//Adding scrollview
scroll = new ScrollView(context);
//Creating TextView
text = new TextView(context);
text.setText(stringArray[position]);
text.setTextAppearance(context, android.R.style.TextAppearance_Medium);
//Adding TextView to ScrollView
scroll.addView(text, 0);
//Adding ScrollView to ViewPager
((ViewPager) container).addView(scroll, 0);
return scroll;
}
Fragment.java
CustomPagerAdapter adapter;
ViewPager pager;
...
///Set adapter
adapter = new CustomPagerAdapter(getActivity().getApplicationContext(), stringArray);
}
pager.setAdapter(adapter);
//Set onPagerChanger event
pager.setOnPageChangeListener(new OnPageChangeListener(){
#Override
public void onPageScrollStateChanged(int arg0) {}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
pager.getParent().requestDisallowInterceptTouchEvent(true);
}
#Override
public void onPageSelected(int position) {
titleUpdater(position);
activePosition = position;
}
});

Related

View Pager layouts not keep match parent after switch views

I have four layouts inside of my viewpager that are supposed to match width/height of its parent (the viewpager). When the activity starts the first page appears to do that, but as soon as you swipe to the next one this weird gap appears. The gap will stay until the activity is restarted. How do I get rid of this gap?
Here's a video of what's happening: https://youtu.be/EA51HZuFruY
XML of one of the layouts (the other three are identical only having different background colors)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#color/blue">
<Button
android:id="#+id/tab1_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:onClick="tab1Click"/>
</RelativeLayout>
Code for the viewpager's adapter
private class TabPagerAdapter extends PagerAdapter {
private ArrayList<Integer> layouts = new ArrayList<>();
TabPagerAdapter() {
layouts.add(R.layout.tab_menu_1);
layouts.add(R.layout.tab_menu_2);
layouts.add(R.layout.tab_menu_3);
layouts.add(R.layout.tab_menu_4);
}
#Override
public int getCount() {
return layouts.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == (View) object;
}
#Override
public Object instantiateItem(ViewGroup collection, int position) {
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(layouts.get(position), collection, false);
collection.addView(view);
return view;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
}
EDIT: My layouts inside the viewpager are not matching parent if more than two views are in the viewpager. I can also tell it's not the viewpager not keeping it's constraints that I've given them.
EDIT: After about a month I figured out that changing the offscreen page limit to support the maximum number of screen that could ever be offscreen stops the problem. While I'd be fine with this it's causing slow down in the app, but maybe this might reveal the actually problem.

Viewpager no longer swipeable after onClick is set on inflated View

I have a viewpager, which contain an image. If I create the image view using an xml layout as below
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
final int realPosition = getItemPosition(position);
View view = LayoutInflater.from(mContext).inflate(R.layout.item_adsong, container, false);
ImageView imageView = (ImageView)view.findViewById(R.id.adsong_img);
/... set to the image.../
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickPage(realPosition);
}
});
container.addView(view);
return view;
}
After adding the onClickListener, I can no longer swipe my view pager from page to page. Without the onClickListener, I could do so.
However, if I create my ImageView from the code (instead of using xml layout) as below
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
final int realPosition = getItemPosition(position);
ImageView view = new ImageView(mContext);
/... set to the image.../
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickPage(realPosition);
}
});
container.addView(view);
return view;
}
I could now swipe the view pager, and I could do the click as I like. Why my first example above is intercepting the swipe, while the second is not? How could I fix my first example above to allow both swipe and onClick still work (I prefers using the layout, as I have several more e.g. some TextViews than just ImageView to show in my view pager). Thanks!
After further thorough debug and investigation, found the issue as per https://groups.google.com/forum/#!topic/android-developers/wIqNP4fzJQc. The cause of the issue is because the existence of TextView in my .xml layout. The TextView is scrollable by default.
Given the TextView is scrollable, the ViewPager then would allow the text to scroll by not intercepting the scrolling touch, and passing to the child. Hence the scrolling touch of the ViewPager is not working.
To fix the problem I override the canScrollHorizontal function of the TextView to return false. This solve the problem
public class MyTextView extends TextView {
//...
#Override
public boolean canScrollHorizontally(int direction) {
return false;
}
//....
Note: using setHorizontallyScrolling(false) or setting the android:scrollHorizontally="false" attribute in the XML of the TextView doesn't solve the problem somehow.
Hope this helps some who face the ViewPager no longer scrollable issue.

Android: How to implement ViewPager with scroll bar?

I have a challenging problem and wanted to see if the community has some comments about its implementation.
I have a ViewPager and added 20 pages in it, and each page has a WebView. – This provides vertical page flipping between multiple websites
It should work as a ViewPager by default but when I pinch to zoom, each page will shrink and the ViewPager will scroll like a List View.
I didn’t want to use a different view like a List View as I want a smooth transition and the two modes use the same web contents so want to avoid any construction/deconstruction that might affect a smooth transition.
I was able to implement this scrolling ViewPager with VelocityViewPager.
What I want to do is add a scrollbar to navigate down the pages by holding and dragging a scroller, just like a PC’s behaviour – as opposed to a ListView which only shows the scrollbar but allows no interaction. I have made a custom view that looks like a scrollbar and performs a ViewPager’s fake drag as the scrollbar is moved. The problem is I can only scroll pages ViewPager is holding - so when the ViewPager keeps the whole 20 pages, it works well but If I keep 3 pages as default to make use of page recycling, it doesn’t scroll past 3. It seems as though it doesn’t create the next pages that it usually would when scrolling with your finger.
I’m not sure why ViewPager doesn’t create next pages while fake dragging. Is there anything I have to do other than beginFakeDrag(), endFakeDrag() and fakeDragBy()?
And, Is there any way I can implement this behaviour without keeping all 20 pages in ViewPager?
Have a look into this code, this may be useful to you:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPagerAdapter adapter = new ViewPagerAdapter(this, imageArra);
ViewPager myPager = (ViewPager) findViewById(R.id.myfivepanelpager);
myPager.setAdapter(adapter);
myPager.setCurrentItem(0);
}
private int imageArra[] = { R.drawable.gallery_photo_1, R.drawable.gallery_photo_2,
R.drawable.gallery_photo_3, R.drawable.gallery_photo_5,
R.drawable.gallery_photo_6, R.drawable.gallery_photo_7,
R.drawable.gallery_photo_8, R.drawable.ic_launcher };
}
and ViewPager class is:
public class ViewPagerAdapter extends PagerAdapter {
Activity activity;
int imageArray[];
public ViewPagerAdapter(Activity act, int[] imgArra) {
imageArray = imgArra;
activity = act;
}
public int getCount() {
return imageArray.length;
}
public Object instantiateItem(View collection, int position) {
ImageView view = (ImageView) collection.findViewById(R.id.image);
/*
* view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
* LayoutParams.FILL_PARENT)); view.setScaleType(ScaleType.FIT_XY);
*/
view.setBackgroundResource(imageArray[position]);
((ViewPager) collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
}

Can I set viewpager's item width?

I hope I can show 3 items in a page of viewpager, but now I only could set viewpager's padding value and margin value, so it only show one item in a page of viewpager. How can I set the item width? I think if I can set more little width of item, the viewpager will show more items in a page.
Quick Answer
What you want is overriding getPageWidth in the PagerAdapter implementation you made for that ViewPager.
For example setting it to 0.8f will make a single page cover only 80% of the viewpagers width so that part of the next and/or previous pages are visible.
#Override
public float getPageWidth(final int position) {
return 0.8f;
}
More information at https://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getPageWidth(int)
Other remarks
Also note that the negative margins will only cause the separate pages to overlap each other. The margin is used to define the space between each page.
If no alternative pageWidth is configured (there is no setter, only the override) it will cover 100% by default making no part of the other pages visible unless dragged.
Code example
A very nice overview of what is possible can be found here https://commonsware.com/blog/2012/08/20/multiple-view-viewpager-options.html
The view pager in your layout
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
Example of an inline configured Adapter implementation, this would go in the onCreate or onViewCreated methods:
// get a reference to the viewpager in your layout
ViewPager mViewPager = (ViewPager) findViewById(R.id.viewpager);
// this margin defines the space between the pages in the viewpager mViewPager.setPageMargin(context.getResources().getDimensionPixelSize(R.dimen.margin_normal));
// setting the adapter on the viewpager, this could/should be a proper Adapter implementation in it's own class file instead
mViewPager.setAdapter(new PagerAdapter() {
// just example data to show, 3 pages
String[] titles = {"Eins", "Zwei", "Drei"};
int[] layouts = {R.layout.layout1, R.layout.layout2, R.layout.layout3};
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
// here you can inflate your own view and dress up
ViewGroup layout = (ViewGroup) inflater.inflate(layouts[position], container, false);
container.addView(layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
#Override
public float getPageWidth(final int position) {
return 0.8f;
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
#Override
public int getCount() {
return layouts.length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
Example code based on https://newfivefour.com/android-viewpager-simple-views.html
Have you tried setting the page margins to a negative value, see setPageMargin(int)? If I remember correctly, I read someone realizing something similar to what you're describing that way.
Alternatively, you could have a look at using a Gallery in stead, although I have to admit I'm not a big fan of them as they seem to be less flexible and more buggy.

Having vertically scrolling pages in ViewPager

This may be obvious and a completely unneeded post but I had been having quite an issue resolving a way to allow vertical scrolling functionality on pages in a VewPager and there were very few resolutions coming across google and even here. I found some claiming to resolve the issue but they seemed to be extended and convoluted. So for those who may be searching for the same issue heres the solution. With this (and you will want to make bigger strings than what I wrote here) you will be able to vertically scroll content and swipe between pages.
layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="#+id/conpageslider"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
scrolling viewpager class
public class ScrollingViewPager extends Activity{
private ViewPager pager;
private Context cxt;
private CharSequence[] pages = {"stuff", "more stuff", "other stuff"};
private PageSlider ps;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.layout);
cxt = this;
ps = new PageSlider();
pager = (ViewPager) findViewById(R.id.conpageslider);
pager.setAdapter(ps);
}
public class PageSlider extends PagerAdapter{
#Override
public int getCount() {
return pages.length;
}
#Override
public Object instantiateItem(View collection, int position) {
ScrollView sc = new ScrollView(cxt);
sc.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
sc.setFillViewport(true);
TextView tv = new TextView(cxt);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
tv.setText(pages[position]);
tv.setPadding(5,5,5,5);
sc.addView(tv);
((ViewPager) collection).addView(sc);
return sc;
}
#Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((ScrollView) view);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view==((ScrollView)object);
}
}
}
I am open to critique on the code but at least here is a functioning example
I made similar one that using fragments in viewpager.
tabWigdet can be shown or not.
that example included in android-support-v4 demo application.
I achieved this by setting screenOrientation to landscape, then putting the content of the viewpager as if it is in the portrait mode.

Categories

Resources