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

Nit*_*tri 6 animation android 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) {

        }
    });
Run Code Online (Sandbox Code Playgroud)

这是最好的方法吗?如果是,那么translate变量的值应该是多少?

请帮我实现这个.

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

Bar*_*ski 5

例如,最简单的方法是这样的:

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) {

    }
});
Run Code Online (Sandbox Code Playgroud)

切记width参数应该代表屏幕的宽度(我假设ViewPager填充物填满了屏幕的宽度(所以我分配了width = mViewPager.getWidth())。

您也没有完全说出您希望FAB隐藏自己的方式。所以我只是垂直翻译了它。您还可以使用setScaleX(...)setScaleY(...)

编辑:

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

// formula 1
value = targetValue - ((targetValue - initialValue) * (1.0f - offset));
Run Code Online (Sandbox Code Playgroud)

其中,offset代表变化的参数(在范围内[0f; 1f])。因此,在您的情况下offset是方法的positionOffset参数onPageScrolled

让我们分析一下第0页和第1页之间的转换position==0

  1. 您想FAB水平移动,因此您将要修改translationX参数。
  2. FAB固定在右下角(例如layout_gravity="bottom|right"
  3. 的初始位置FAB是动画的不滚动0。因此,在适当的位置initialValuetranslationX为您动画0

initialValue = 0;
Run Code Online (Sandbox Code Playgroud)

  1. 您要移动FAB到屏幕的中央。给定屏幕宽度作为变量,width您可以计算出向屏幕中心偏移的适当targetValueFAB。它等于屏幕宽度的一半减去宽度的一半FAB。由于您是从右上角开始,因此此值为负(``)

targetValue = -(width - mFab.getWidth()) / 2f;
Run Code Online (Sandbox Code Playgroud)

  1. 由于initialValue参数为0,因此您可以将简化formula 1为(将称为formula 2):

// formula 2
value = targetValue * offset;
Run Code Online (Sandbox Code Playgroud)

  1. 进行计算后,targetValue您最终会得到以下结果(formula 2使用计算值targetValuepositionOffset代替offset):

value = (-(width - mFab.getWidth()) / 2f) * positionOffset;
Run Code Online (Sandbox Code Playgroud)

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

您需要做的是在以后的任何步骤中执行相同的操作。考虑一下initialValuetargetValue中的动画参数,将计算出的值插入,formula 1然后查看它是否按预期工作。