我正在尝试实施 FloatingActionButton 从 Google Design支持库 分为三个选项卡中的两个,并根据Material Design Guidelines - FloatingActionButton 它说:
如果在多个横向屏幕上有一个浮动动作按钮(例如 如在选项卡上),进入每个屏幕时,按钮应显示和 隐藏每个包含的动作是否不同。如果行动是 同样,按钮应保持在屏幕上(并转换为新的 如有必要,我会立场。)
如何在我的应用中为FAB按钮进行此类过渡或动画?
答案 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)
以下是实现理想结果的简单方法
在您的主要活动中添加两个(或等效于您的标签操作)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进行了测试。
用例:
在您的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();
}