在ViewPager滚动上翻译浮动操作按钮

时间:2015-08-24 18:28:35

标签: android animation floating-action-button

我有一个带有3个标签的屏幕,下面有一个ViewPager,有3个片段,右下角有一个浮动动作按钮。

当第一个标签是当前标签时,我想在右下角显示FAB。当第二个标签是当前标签时,我想在底部中心显示FAB。当第三个标签是当前标签时,我想隐藏FAB。

从视图寻呼机滚动,即根据滚动量,从右下角到底部中心或反之亦然的翻译动画应该发生。

以下是我的尝试。

mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            ViewCompat.animate(mFAB)
                    .translationX(-translate)
                    .withLayer()
                    .setDuration(0)
                    .setInterpolator(new LinearInterpolator())
                    .start();
        }

        @Override
        public void onPageSelected(int position) {
            mTabLayout.getTabAt(position).select();
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

这是最好的方法吗?如果是,那么translate变量的值是什么?

请帮我实现这个。

供参考,您可以查看Android Lollipop Call应用程序。 FAB以类似的方式显示拨号器动画。对于第一个标签,它在右下方,然后是中间标签,它位于中间。这正是我想要的。

1 个答案:

答案 0 :(得分:4)

最简单的方法就是这样:

mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        final int width = mViewPager.getWidth();
        if (position == 0) { // represents transition from page 0 to page 1 (horizontal shift)
            int translationX = (int) ((-(width - mFab.getWidth()) / 2f) * positionOffset);
            mFab.setTranslationX(translationX);
            mFab.setTranslationY(0);
        } else if (position == 1) { // represents transition from page 1 to page 2 (vertical shift)
            int translationY = (int) (mFab.getHeight() * positionOffset);
            mFab.setTranslationY(translationY);
            mFab.setTranslationX(-(width - mFab.getWidth()) / 2f);
        }
    }

    @Override
    public void onPageSelected(int position) {

    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
});

请记住,width参数应代表屏幕的宽度(我假设ViewPager填充了屏幕的宽度(所以我指定了width = mViewPager.getWidth())。

您还没有确切地说出您希望隐藏FAB的方式。所以我只是垂直翻译它。您还可以使用setScaleX(...)setScaleY(...)

<强> 编辑:

更改参数的(步骤)值应使用以下方法计算(让我们称之为 - 以供将来参考 - formula 1):

// formula 1
value = targetValue - ((targetValue - initialValue) * (1.0f - offset));

其中offset表示更改的参数(范围[0f; 1f]内)。因此,在您的情况下,offsetpositionOffset方法的onPageScrolled参数。

让我们分析第0页和第1页(您的案例; position==0)之间的转换:

  1. 您希望水平移动FAB,因此您将修改translationX参数。
  2. FAB锚定在右下角(例如layout_gravity="bottom|right"
  3. FAB的初始位置是未滚动的第0页动画的正确位置。因此动画的initialValue的{​​{1}}为translationX
  4. 0

    1. 您想将initialValue = 0; 移至屏幕中央。将屏幕宽度指定为变量FAB,您可以计算width移至屏幕中心的正确targetValue。它等于屏幕宽度的一半减去FAB宽度的一半。因为你从右上角开始,这个值是负的(``)
    2. FAB

      1. 由于targetValue = -(width - mFab.getWidth()) / 2f; 参数为initialValue这一事实,您可以将0简化为(将被引用为formula 1):
      2. formula 2

        1. 以计算出的// formula 2 value = targetValue * offset; 计算targetValueformula 2计算targetValuepositionOffset而不是offset):
        2. value = (-(width - mFab.getWidth()) / 2f) * positionOffset;
          

          这正是我以前将FAB从初始位置(bottom|right)移动到屏幕中心(水平)的原因。 在第1页和第2页之间的转换中,我在计算translationY的所需步长值时经历了类似的过程。

          您需要做的是为以后的任何步骤做同样的事情。考虑动画参数的initialValuetargetValue,将计算值插入formula 1并查看其是否符合要求。