如何在Tabs之间更改FloatingActionButton?

时间:2015-07-14 19:34:49

标签: android floating-action-button

我正在尝试实施 FloatingActionButton Google Design支持库 分为三个选项卡中的两个,并根据Material Design Guidelines - FloatingActionButton 它说:

  

如果在多个横向屏幕上有一个浮动动作按钮(例如   如在选项卡上),进入每个屏幕时,按钮应显示和   隐藏每个包含的动作是否不同。如果行动是   同样,按钮应保持在屏幕上(并转换为新的   如有必要,我会立场。)

Example of FAB animation in tabs

如何在我的应用中为FAB按钮进行此类过渡或动画?

7 个答案:

答案 0 :(得分:37)

此功能目前尚未内置于FloatingActionButton中,因此您必须自行设置动画。假设您的FloatingActionButton在您的主要活动中,请将以下函数添加到您的活动中。

int[] colorIntArray = {R.color.walking,R.color.running,R.color.biking,R.color.paddling,R.color.golfing};
int[] iconIntArray = {R.drawable.ic_walk_white,R.drawable.ic_run_white,R.drawable.ic_bike_white,R.drawable.ic_add_white,R.drawable.ic_arrow_back_white};

protected void animateFab(final int position) {
    fab.clearAnimation();
    // Scale down animation
    ScaleAnimation shrink =  new ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    shrink.setDuration(150);     // animation duration in milliseconds
    shrink.setInterpolator(new DecelerateInterpolator());
    shrink.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            // Change FAB color and icon
            fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position]));
            fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));

            // Scale up animation
            ScaleAnimation expand =  new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            expand.setDuration(100);     // animation duration in milliseconds
            expand.setInterpolator(new AccelerateInterpolator());
            fab.startAnimation(expand);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });
    fab.startAnimation(shrink);
}

更新颜色和可绘制资源以匹配您的项目。在onCreate方法中添加选项卡选择侦听器,并在选择选项卡时调用animate函数。

tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        mViewPager.setCurrentItem(tab.getPosition());
        animateFab(tab.getPosition());
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
});

确保您有足够的颜色和图标以匹配您拥有的标签数量。

答案 1 :(得分:21)

以下是实现理想结果的简单方法

enter image description here

在您的主要活动中添加两个(或等效于您的标签操作)FloatingActionButton,如下所示

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/appbar_padding_top"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/AppTheme.PopupOverlay">

    </android.support.v7.widget.Toolbar>

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fabChat"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="end|bottom"
    android:layout_margin="@dimen/fab_margin"
    android:src="@drawable/ic_fab_chat" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fabPerson"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="end|bottom"
    android:layout_margin="@dimen/fab_margin"
    android:src="@drawable/ic_fab_person"
    android:visibility="gone" />

现在在您的MainActivity.java中使用Fab的默认函数来隐藏和显示每个选项卡选项,如下所示

private void animateFab(int position) {
    switch (position) {
        case 0:
            fabChat.show();
            fabPerson.hide();
            break;
        case 1:
            fabPerson.show();
            fabChat.hide();
            break;

        default:
            fabChat.show();
            fabPerson.hide();
            break;
    }
}

调用animateFab功能如下

TabLayout.OnTabSelectedListener onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        animateFab(tab.getPosition());
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
};

ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        animateFab(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
};

答案 2 :(得分:3)

扩展blackcj的答案,解决方案的效果非常好。但是我想在其中添加一些内容。

我以慢动作观看了该视频。 drawable和fab的动画效果不同。隐藏时,fab和drawable是同步的。在展示时,fab首先回归,并且在完成60-70%后,可绘制的开始动画从0开始,旋转和缩放变为全尺寸。

但是,我无法实现可绘制的动画效果。但是,我设法使用不同的插值器进行旋转和缩放,并略微修改了时间。因此,它似乎更像是在谷歌设计指南中提供的视频。

int[] colorIntArray = {R.color.red,R.color.gray,R.color.black};
int[] iconIntArray = {R.drawable.ic_btn1, R.drawable.ic_btn2, R.drawable.ic_btn3};

    protected void animateFab(final int position) {
        fab.clearAnimation();

        // Scale down animation
        ScaleAnimation shrink = new ScaleAnimation(1f, 0.1f, 1f, 0.1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        shrink.setDuration(100);     // animation duration in milliseconds
        shrink.setInterpolator(new AccelerateInterpolator());
        shrink.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // Change FAB color and icon
                fab.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), colorIntArray[position]));
                fab.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), iconIntArray[position]));

                // Rotate Animation
                Animation rotate = new RotateAnimation(60.0f, 0.0f,
                        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                        0.5f);
                rotate.setDuration(150);
                rotate.setInterpolator(new DecelerateInterpolator());

                // Scale up animation
                ScaleAnimation expand = new ScaleAnimation(0.1f, 1f, 0.1f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                expand.setDuration(150);     // animation duration in milliseconds
                expand.setInterpolator(new DecelerateInterpolator());

                // Add both animations to animation state
                AnimationSet s = new AnimationSet(false); //false means don't share interpolators
                s.addAnimation(rotate);
                s.addAnimation(expand);
                fab.startAnimation(s);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        fab.startAnimation(shrink);
    }

