在滑动ViewPager中查看翻译

14
我在阅读有关自定义 ViewPager 滑动页面动画的示例,该示例涉及将页面(View)翻译到一定量。该示例来自文档。具体而言,它是关于一个名为 ZoomOutPageTransformer 的实现,可以通过 setPageTransformer() 设置在 ViewPager 上以自定义页面滑动(引入 缩放 动画)的方式。
这就是最终结果应该是什么样子的: enter image description here 现在,他们描述了他们要如何做:

在实现 transformPage() 时,您可以通过确定屏幕上的页面位置(从 transformPage() 方法的 position 参数获取),以此来创建自定义的幻灯片动画。

position参数指示给定页面相对于屏幕中心的位置。它是一个动态属性,随着用户滚动页面而更改。当页面填充整个屏幕时,其 position 值为 0。当页面刚好绘制在屏幕右侧时,其 position 值为 1. 如果用户在第一页和第二页之间滚动了一半,则第一页的 position 值为 -0.5,而第二页的 position 值为 0.5。根据屏幕上页面的位置,您可以通过使用诸如 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。因此,如果页面中心移动了x个position单位,则以像素/ dp为单位的平移量将为w * x。但他们使用了一些边距计算来计算平移量。

有人能解释一下他们如何进行此计算以及我的计算有什么问题吗?

4个回答

3

您在这里忽略了一件事情,即PageTransformer是在视图被定位之后应用的。

因此,无论是否将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翻译的意思并不是移动页面,而是为了补偿页面缩小而进行管理。

如果没有它,页面将会有一些难看的副作用。试一下,把这些行删除:) - 视图会向右/左移,但定位会出错。

因此,在这种情况下,X翻译只是简单地管理页面间距以改善动画效果-上面的数学公式就是为此而设计的。它所做的是根据屏幕高度/宽度减少页面之间的间距。首先,它消除空间(horzMargin),然后添加一些间距(- vertMargin / 2)。

这就是为什么您的计算不正确(w*x)- 您正在尝试移动页面- 但它已经在移动了。


1

GitHub提供了一个动画库library,可以让您轻松实现所需的动画效果,无需进行任何计算。
您无需创建自定义的ViewPager PageTransformer
只需在app/build.gradle文件中添加以下库即可。

compile 'com.ToxicBakery.viewpager.transforms:view-pager-transforms:1.2.32@aar'

enter image description here

MainActivity.java

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;
        }

    }

}

activity_main.xml

<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" />

fragment_main.xml

<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" />

我希望这可以帮到你。 :-)

0

当我重新阅读了你的问题和这个答案时,我不确定是否真正回答了你的问题。但我认为这可能会有所帮助,所以我发表一下。

根据this,position = 0表示此页面在前台和中心位置(对于这个例子,是全屏幕)。我们只关心位置在-1到+1范围内的页面,否则它距离视野太远而无需关注。您可以在第一个和最后一个条件中看到这一点,其中alpha设置为0,使视图完全透明。

我无法理解这个语句,

view.setTranslationX(horzMargin - vertMargin / 2);

当我仔细查看它时,我也没有看到这段代码的多少价值。因为边距是基于比例尺计算的,而比例尺限制在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()


0
如果您按比例因子缩小矩形,
假设原始高度为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轴的平移应该有一些偏移,以获得动画效果,并且从两个页面的边距中减去一些距离...这是因为正向和负向的x轴平移加起来恰好等于边距。

我可能在猜测,但为了让我拥有一个可变的x轴平移和与比例因子变化的边距,使用vertMargin来创建这种偏移。如果您删除vertMargin代码,则仍将进行相同的动画,但速度会快一些,但不会在两个页面之间保留任何边距。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接