我正在阅读一个关于自定义ViewPager
滑动页面动画的示例,该动画需要将页面(View
)翻译成一定数量。该示例来自docs。具体来说,它是关于一个名为ZoomOutPageTransformer
的实现,可以在ViewPager
到setPageTransformer()
上设置,以自定义页面的滑动方式(在其中加入 zoom 动画)。
这是最终结果的样子:
现在,他们描述了他们将如何做到这一点:
在
transformPage()
的实施中,您可以创建 通过确定需要哪些页面来自定义幻灯片动画 根据屏幕上页面的位置进行转换,即 从position
方法的transformPage()
参数中获取。
position
参数指示给定页面的位置 相对于屏幕的中心。这是一个动态的属性 用户滚动页面时更改。当一个页面填充 屏幕,其position
值为0.当页面刚刚离开时 在屏幕的右侧,其position
值为1.如果用户滚动 在第一页和第二页之间,第一页的position
为-0.5和 第二页的position
为0.5。基于position
页面 在屏幕上,您可以通过设置页面来创建自定义幻灯片动画 使用setAlpha()
,setTranslationX()
或等方法的属性setScaleY()
。
这是他们提供的PageTransformer
的实施:
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA +
(scaleFactor - MIN_SCALE) /
(1 - MIN_SCALE) * (1 - MIN_ALPHA));
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
问题:
我无法理解声明,
view.setTranslationX(horzMargin - vertMargin / 2);
我的理解是position
参数的值1.0等于覆盖屏幕宽度,即w。因此,如果页面的中心移动了position
的x个单位,那么以像素/ dp表示的翻译将是w * x。但他们正在使用一些保证金计算来计算翻译金额。
任何人都可以解释他们如何进行此计算以及我的计算会出现什么问题?
答案 0 :(得分:3)
此处缺少一件事,PageTransformer应用于已定位的 AFTER 视图。
因此,无论是否将PageTransformer附加到PageView - 当您在页面之间滚动时 - 您只需使用SNAP功能进行滚动(如在LiseView中)。
PageTransformer只会在其上添加效果。
所以目的,
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
不来移动页面 - 但是为了补偿页面缩小。
没有它,页面会有一些丑陋的副作用。尝试,删除行:) - 视图将向右/向左,但定位将关闭。
因此,翻译X不会移动页面,但是,在这种情况下,只需管理页面间距以改善动画效果 - 上面就是数学。它的作用是根据屏幕高度/宽度减少页面之间的空间。首先它否定了空间(horzMargin)然后它增加了一点间距( - vertMargin / 2)
这就是为什么你的计算不好(w * x) - 你试图移动页面 - 但它已经在移动。
答案 1 :(得分:1)
GitHub为您想要的动画提供library而无需任何计算
您无需创建自定义ViewPager PageTransformer
只需在app/build.gradle
文件中添加以下库。
compile 'com.ToxicBakery.viewpager.transforms:view-pager-transforms:1.2.32@aar'
public class MainActivity extends Activity {
private static final String KEY_SELECTED_PAGE = "KEY_SELECTED_PAGE";
private static final String KEY_SELECTED_CLASS = "KEY_SELECTED_CLASS";
private int mSelectedItem;
private ViewPager mPager;
private PageAdapter mAdapter;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int selectedPage = 0;
if (savedInstanceState != null) {
mSelectedItem = savedInstanceState.getInt(KEY_SELECTED_CLASS);
selectedPage = savedInstanceState.getInt(KEY_SELECTED_PAGE);
}
setContentView(R.layout.activity_main);
mAdapter = new PageAdapter(getFragmentManager());
mPager = (ViewPager) findViewById(R.id.container);
mPager.setAdapter(mAdapter);
try {
mPager.setPageTransformer(true, new TransformerItem(ZoomOutSlideTransformer.class).clazz.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
mPager.setCurrentItem(selectedPage);
}
public static class PlaceholderFragment extends Fragment {
private static final String EXTRA_POSITION = "EXTRA_POSITION";
private static final int[] COLORS = new int[] { 0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444 };
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final int position = getArguments().getInt(EXTRA_POSITION);
final TextView textViewPosition = (TextView) inflater.inflate(R.layout.fragment_main, container, false);
textViewPosition.setText(Integer.toString(position));
textViewPosition.setBackgroundColor(COLORS[position - 1]);
return textViewPosition;
}
}
private static final class PageAdapter extends FragmentStatePagerAdapter {
public PageAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
final Bundle bundle = new Bundle();
bundle.putInt(PlaceholderFragment.EXTRA_POSITION, position + 1);
final PlaceholderFragment fragment = new PlaceholderFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public int getCount() {
return 5;
}
}
private static final class TransformerItem {
final String title;
final Class<? extends PageTransformer> clazz;
public TransformerItem(Class<? extends PageTransformer> clazz) {
this.clazz = clazz;
title = clazz.getSimpleName();
}
@Override
public String toString() {
return title;
}
}
}
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="MainActivity" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/app_name"
android:textColor="@android:color/white"
android:textSize="72sp"
tools:context="MainActivity$PlaceholderFragment" />
我希望这可以帮助你。: - )
答案 2 :(得分:0)
当我重新阅读你的问题和答案时,我不确定我是否已经真正解决了你的问题。我认为这可能会有所帮助,所以我发布了它。
根据this,position = 0表示此页面位于前面和后面。中心(例如,全屏)。我们只关心位置在-1到+1范围内的页面,否则它太过于缺乏关注。您可以在第1和第1期看到这一点。将alpha设置为0的最后条件,使视图完全透明。
我无法理解声明,
view.setTranslationX(horzMargin - vertMargin / 2);
当我看到它时,我在这部分代码中也没有看到太多价值。由于边际是基于scaleFactor计算的,&amp;限制为0.85 - 1.0,它在过渡的外观上没有太大的区别。我敢肯定,那些对我的设计有着比我更好的人会不同意。但是,我删除了这部分代码作为实验。
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
虽然如果我仔细观察,我可以看到根据设置translationX的小差异,我从来没有注意到随意使用。将MIN_SCALE设置为0.5(或更小)可以看出更多的差异。
我的计算会出现什么问题?
可能没什么,只要你将它限制为像当前代码那样的小结果。请记住,ViewPager类是动画的主要控制器,而不是setTranslationX()
。
答案 3 :(得分:0)
如果通过scaleFactor缩小rectange,
假设原始高度为pageHeight,宽度为pageWidth;
新的缩小高度将是scaleFactor * pageHeight
shrinkMarginTopBottom = pageHeight - scaleFactor * pageHeight = pageHeight(1 - scaleFactor);
and I assume it will be equally shirnked from bottom and top;
shrinkMarginTop = shrinkMarginTopBottom/2;
which is equal to below mentioned formula
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
所以在解释保证金计算后
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
x平移应该对页面位置0和1有一些偏移以获得动画效果和一些距离因此减去两者的边距...分裂发生是因为+ ve和-ve x平移加起来精确边距< / p>
我可能猜测但是对于我来说,变量x平移和余量随着比例因子而变化,vertMargin用于创建随着比例变化的偏移量。如果删除vertMargin代码,它仍将是动画相同但是更快,但两页之间没有保留任何余量。