并且标签选项卡照常更改侦听器:

tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        mViewPager.setCurrentItem(tab.getPosition());
        animateFab(tab.getPosition());
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
});

答案 3 :(得分:2)

最后,我找到了一个非常简单的解决方案,并且显示了与附加的gif完全相同的动画 - 在@ Nauman的omid @ Omid解决方案中,show动画在隐藏动画完成之前开始。但一定要使用最新的支持库!我已经使用版本23.2.1进行了测试。

用例:

  • 在标签1(索引0)
  • 上显示fab 1
  • 在标签2(索引1)上显示fab 2
  • 不要在标签3(索引2)
  • 上显示任何工厂

在您的xml中,放置到具有唯一ID并且可见性设置为隐藏的工厂:

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="16dp"
    android:src="@drawable/some_icon"
    android:visibility="invisible" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="16dp"
    android:src="@drawable/another_icon"
    android:visibility="invisible" />

然后,将您的fabs的两个字段添加到您的Activity中(您也可以使用局部变量或每次findViewById(...)获取View):

public class MainActivity extends AppCompatActivity {
    private FloatingActionButton fab1;
    private FloatingActionButton fab2;

onCreate(...)函数中,找到这些视图并将其保存到声明的字段中:

fab1 = (FloatingActionButton) findViewById(R.id.fab1);
fab2 = (FloatingActionButton) findViewById(R.id.fab2);

接下来声明一个函数,显示给定位置的正确fab。默认情况(选项卡3或更多)非常简单:只需在fab上调用hide()方法即可。 show()hide()已经实现了缩放动画。但是如果我们将tab2隐藏在选项卡1上,我们必须等到它完成才能显示fab1。因此,为FloatingActionButton.OnVisibilityChangedListener方法设置hide(...)参数,并在该侦听器的onHidden(...)方法中显示所需的新fab。结果如下:

public void showRightFab(int tab) {
    switch (tab) {
        case 0:
            fab2.hide(new FloatingActionButton.OnVisibilityChangedListener() {
                @Override
                public void onHidden(FloatingActionButton fab) {
                    fab1.show();
                }
            });
            break;

        case 1:
            fab1.hide(new FloatingActionButton.OnVisibilityChangedListener() [
                @Override
                public void onHidden(FloatingActionButton fab) {
                    fab2.show();
                }
            });
            break;

        default:
            fab1.hide();
            fab2.hide();
            break;
    }
}

那是最困难的部分!现在为ViewPager添加一个监听器,以便每次选定的选项卡发生变化时调用showRightFab(...)函数。

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageSelected(int position) {
        showRightFab(position);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

    @Override
    public void onPageScrollStateChanged(int state) {}
});

最后,在onCreate(...)方法中手动调用该函数一次,以在默认选项卡上显示fab,因为ViewPager.OnPageChangeListener的{​​{1}}方法不是&#39 ; t启动时调用(例如,如果你打开应用程序并显示选项卡1,则不显示fab,因为从未调用onPageSelected(...)函数)。

showRightFab(...)

这项工作在我的申请中完美无缺!

答案 4 :(得分:2)

扩展blackcj&amp; amp; kirtan403的回答,我还添加了隐藏fab所选标签(在本例中为第一个标签)的功能,该标题回答了blackcj&#39下的bernzkie问题的答案。

为实现这一目标,我首先宣布int[]有3个项目,每个项目都是3个标签中每个标签的fab。我将每个项目中的第一项设置为0,因为这将是第一个标签的不可见fab,它不需要资源。

int[] colorIntArray = {0, R.color.fab_red, R.color.fab_green};
int[] iconIntArray = {0, R.drawable.fab_pencil, R.drawable.fab_chevron};

然后,我在if的{​​{1}}方法中设置onCreate语句,其中包含Activity和标签。这个陈述隐藏了晶圆厂并将其缩小,以便当它再次变得可见时,可以使其仅向上扩展,而不是不必要地向下,然后再向上。我将比例设置为与blackcj的缩小动画的最终比例相匹配。

fab

