Best way to implement a nested viewpager - android

I have a viewpager that inflates a layout that (sometimes) has another viewpager to view photos
<androidx.viewpager.widget.ViewPager
android:id="#+id/gallery"
android:clickable="true"
android:focusableInTouchMode="true"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
They both use swipes. I know there is a similar question to this, but seeing as all the answers are old and didn't work for me, does anyone know any good methods of letting users swipe the nested viewpager without forcing a swipe on the parent viewpager? I know it can be done since apps like Diaro do it, but I'm not sure how to go about it myself

Related

Viewpager2 scroll stops working when scrolling back

I am facing a weird issue, I have a Viewpager2, the fragment page contains a Scrollview, HorizontalScrollView, and a RecyclerView.
When I launch the fragment that hosts the ViewPager the UI works, it also works if I swipe right, but as soon as I swipe left to the previous page the touch stops working, I lose the ability to swipe up and down on the page.
I feel lost here, it worked perfectly fine with the old ViewPager
ViewPager fragment page
<ScrollView
android:isScrollContainer="true"
android:measureAllChildren="true"
android:background="?backgroundColor"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
...
</androidx.constraintlayout.widget.ConstraintLayout>
<ScrollView/>
ViewPager
<androidx.viewpager2.widget.ViewPager2
android:orientation="horizontal"
android:id="#+id/pager"
android:layout_width="0dp"
android:layout_height="0dp"
...
/>
I fixed the issue by updating ViewPager's PageTransformer.
I extended ViewPager2.PageTransformer on my PageTransformer thinking the old transformer would work just fine.
Looks like this is not the case, the old version was missing the translationZ looks like not setting the translationZ causes this behavior.

ViewPager in CoordinatorLayout shrinks unexpectedly

In my Android app running on Android 5.1.1 I have a layout using a Toolbar with a TabLayout, and underneath is a ViewPager. All of these are put together in a CoordinatorLayout.
In the first page of the ViewPager is a RecyclerView serving CardView items.
My problem is that my ViewPager keeps getting resized in a way so that my CardView list items are cropped.
My main layout looks basically like this:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
And the first fragment served by my ViewPager looks like:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
</FrameLayout>
This renders something that looks like this:
When clicking a button in my layout, I use startActivityForResult to invoke another activity, and when returning to my activity sometimes suddenly my list is cropped so that only half of the first item is visible:
After swiping horizontally to another pager in the ViewPager and then back, the problem disappears, so it does seem a re-layout has not been properly triggered. Pressing HOME and then resuming my activity does NOT resolve the problem though. Note that this happens even if I am not modifying my layout in any way, I am simply returning from a startActivityForResult call. And yes, it only happens sometimes... And I have no background threads running that could explain the apparent random behavior.
At first I thought it was the RecyclerView that had shrunk, but using HierarchyViewer I was able to find that it was actually the entire ViewPager that had shrunk to about half its original height.
I tried various hacks to get around this, including calling invalidate() and requestLayout() on my entire view hiearchy, but nothing seemed to help (although swiping to another page and back again fixes it). Also, those are not the kind of solutions I want to resort to... Then I tried changing my ViewPager height to wrap_content, which did in fact solve this particular problem; after returning to my activity the first item in my RecyclerView is never cropped, and I can scroll down to the other items. However, now instead the very last item of my list is always cropped, as can be seen in this screenshot where the list is scrolled all the way to the bottom:
Since I am now at a point where I don't really understand what's going on, I need some help. What should I really use as the layout_height for my ViewPager, and - above all - why? To me, match_parent makes sense, but how should I be thinking here? Is there a rational reason my views got cropped when using match_parent, or did I in fact encounter a bug in ViewPager, RecyclerView and/or CoordinatorLayout? How do I make sure that my ViewPager consistently fills the entire screen area below the AppBar, and that my RecyclerView can be scrolled vertically to properly render all CardView list items?
It turns out this is almost certainly a bug in CoordinatorLayout or even more likely in AppBarLayout$ScrollingViewBehavior. In an effort to create a MCVE I realized it was the fact that my sub-activity had an IME on screen that caused the shrinking of the ViewPager - when my activity is resumed after onActivityResult, the ViewPager is shrunk as a result of reduced screen real-estate from the IME, but is never expanded again despite the fact that the IME is no longer being shown and the fact that the CoordinatorLayout is indeed expanded.
After debugging and stepping through onLayout and onMeasure of CoordinatorLayout and ViewPager I am now fairly sure that the CoordinatorLayout does not properly propagate the change in size to its children.
I found that I can "fix" the problem by calling requestLayout on my ViewPager, but only if the call is sufficiently delayed (10 ms never works, 100 ms works most of the time):
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mViewPager.requestLayout();
}
}, 100);
}
This obviously isn't a robust solution, but after investigating some more it turns out I probably don't even need CoordinatorLayout since I don't really have any advanced scrolling behavior. So my solution will be to simply go with a LinearLayout or RelativeLayout as my root view group instead. Nice and simple, no need to complicate things.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
I will however try to condense this into a simple example and file a bug with Google.
As to what I should use as the height for my ViewPager, my original use of match_parent still seems reasonable. The fact that wrap_content solved the problem (but caused other problems) is probably just due to inconsistencies caused by the bug.
I've experienced a similar issue when using an older version of the support library.
See these related issues:
https://code.google.com/p/android/issues/detail?id=176406
https://code.google.com/p/android/issues/detail?id=176187
Make sure you're using the latest Support library, version 23.1 as of this writing.
In your fragment just remove the frameLayout and make recyclerView parent...I hope it will work:
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp">
<android.support.v7.widget.RecyclerView/>

