Android 带有 PageTransformer 和 SceneTransition 的 ViewPager
Android ViewPager with PageTransformer and SceneTransition
感谢您的光临。
我一直在使用 PageTransformer
和 TransitionManager
的组合时遇到奇怪的行为。
我使用的层次结构相当简单:viewPager
,每个页面都是 fragment
。该片段有两种不同的布局,随 TransitionManager.go()
.
而变化
问题:
如果我只是滚动浏览 viewPager,一切都很好,我的 pageTransformer 应用正确的值,创建所需的视差效果。
如果我只是来回单击以更改页面内的场景,我也会得到所需的输出。
然而,每当我使用 TransitionManager.go()
(让我们说两次,回到第一个布局)然后开始滚动我的 viewPager 时,视差效果就不会再出现了。
我的问题:
同时使用 PageTransformer
和 TransitionManager
是否有任何我无法找到的已知问题?
我的代码:
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>
我的适配器相当简单:
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();
}
}
然后是我的 PageTransformer,它独立移动视图的每个子视图
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;
}
}
}
最后是我的 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;
}
}
}
最后,这是一张显示所发生情况的 gif。可以看到,开头的"Item 1"有视差效果。来回切换场景后,PageTransformer 将不再适用。
提前致谢!
我会回答我自己的问题,以防有人遇到与我相同的问题。
问题来自我在片段中使用的 rootLayout 不是 "the right one",因此 TransitionManager
在返回第一个场景时添加了一个额外的层。
这是我更改的内容:
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);
}
由于我在我的层次结构中添加了另一层,我还必须稍微更改我的 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;
}
}
}
感谢您的光临。
我一直在使用 PageTransformer
和 TransitionManager
的组合时遇到奇怪的行为。
我使用的层次结构相当简单:viewPager
,每个页面都是 fragment
。该片段有两种不同的布局,随 TransitionManager.go()
.
问题: 如果我只是滚动浏览 viewPager,一切都很好,我的 pageTransformer 应用正确的值,创建所需的视差效果。 如果我只是来回单击以更改页面内的场景,我也会得到所需的输出。
然而,每当我使用 TransitionManager.go()
(让我们说两次,回到第一个布局)然后开始滚动我的 viewPager 时,视差效果就不会再出现了。
我的问题:
同时使用 PageTransformer
和 TransitionManager
是否有任何我无法找到的已知问题?
我的代码:
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>
我的适配器相当简单:
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();
}
}
然后是我的 PageTransformer,它独立移动视图的每个子视图
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;
}
}
}
最后是我的 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;
}
}
}
最后,这是一张显示所发生情况的 gif。可以看到,开头的"Item 1"有视差效果。来回切换场景后,PageTransformer 将不再适用。
提前致谢!
我会回答我自己的问题,以防有人遇到与我相同的问题。
问题来自我在片段中使用的 rootLayout 不是 "the right one",因此 TransitionManager
在返回第一个场景时添加了一个额外的层。
这是我更改的内容:
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);
}
由于我在我的层次结构中添加了另一层,我还必须稍微更改我的 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;
}
}
}