然后在 if (tabLayout.getSelectedTabPosition() == 0) { // if on the 1st tab fab.hide(); // scale down to only scale up when switching from 1st tab fab.setScaleX(0.2f); fab.setScaleY(0.2f); } 方法之外,我添加了blackcj的onCreate方法,并修改了kirtan403 animateFab。但是,我修改了rotate方法也有一个条件语句,其中:

  • 如果它返回第一个标签页,animateFab会被隐藏(隐藏时会自动缩小);

  • 当从工厂已经全尺寸且可见的标签切换到另一个可见的标签时,它会执行全面缩小,更改&amp;放大动画;

  • 从隐藏fab(在本例中为第一个标签)的标签中切换 时,fab可见,然后按比例放大(不是缩小,然后按比例放大)使用自定义动画。

    fab

然后我只是将blackcj未更改的标签选择监听器添加到protected void animateFab(final int position) { fab.clearAnimation(); if (tabLayout.getSelectedTabPosition() == 0) { // if on the 1st tab fab.hide(); } else if (fab.getScaleX() == 1f) { // if the fab is full scale // Scale down animation ScaleAnimation shrink = new ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); shrink.setDuration(150); // animation duration in milliseconds shrink.setInterpolator(new DecelerateInterpolator()); shrink.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { // Change FAB color and icon fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position])); fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null)); // Scale up animation ScaleAnimation expand = new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); expand.setDuration(100); // animation duration in milliseconds expand.setInterpolator(new AccelerateInterpolator()); // Rotate Animation Animation rotate = new RotateAnimation(60.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotate.setDuration(200); rotate.setInterpolator(new DecelerateInterpolator()); // Add both animations to animation state AnimationSet animationSet = new AnimationSet(false); //false means don't share interpolators animationSet.addAnimation(expand); animationSet.addAnimation(rotate); fab.startAnimation(animationSet); } @Override public void onAnimationRepeat(Animation animation) { } }); fab.startAnimation(shrink); } else { // if the fab is already scaled down // Change FAB color and icon fab.setBackgroundTintList(getResources().getColorStateList(colorIntArray[position])); fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null)); fab.show(); // Scale up animation ScaleAnimation expand = new ScaleAnimation(0.2f, 1f, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); expand.setDuration(100); // animation duration in milliseconds expand.setInterpolator(new AccelerateInterpolator()); // Rotate Animation Animation rotate = new RotateAnimation(60.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotate.setDuration(200); rotate.setInterpolator(new DecelerateInterpolator()); // Add both animations to animation state AnimationSet animationSet = new AnimationSet(false); //false means don't share interpolators animationSet.addAnimation(expand); animationSet.addAnimation(rotate); fab.startAnimation(animationSet); } } 方法。

onCreate

希望这会有所帮助,它对我来说无疑是完美无缺的。感谢blackcj&amp; kirtan403。 :)

答案 5 :(得分:1)

你可以为viewpager添加一个监听器,并根据状态显示和隐藏fab 当您开始滚动viewpager时,这是状态的顺序SCROLL_STATE_DRAGGING SCROLL_STATE_SETTLING SCROLL_STATE_IDLE

例如:

ClipBoard.objects = objects[selectedIndexPath.row]

答案 6 :(得分:0)

这对我有用:

private boolean isFloatingActionButtonHidden = false;
private int[] colorIntArray = {R.color.walking,R.color.running,R.color.biking,R.color.paddling,R.color.golfing};
private int[] iconIntArray = {R.drawable.ic_walk_white,R.drawable.ic_run_white,R.drawable.ic_bike_white,R.drawable.ic_add_white,R.drawable.ic_arrow_back_white};

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        switch (state) {
            case ViewPager.SCROLL_STATE_SETTLING:
                // This is triggered just before the view pager reaches the final state
                // if you want to trigger the animation after the page reaches its final position
                // just move this to "case ViewPager.SCROLL_STATE_IDLE:"
                showFloatingActionButton(viewPager.getCurrentItem());
                break;
            case ViewPager.SCROLL_STATE_IDLE:
                // This is only triggered if user pulls to the left of the start or right of the end
                if (isFloatingActionButtonHidden) {
                    showFloatingActionButton(viewPager.getCurrentItem());
                }
                break;
            default:
                // in all other cases just hide the fab if it is not visable
                if (!isFloatingActionButtonHidden) {
                    hideFloatingActionButton();
                }
        }
   }
});

private void showFloatingActionButton(int position) {
    fab.setImageDrawable(getResources().getDrawable(iconIntArray[position], null));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        floatingActionButton.setBackgroundTintList(getResources().getColorStateList(iconIntArray[position], getTheme()));
    } else {
        floatingActionButton.setBackgroundTintList(getResources().getColorStateList(iconIntArray[position]));
    }

    floatingActionButton.show();
}

private void hideFloatingActionButton() {
    isFloatingActionButtonHidden = true;
    floatingActionButton.hide();
}
相关问题