Is there any way to have embedded scrollable tabs?

I have a layout in my head that should look like that: http://i.imgur.com/H1nTRvd.png
Only part that will be dynamic is the blue one. I don't know the number of tabs that will be created before I load the activity, hence the number is acquired from server (could be either 5 or 24 for all I know).
The bottom buttons should not move when I swipe and the blue area changed.
Currently I have this implemented w/o tabs list using embedded fragment in my activity and gesture listener. There's no good looking transaction animation between fragments.
#Nick Pakhomov: You can use PagerTabStrip
PagerTabStrip
is intended to be used as a child view of a ViewPager widget in your XML layout. PagerTabStrip is most often used with fragment, which is a convenient way to supply and manage the Lifecycle of each fragment.
So here’s how a ViewPager with a PagerTabStrip in it would look like in the layout file:
<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">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_tab_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:textColor="#fff"
/>
</android.support.v4.view.ViewPager>
Please check this PagerSlidingTabStrip demo . I hope it will helps you .

How to use ChrisBanes' ActionBar-PullToRefresh library with Fragments having GridViews

I am trying to use Chris Banes' library Actionbar-PullToRefresh. It can be found here.
I am using Tabs + ViewPager + Fragments in my app.
The problem I'm facing is that my fragment has a GridView and I cannot figure out how to use this library to work with it.
I read through the sample code. He says that all you have to do is, wrap your refreshable view in a PullToRefreshLayout like this:
<uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ptr_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- Your content, here we're using a ScrollView -->
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ScrollView>
</uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout>
This works great for stuff like ListView, ScrollView, GridView, etc. However, apparently this will not work for Fragments (Tabs & ViewPagers). Now, in the sample code he has wrapped the refreshable fragment with a ScrollView INSTEAD of a PullToRefreshLayout.
I cannot do this because my Fragment 1 (under tab 1) has a GridView. Now I cannot add a GridView to a ScrollView because that just wouldn't make sense.
For example, if I put my GridView inside the ScrollView as shown below, it just doesn't make sense:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ptr_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:scrollbarStyle="outsideInset" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFF000" >
<!-- MY GRID VIEW -->
<GridView
...
/>
</RelativeLayout>
</ScrollView>
The above code works. Sort of. (I need to disable scrolling of my GridView and use an ExpandableGridView to get it working properly... which seems like overkill & I'm not even sure if that would work).
If I replace the ScrollView wrapper with anything else like PullToRefreshLayout or any other layout, the refreshing doesn't work.
What to do? How to get my layout to work with this library without wrapping a ScrollView around it?
I hope I was clear enough. Please let me know if you need any more info. I tried to explain it the best I could.
Thanks!
I had a similar issue trying to get it to work with a ListView that I had in one of my tabs.
I solved my issue by using the PullToRefreshAttacher instead of using the layout.
In your Activity that is controlling the ViewPager for the fragments, initialize a PullToRefreshAttacher in onCreate or an init method.
mPullToRefreshAttacher = PullToRefreshAttacher.get(this);
Next make a public method that allows access to the attacher that you just initialized.
public PullToRefreshAttacher getPullToRefreshAttacher() {
return mPullToRefreshAttacher;
}
Then in the fragment you want the refresh functionality.
mPullToRefreshAttacher = ((MainTabActivity) getActivity())
.getPullToRefreshAttacher();
mPullToRefreshAttacher.addRefreshableView(activeListView, this);
Except in your case activeListView would be the reference to your GridView instead of a ListView.
Then make sure your fragment implements OnRefreshListener so you can handle the Refresh.
I have not actually tested this with a GridView so let me know if it works.
Good Luck!

Swipe part of the page using pager view

I have ViewPager with PagerTabStrip , when swiping from page to another, both the pager and the tab will be moving together. (like google paly)
It's working fine. now all the pages have common data, and one part is going to change when swiping, so i don't want to swipe the whole page, just the area that going to change.
As you can see in the following image just the red area will be effected when swipe pages, the green area will not move.
I've searched a lot, but i can't find anything useful, any help would be appreciated.
viewpager code:
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#FFFFFF"
android:textColor="#003366"
android:paddingTop="4dp"
android:paddingBottom="4dp"/>
</android.support.v4.view.ViewPager>
Using swipeyTabs is the answer.
The problem when using PagerTabStrip is that the PagerTabStrip will be inside the ViewPager tag see the following code:
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#FFFFFF"
android:textColor="#003366"
android:paddingTop="4dp"
android:paddingBottom="4dp"/>
</android.support.v4.view.ViewPager>
so you cant separate them form each other.
but when using the SwipeyTabs, each tag will be as a separate part, see the following code:
<net.peterkuterna.android.apps.swipeytabs.SwipeyTabs
android:id="#+id/swipeytabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
swipeytabs:bottomBarColor="#ff96aa39"
swipeytabs:bottomBarHeight="2dip"
swipeytabs:tabIndicatorHeight="3dip"
android:background="#ff3b3b3b"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1" />
In this case, you can customize your layout as you want by dealing with ViewPager and SwipeyTabs as two parts.
In your case, I guess you can put the SwipeyTabs and ViewPager in red position like in the image, and in the green areas, you have to just adjust them as your needs.
I found these links which may help you. Good luck with that.
Swipey tabs sample
ViewPager meets Swipey Tabs
Disclaimer: I misread your post. Separating the ViewPager from the PagerTabStrip may not work or may need another approach. I'll leave the answer here in case it may help anyway.
You can achieve that by embedding the ViewPager in a separate fragment and placing another independent fragment beneath, which is not controlled by the ViewPager.
Basically, your main activity consists of two fragments: one that contains the ViewPager (which contains more fragments), another one that contains your fixed view.
To do it properly, this needs support for nested fragments, which is only available on Android 4.2 or otherwise in the latest support library (revision 11).
Be aware when instantiating your adapter for the ViewPager, you need to use the FragmentManager returned by getChildFragmentManager().

Categories

Resources