如何在选项卡之间更改 FloatingActionButton?
How to change FloatingActionButton between Tabs?
我正在尝试实现 FloatingActionButton
从 Google 设计支持库 到三个选项卡中的两个,并根据 Material Design Guidelines - FloatingActionButton
它说:
If there is a floating action button on multiple lateral screens (such
as on tabs), upon entering each screen, the button should show and
hide if the action contained on each is different. If the action is
the same, the button should stay on screen (and translate to a new
position, if necessary.)
如何为我的应用程序中的 FAB 按钮制作这种过渡或动画?
FloatingActionButton 目前未内置此功能,因此您必须自己为其设置动画。假设您的 FloatingActionButton 在您的主 activity 中,将以下函数添加到您的 activity.
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 方法中添加选项卡选择侦听器,并在选择选项卡时调用动画功能。
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) {
}
});
确保您有足够的颜色和图标来匹配您拥有的标签数量。
你可以给viewpager添加一个监听器,根据状态显示和隐藏fab
当您开始滚动 viewpager 时,这是状态的顺序 SCROLL_STATE_DRAGGING SCROLL_STATE_SETTLING SCROLL_STATE_IDLE
例如:
viewPager.addOnPageChangeListener(this);
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if(state==ViewPager.SCROLL_STATE_IDLE)
fab.show();
else if(state==ViewPager.SCROLL_STATE_DRAGGING)
fab.hide();
}
以下是实现您想要的结果的简单方法
在您的主要 activity 中添加两个(或相当于您的选项卡操作)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) {
}
};
扩展 blackcj 的答案,正如所解释的那样,该解决方案非常有效。但是我想补充一点。
我以慢动作观看了那个视频。 drawable 和 fab 的动画效果不同。隐藏时,fab 和 drawable 是同步的。显示时,fab 首先返回,完成 60-70% 后,drawable 从 0 开始动画,旋转和缩放变为全尺寸。
但是,我无法完全实现可绘制动画。但是,我设法使用不同的插值器和稍微修改的时间进行旋转和缩放。所以它看起来更像是 google 设计指南中也介绍的视频。
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) {
}
});
最后,我找到了一个非常简单的解决方案,它显示的动画与附加的 gif 完全一样——在@Nauman 或@Omid 的解决方案中,显示动画在隐藏动画完成之前开始。但一定要使用最新的支持库!我已经用版本 23.2.1 测试了它。
用例:
- 在选项卡 1(索引 0)上显示 fab 1
- 在选项卡 2(索引 1)上显示 fab 2
- 不在选项卡 3(索引 2)上显示任何 fab
在您的 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" />
然后,为你的晶圆厂添加两个字段到你的Activity(你也可以使用局部变量或每次通过findViewById(...)
获取视图):
public class MainActivity extends AppCompatActivity {
private FloatingActionButton fab1;
private FloatingActionButton fab2;
在您的 onCreate(...)
函数中,找到这些视图并将它们保存到声明的字段中:
fab1 = (FloatingActionButton) findViewById(R.id.fab1);
fab2 = (FloatingActionButton) findViewById(R.id.fab2);
接下来声明一个函数,显示给定位置的正确晶圆厂。默认情况(选项卡 3 或更多)非常简单:只需在晶圆厂上调用 hide()
方法。 show()
和 hide()
已经实现了缩放动画。但是如果我们在选项卡 1 上隐藏 fab2,我们必须等到它完成才能显示 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
的onPageSelected(...)
方法没有被调用在启动时(例如,否则如果您打开应用程序并且它显示选项卡 1,则不会显示 fab,因为从未调用过 showRightFab(...)
函数)。
showRightFab(viewPager.getCurrentItem());
这项工作在我的申请中非常完美!
这对我有用:
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();
}
扩展 blackcj 和 kirtan403 的答案,我还添加了隐藏所选选项卡(在本例中为第一个选项卡)上的 fab
的功能,该选项卡在 blackcj 的答案下回答了 bernzkie 的问题。
为了实现这一点,我首先用 3 个项目声明了 int[]
,每个项目用于 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};
然后我在 Activity
的 onCreate
方法中设置一个 if
语句,该语句具有 fab
和制表符。此语句隐藏晶圆厂并将其按比例缩小,以便当它再次可见时,可以使其仅按比例放大,而不是不必要地缩小,然后再放大。我将比例设置为匹配 blackcj 缩小动画的最终比例。
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);
}
然后在onCreate
方法外加了blackcj的animateFab
方法,kirtan403的rotate
修改。但是,我修改了 animateFab
方法,使其也有一个条件语句,其中:
如果returns到第一个选项卡,fab
隐藏(隐藏时自动缩小);
当从 fab 已经全尺寸且可见的选项卡切换到另一个应该可见的选项卡时,它会执行完全缩小、更改和放大动画;
当切换从带有隐藏fab
的选项卡(在本例中为第一个选项卡)时,fab
可见,然后使用自定义动画放大(不是缩小,然后放大)。
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的未更改的选项卡选择监听器。
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
animateFab(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
希望这对您有所帮助,它对我来说确实完美无缺。感谢 blackcj 和 kirtan403。 :)
我正在尝试实现 FloatingActionButton 从 Google 设计支持库 到三个选项卡中的两个,并根据 Material Design Guidelines - FloatingActionButton 它说:
If there is a floating action button on multiple lateral screens (such as on tabs), upon entering each screen, the button should show and hide if the action contained on each is different. If the action is the same, the button should stay on screen (and translate to a new position, if necessary.)
如何为我的应用程序中的 FAB 按钮制作这种过渡或动画?
FloatingActionButton 目前未内置此功能,因此您必须自己为其设置动画。假设您的 FloatingActionButton 在您的主 activity 中,将以下函数添加到您的 activity.
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 方法中添加选项卡选择侦听器,并在选择选项卡时调用动画功能。
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) {
}
});
确保您有足够的颜色和图标来匹配您拥有的标签数量。
你可以给viewpager添加一个监听器,根据状态显示和隐藏fab 当您开始滚动 viewpager 时,这是状态的顺序 SCROLL_STATE_DRAGGING SCROLL_STATE_SETTLING SCROLL_STATE_IDLE
例如:
viewPager.addOnPageChangeListener(this);
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if(state==ViewPager.SCROLL_STATE_IDLE)
fab.show();
else if(state==ViewPager.SCROLL_STATE_DRAGGING)
fab.hide();
}
以下是实现您想要的结果的简单方法
在您的主要 activity 中添加两个(或相当于您的选项卡操作)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) {
}
};
扩展 blackcj 的答案,正如所解释的那样,该解决方案非常有效。但是我想补充一点。
我以慢动作观看了那个视频。 drawable 和 fab 的动画效果不同。隐藏时,fab 和 drawable 是同步的。显示时,fab 首先返回,完成 60-70% 后,drawable 从 0 开始动画,旋转和缩放变为全尺寸。
但是,我无法完全实现可绘制动画。但是,我设法使用不同的插值器和稍微修改的时间进行旋转和缩放。所以它看起来更像是 google 设计指南中也介绍的视频。
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) {
}
});
最后,我找到了一个非常简单的解决方案,它显示的动画与附加的 gif 完全一样——在@Nauman 或@Omid 的解决方案中,显示动画在隐藏动画完成之前开始。但一定要使用最新的支持库!我已经用版本 23.2.1 测试了它。
用例:
- 在选项卡 1(索引 0)上显示 fab 1
- 在选项卡 2(索引 1)上显示 fab 2
- 不在选项卡 3(索引 2)上显示任何 fab
在您的 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" />
然后,为你的晶圆厂添加两个字段到你的Activity(你也可以使用局部变量或每次通过findViewById(...)
获取视图):
public class MainActivity extends AppCompatActivity {
private FloatingActionButton fab1;
private FloatingActionButton fab2;
在您的 onCreate(...)
函数中,找到这些视图并将它们保存到声明的字段中:
fab1 = (FloatingActionButton) findViewById(R.id.fab1);
fab2 = (FloatingActionButton) findViewById(R.id.fab2);
接下来声明一个函数,显示给定位置的正确晶圆厂。默认情况(选项卡 3 或更多)非常简单:只需在晶圆厂上调用 hide()
方法。 show()
和 hide()
已经实现了缩放动画。但是如果我们在选项卡 1 上隐藏 fab2,我们必须等到它完成才能显示 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
的onPageSelected(...)
方法没有被调用在启动时(例如,否则如果您打开应用程序并且它显示选项卡 1,则不会显示 fab,因为从未调用过 showRightFab(...)
函数)。
showRightFab(viewPager.getCurrentItem());
这项工作在我的申请中非常完美!
这对我有用:
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();
}
扩展 blackcj 和 kirtan403 的答案,我还添加了隐藏所选选项卡(在本例中为第一个选项卡)上的 fab
的功能,该选项卡在 blackcj 的答案下回答了 bernzkie 的问题。
为了实现这一点,我首先用 3 个项目声明了 int[]
,每个项目用于 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};
然后我在 Activity
的 onCreate
方法中设置一个 if
语句,该语句具有 fab
和制表符。此语句隐藏晶圆厂并将其按比例缩小,以便当它再次可见时,可以使其仅按比例放大,而不是不必要地缩小,然后再放大。我将比例设置为匹配 blackcj 缩小动画的最终比例。
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);
}
然后在onCreate
方法外加了blackcj的animateFab
方法,kirtan403的rotate
修改。但是,我修改了 animateFab
方法,使其也有一个条件语句,其中:
如果returns到第一个选项卡,
fab
隐藏(隐藏时自动缩小);当从 fab 已经全尺寸且可见的选项卡切换到另一个应该可见的选项卡时,它会执行完全缩小、更改和放大动画;
当切换从带有隐藏
fab
的选项卡(在本例中为第一个选项卡)时,fab
可见,然后使用自定义动画放大(不是缩小,然后放大)。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的未更改的选项卡选择监听器。
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
animateFab(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
希望这对您有所帮助,它对我来说确实完美无缺。感谢 blackcj 和 kirtan403。 :)