and thank you for stopping by.
I've been facing a weird behavior using the combination of both PageTransformer
and TransitionManager
.
The hierarchy I'm using is fairly easy : A viewPager
with each page being a fragment
. The fragment has two different layouts, changing with the TransitionManager.go()
.
The issue : If I just scroll through the viewPager, everything is fine, and my pageTransformer applies the right values, creating the desired parallax effect. If I just click back and forth to change scenes inside a page, I also get the desired output.
However, whenever I use the TransitionManager.go()
(let's say twice, to go back to the first layout) and then start scrolling through my viewPager, the parallax effect doesn't occur anymore.
My question :
Is there any known issue I haven't been able to find with using both a PageTransformer
and a TransitionManager
at the same time?
My code :
Fragment1.java
public class Fragment1 extends Fragment {
private Scene mStartScene;
private Scene mInfoScene;
private Transition mTransition;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.view_pager_item_default, container, false);
RelativeLayout rootLayout = (RelativeLayout) v.findViewById(R.id.p1);
mTransition = new ChangeBounds();
mTransition.setDuration(400);
mStartScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_default, getContext());
mInfoScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_details, getContext());
return (v);
}
public void changeScene(View v) {
Scene tmp = mInfoScene;
mInfoScene = mStartScene;
mStartScene = tmp;
TransitionManager.go(mStartScene, mTransition);
}
}
view_pager_item_default.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/p1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:elevation="20dp"
android:text="Item 1"
android:onClick="changeScene"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="60dp"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:padding="20dp"
android:layout_height="wrap_content"
android:background="@drawable/white_shape"
android:textSize="40sp"
android:gravity="center"
android:textColor="#000000"/>
<ImageView
android:id="@+id/imageView"
android:elevation="19dp"
android:scaleType="centerCrop"
android:layout_marginBottom="-10dp"
android:layout_centerHorizontal="true"
android:src="@mipmap/big_image"
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
view_pager_item_details.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/p1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:elevation="20dp"
android:text="Item 1 description"
android:onClick="changeScene"
android:layout_marginTop="150dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/white_shape"
android:clickable="true"
android:textSize="30sp"
android:gravity="center"
android:textColor="#000000"/>
<ImageView
android:id="@+id/imageView"
android:elevation="21dp"
android:layout_marginTop="50dp"
android:layout_centerHorizontal="true"
android:src="@mipmap/small_image"
android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
My adapter is fairly simple :
public class MyPagerAdapter extends FragmentPagerAdapter {
private final List fragments;
public MyPagerAdapter(FragmentManager fm, List fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return (Fragment) this.fragments.get(position);
}
@Override
public int getCount() {
return this.fragments.size();
}
}
Then is my PageTransformer which moves each children of the view independently
public class MyPagerTransformer implements ViewPager.PageTransformer {
private float mParallaxCoeff;
private float mDistanceCoeff;
public MyPagerTransformer(float parallax, float distance) {
mParallaxCoeff = parallax;
mDistanceCoeff = distance;
}
@Override
public void transformPage(View page, float position) {
float coefficient = page.getWidth() * mParallaxCoeff;
ViewGroup vG = (ViewGroup) page;
for (int i = vG.getChildCount() - 1; i >= 0; --i) {
View v = vG.getChildAt(i);
if (v != null) {
v.setTranslationX(coefficient * (position * position * position));
}
coefficient *= mDistanceCoeff;
}
}
}
And lastly my Activity :
public class MainActivity extends AppCompatActivity {
private Fragment1 mFrag1;
private Fragment1 mFrag2;
private Fragment1 mFrag3;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
mViewPager = (ViewPager) findViewById(R.id.main_view_pager);
CirclePageIndicator indicator = (CirclePageIndicator) findViewById(R.id.indicator);
if (mViewPager != null) {
mViewPager.setPageTransformer(true, new MyPagerTransformer(8.0f, 8.0f));
//vp.addOnPageChangeListener(listener);
List<Fragment> fragments = new ArrayList<>();
mFrag1 = new Fragment1();
mFrag2 = new Fragment1();
mFrag3 = new Fragment1();
fragments.add(mFrag1);
fragments.add(mFrag2);
fragments.add(mFrag3);
PagerAdapter realViewPagerAdapter = new MyPagerAdapter(super.getSupportFragmentManager(), fragments);
mViewPager.setAdapter(realViewPagerAdapter);
indicator.setViewPager(mViewPager);
}
}
public void changeScene(View v) {
switch (mViewPager.getCurrentItem()) {
case 0:
mFrag1.changeScene(v);
break;
case 1:
mFrag2.changeScene(v);
break;
case 2:
mFrag3.changeScene(v);
break;
default:
break;
}
}
}
Lastly, here's a gif showing what happens. As you can see, at the beginning "Item 1" has the parallax effect. After switching scenes back and forth, the PageTransformer won't apply anymore.
Thanks in advance !
I will answer my own question in case anyone would bump into the same issue as I did.
The problem came from the rootLayout I was using in the fragment not being "the right one", therefore the TransitionManager
was adding an extra layer when going back to the first scene.
Here's what I changed :
Fragment1.java
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//view_pager_root.xml is a simple empty FrameLayout
View v = inflater.inflate(R.layout.view_pager_root, container, false);
RelativeLayout rootLayout = (RelativeLayout) v.findViewById(R.id.p1);
mTransition = new ChangeBounds();
mTransition.setDuration(400);
mStartScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_default, getContext());
mInfoScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_details, getContext());
return (v);
}
Since I added another layer into my hierarchy, I also had to change slightly my PageTransformer
:
@Override
public void transformPage(View page, float position) {
float coefficient = page.getWidth() * mParallaxCoeff;
//vG is the FrameLayout
ViewGroup vG = (ViewGroup) page;
if (vG.getChildAt(0) instanceof ViewGroup) {
//vG is now the RelativeLayout from the scene
vG = (ViewGroup) vG.getChildAt(0);
for (int i = vG.getChildCount() - 1; i >= 0; --i) {
View v = vG.getChildAt(i);
if (v != null) {
v.setTranslationX(coefficient * (position * position * position));
}
coefficient *= mDistanceCoeff;
}
}
}