翻译 ViewPager 滚动条上的浮动操作按钮

Translate Floating Action Button on ViewPager scroll

我有一个包含 3 个选项卡的屏幕,下面是一个包含 3 个片段的 ViewPager 和一个位于右下角的浮动操作按钮。

当第一个选项卡是当前选项卡时,我想在右下角显示 FAB。当第二个选项卡是当前选项卡时,我想在底部中心显示 FAB。当第 3 个选项卡是当前选项卡时,我想隐藏 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) {

        }
    });

这是最好的方法吗?如果是,翻译变量的值应该是多少?

请帮我实现这个。

您可以查看 Android Lollipop Call 应用程序作为参考。显示拨号器的 FAB 以类似的方式进行动画处理。对于第一个选项卡,它位于右下角,然后对于中间选项卡,它位于中心。这正是我想要的。

最简单的方法是这样的:

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] 内)。所以在你的情况下 offsetonPageScrolled 方法的 positionOffset 参数。

让我们分析第 0 页和第 1 页之间的过渡(您的情况;position==0):

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

initialValue = 0;

  1. 您想将 FAB 移到屏幕中央。给定屏幕宽度作为变量 width,您可以计算 FAB 向屏幕中心移动的正确 targetValue。它等于屏幕宽度的一半减去 FAB 宽度的一半。由于您是从右角开始的,因此该值为负数 (``)

targetValue = -(width - mFab.getWidth()) / 2f;

  1. 由于initialValue参数为0,可以将formula 1简化为(将引用为formula 2):

// formula 2
value = targetValue * offset;

  1. 采用计算的 targetValue 你最终得到这个(formula 2 计算的 targetValuepositionOffset 而不是 offset):

value = (-(width - mFab.getWidth()) / 2f) * positionOffset;

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

您需要做的是对以后的任何步骤做同样的事情。考虑动画参数的 initialValuetargetValue,将计算值插入 formula 1 并查看它是否按预期工作。