Android - ViewPager动画(纸叠)
Android - ViewPager Animation (paper stack)
我有一些项目要显示,目前我使用带有滚动动画的列表视图。但是,我想制作 Shazam Discover 面板的相同动画,我不知道是否必须使用 ListView 或其他 Widget ...
任何的想法 ?
提前致谢 !
我找到了两个可以找到好东西的地方。
Github Best UI
希望这两个对你有帮助;)
感谢这两个链接,
我解决了我自己的问题:),所以我post这里是解决方案
为了重现上面相同的动画(如纸堆),我最终使用了垂直 viewpager with a pagetransformer animation
所以我有:
- ViewPager : 包含要显示的项目
- PagerAdapter : 实例化每个项目的适配器
- PageTransformer : 幻灯片动画
- A Fragment : 包含 ViewPager
叠纸动画
这里的第一个难点是制作叠纸动画,就是把旧的物品叠在当前的物品后面...在每个物品之间创建一个"z-index"顺序,否则旧的物品会在前面和后面的电流。 (我说得有道理吗?:P)
所以我决定向 ViewPager 的每个视图添加一个标签,并将其作为其位置的值,并将其用于 PageTransformer 来定义视图的 translationZ
。所以 ViewPager 的第一个项目视图,所以位置 = 0,有一个 z-index = 0,第二个 z-index = 1 ...所以创建一个纸堆!
正确的"Destruction"
第二个困难是在完美的时刻隐藏和显示上一个项目...因为默认情况下 ViewPager 只显示 2 个视图,并在加载第三个时调用 destroyItem
。所以我们看到最后一个视图的销毁...在我的第一条消息的视频中我们可以看到当当前视图在其他视图之前通过时最后一个视图被删除,那么如何做到这一点?
我决定在我的 PagerAdapter 中创建一个 ArrayList<View>
并在调用 instantiateItem
函数时添加每个视图。我还创建了一个 Getter 来从我的 Fragment 中获取 ArrayList。在我的 Framgment 中,我向我的 ViewPager 添加了一个 addOnPageChangeListener
。使用此侦听器,我可以确定显示 ViewPager 的哪个视图(带有位置和视图的 ArrayList)和 positionOffset,使用这两个变量我可以隐藏或显示以前的视图完美时刻...
代码
我在下面澄清了我的代码以使其通用
片段
public class MyFragment extends Fragment {
private ViewPager viewPager;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment, container, false);
viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
final MyPagerAdapter pagerAdapter = new MyPagerAdapter(getActivity());
viewPager.setAdapter(pagerAdapter);
viewPager.setPageTransformer(true, new PaperStackTransformer());
viewPager.setRotation(90); // Vertical viewpager
viewPager.setOffscreenPageLimit(10); // To display more than 2 view (and 10 to avoid bugs...)
final ArrayList<View> views = MyPagerAdapter.getViews();
final float[] previousPositionOffset = new float[1];
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset > 0.9 || positionOffset < 0.1) return;
float dif = previousPositionOffset[0] - positionOffset;
// Change values (0.40 and 0.70) to conform to your PageViewer view
if (positionOffset > 0.40 && positionOffset < 0.70 ){
// at this moment current view hide the previous
if (dif < 0) {
// If we scroll down we hide the previous view
int p = position - 2;
if (p >= 0 && views.get(p).getVisibility() == View.VISIBLE) {
views.get(p).setVisibility(View.INVISIBLE);
}
}
else if (dif > 0) {
// If we scroll up we show the previous view
int p = position - 2;
if (p >= 0 && views.get(p).getVisibility() == View.INVISIBLE) {
views.get(p).setVisibility(View.VISIBLE);
}
}
}
previousPositionOffset[0] = positionOffset;
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
return rootView;
}
}
PagerAdapter
public class MyPagerAdapter extends PagerAdapter {
private ArrayList<View> views;
...
public ArrayList<View> getViews() {
return views;
}
...
@Override
public Object instantiateItem(ViewGroup container, int position) {
...
View view = inflater.inflate(R.layout.view, null, false);
...
view.setTag(position); // To the "z-index" order on PageTransformer
view.setRotation(-90f); // Vertical ViewPager
((ViewPager) container).addView(view);
views.add(view); // add the view to the list
return view;
}
...
}
PageTransformer
public class PaperStackTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.9f;
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
view.setTranslationX(1150 * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else if (position <= 0) { // [-1,0]
view.setAlpha(1 - position);
view.setTranslationX(1150 * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else if (position <= 1) { // (0,1]
view.setAlpha(1);
view.setTranslationX(1);
view.setScaleX(1);
view.setScaleY(1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else { // (1,+Infinity]
view.setAlpha(1);
}
}
}
结论
所以 listview 不是解决方案,我希望这个片段能帮助一些人。
my paper stack animation :D
我有一些项目要显示,目前我使用带有滚动动画的列表视图。但是,我想制作 Shazam Discover 面板的相同动画,我不知道是否必须使用 ListView 或其他 Widget ...
任何的想法 ?
提前致谢 !
我找到了两个可以找到好东西的地方。
Github Best UI
希望这两个对你有帮助;)
感谢这两个链接,
我解决了我自己的问题:),所以我post这里是解决方案
为了重现上面相同的动画(如纸堆),我最终使用了垂直 viewpager with a pagetransformer animation
所以我有:
- ViewPager : 包含要显示的项目
- PagerAdapter : 实例化每个项目的适配器
- PageTransformer : 幻灯片动画
- A Fragment : 包含 ViewPager
叠纸动画
这里的第一个难点是制作叠纸动画,就是把旧的物品叠在当前的物品后面...在每个物品之间创建一个"z-index"顺序,否则旧的物品会在前面和后面的电流。 (我说得有道理吗?:P)
所以我决定向 ViewPager 的每个视图添加一个标签,并将其作为其位置的值,并将其用于 PageTransformer 来定义视图的 translationZ
。所以 ViewPager 的第一个项目视图,所以位置 = 0,有一个 z-index = 0,第二个 z-index = 1 ...所以创建一个纸堆!
正确的"Destruction"
第二个困难是在完美的时刻隐藏和显示上一个项目...因为默认情况下 ViewPager 只显示 2 个视图,并在加载第三个时调用 destroyItem
。所以我们看到最后一个视图的销毁...在我的第一条消息的视频中我们可以看到当当前视图在其他视图之前通过时最后一个视图被删除,那么如何做到这一点?
我决定在我的 PagerAdapter 中创建一个 ArrayList<View>
并在调用 instantiateItem
函数时添加每个视图。我还创建了一个 Getter 来从我的 Fragment 中获取 ArrayList。在我的 Framgment 中,我向我的 ViewPager 添加了一个 addOnPageChangeListener
。使用此侦听器,我可以确定显示 ViewPager 的哪个视图(带有位置和视图的 ArrayList)和 positionOffset,使用这两个变量我可以隐藏或显示以前的视图完美时刻...
代码
我在下面澄清了我的代码以使其通用
片段
public class MyFragment extends Fragment {
private ViewPager viewPager;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment, container, false);
viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
final MyPagerAdapter pagerAdapter = new MyPagerAdapter(getActivity());
viewPager.setAdapter(pagerAdapter);
viewPager.setPageTransformer(true, new PaperStackTransformer());
viewPager.setRotation(90); // Vertical viewpager
viewPager.setOffscreenPageLimit(10); // To display more than 2 view (and 10 to avoid bugs...)
final ArrayList<View> views = MyPagerAdapter.getViews();
final float[] previousPositionOffset = new float[1];
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset > 0.9 || positionOffset < 0.1) return;
float dif = previousPositionOffset[0] - positionOffset;
// Change values (0.40 and 0.70) to conform to your PageViewer view
if (positionOffset > 0.40 && positionOffset < 0.70 ){
// at this moment current view hide the previous
if (dif < 0) {
// If we scroll down we hide the previous view
int p = position - 2;
if (p >= 0 && views.get(p).getVisibility() == View.VISIBLE) {
views.get(p).setVisibility(View.INVISIBLE);
}
}
else if (dif > 0) {
// If we scroll up we show the previous view
int p = position - 2;
if (p >= 0 && views.get(p).getVisibility() == View.INVISIBLE) {
views.get(p).setVisibility(View.VISIBLE);
}
}
}
previousPositionOffset[0] = positionOffset;
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
return rootView;
}
}
PagerAdapter
public class MyPagerAdapter extends PagerAdapter {
private ArrayList<View> views;
...
public ArrayList<View> getViews() {
return views;
}
...
@Override
public Object instantiateItem(ViewGroup container, int position) {
...
View view = inflater.inflate(R.layout.view, null, false);
...
view.setTag(position); // To the "z-index" order on PageTransformer
view.setRotation(-90f); // Vertical ViewPager
((ViewPager) container).addView(view);
views.add(view); // add the view to the list
return view;
}
...
}
PageTransformer
public class PaperStackTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.9f;
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
view.setTranslationX(1150 * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else if (position <= 0) { // [-1,0]
view.setAlpha(1 - position);
view.setTranslationX(1150 * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else if (position <= 1) { // (0,1]
view.setAlpha(1);
view.setTranslationX(1);
view.setScaleX(1);
view.setScaleY(1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) view.setTranslationZ((int) view.getTag()*1.0f);
} else { // (1,+Infinity]
view.setAlpha(1);
}
}
}
结论
所以 listview 不是解决方案,我希望这个片段能帮助一些人。 my paper stack animation :D