底部工作表的动画布局更改
Posted
技术标签:
【中文标题】底部工作表的动画布局更改【英文标题】:Animate layout change of bottom sheet 【发布时间】:2018-01-21 07:53:38 【问题描述】:在我的应用程序中,我使用了一个底部工作表(来自支持库),效果很好。现在我想在向上拖动工作表时为布局更改设置动画。为此,我创建了 BottomSheetCallback
的子类(这通常是 Fragment 的内部类,因此并非此类中使用的所有对象都在此处初始化):
public class MyBehavior extends BottomSheetBehavior.BottomSheetCallback
Transition transition;
float lastOffset = 0;
Scene scene;
public PlayerBehavior()
TransitionInflater inflater = TransitionInflater.from(getContext());
transition = inflater.inflateTransition(R.transition.player);
//transition.setDuration(300);
scene = fullLayout;
transition.setInterpolator(new Interpolator()
@Override
public float getInterpolation(float v)
return lastOffset;
);
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState)
if(newState == BottomSheetBehavior.STATE_DRAGGING)
TransitionManager.go(scene, transition);
@Override
public void onSlide(View bottomSheet, final float slideOffset)
scene = (slideOffset > lastOffset) ? smallLayout : fullLayout;
lastOffset = slideOffset;
如您所见,我还从不同的布局文件创建了两个 Scene
和一个自定义 Transition
以使用 TransitionManager
在场景之间进行动画处理。我的问题是Transition
应该基于slideOffset
参数(范围为0-1),但TransitionManager
在后台使用Animation
类,这通常在android 中基于时间。
我尝试创建自定义 Intapolator,但这不能正常工作。那么如何创建一个基于外部变量而不是时间的Transition
?
【问题讨论】:
你能提供一个直观的例子吗?比如截图? 我认为不可能。 BottomSheet 偏移的值从 -1 到 1,它并不总是在 0 和 1 或 -1 和 0 之间反弹。在某些情况下,它会从 0.3 开始并上升到 1.0f。我过去有同样的问题。我必须根据时间来监听状态变化事件。 您需要哪种类型的动画。 【参考方案1】:根据您的描述,我认为您正在尝试实现类似谷歌地图底页行为的东西。当 bottomsheet 向上拖动时,布局会发生变化。
如果这是您想要实现的目标,那么您不需要强制执行自定义动画,因为 bottomsheetdialog 本身在合并到父 Coordinator 布局 中时具有这些动画行为强>.
这是我如何实现相同行为的示例代码。它还使 FloatingActionButton 在底部表格被拖动到全屏大小时不可见:
创建一个要在主布局中使用的底部对话框
public class CustomBottomDialog extends BottomSheetDialogFragment
String mSomeName;
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
// if some arguments are passed from the calling activity
mSomeName = getArguments().getString("some_name");
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View bottomSheet = inflater.inflate(R.layout.bottomsheet_layout, container, false);
// initialise your bottomsheet_layout items here
TextView tvName = bottomSheet.findViewById(R.id.display_name);
tvName.setText(mSomeName);
tvName.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
// do something here
((MainActivity)getActivity()).doSomething();
);
return bottomSheet;
bottomsheet_layout:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_>
<android.support.design.widget.FloatingActionButton
android:id="@+id/nav"
android:layout_
android:layout_
android:src="@drawable/navigation_tilt_grey"
app:backgroundTint="@color/colorAccent"
app:elevation="3dp"
app:fabSize="normal"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
app:layout_anchor="@+id/live_dash"
app:layout_anchorGravity="top|right" />
<!--BottomSheet-->
<android.support.v4.widget.NestedScrollView
android:id="@+id/live_dash"
android:layout_
android:layout_
android:background="#F3F3F3"
android:clipToPadding="true"
app:layout_behavior="android.support.design.widget.BottomSheetBe
havior"
tools:layout_editor_absoluteY="150dp">
<!--Include your items here, the height of all items combined
will take the main screen layout size with animation-->
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
从您的活动中调用此 BottomSheet:
public void notifyBottomSheet(String somename)
BottomSheetDialogFragment customDialogFragment = new CustomBottomDialog();
Bundle args = new Bundle();
args.putString("some_name", somename);
customDialogFragment.setArguments(args);
customDialogFragment.show(getSupportFragmentManager(), customDialogFragment.getTag());
customDialogFragment.setCancelable(false); // if you don't wish to hide
希望这能解决您想要实现的目标。
【讨论】:
我真的觉得我已经盯着这个看很久了,试图理解它是如何工作的。如果问题要求的想法是在拖动布局时将布局从窥视更改为非窥视,它怎么知道要从什么开始动画?【参考方案2】:要轻松地将某些内容从屏幕底部滑出,您可以使用以下代码:
final int activityHeight = findViewById(android.R.id.content).getHeight();
cardContainer.animate().yBy(activityHeight - cardContainer.getY()).setDuration(SLIDE_OUT_DURATION);
cardContainer
是您试图从屏幕上滑出的视图。
有关完整示例,请参阅此blog post。请注意,您也可以使用translationY
代替yBy
。另一种更通用的方法是使用以下代码:
public static ViewPropertyAnimator slideOutToBottom(Context ctx, View view)
final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
int[] coords = new int[2];
view.getLocationOnScreen(coords);
return view.animate().translationY(screenHeight - coords[Y_INDEX]).setDuration(SLIDE_OUT_DURATION);
public static ViewPropertyAnimator slideInFromBottom(Context ctx, View view)
final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
int[] coords = new int[2];
view.getLocationOnScreen(coords);
view.setTranslationY(screenHeight - coords[Y_INDEX]);
return view.animate().translationY(0).setDuration(SLIDE_IN_DURATION).setInterpolator(new OvershootInterpolator(1f));
【讨论】:
【参考方案3】:## Translation Animation ##
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fillAfter="true"
>
<translate
android:fromYDelta="100%p"
android:toYDelta="-30%p"
android:duration="900" />
</set>
## 主要活动##
@Override
protected void onResume()
super.onResume();
Animation am= AnimationUtils.loadAnimation(this,R.anim.fadeout);
tv5.startAnimation(am);
Animation myanim= AnimationUtils.loadAnimation(this,R.anim.translate);
tv1.startAnimation(myanim);
myanim.setStartOffset(500);
Animation animation= AnimationUtils.loadAnimation(this,R.anim.translate);
animation.setStartOffset(1000);
tv2.startAnimation(animation);
Animation an= AnimationUtils.loadAnimation(this,R.anim.translate);
an.setStartOffset(1500);
tv3.startAnimation(an);
Animation ab= AnimationUtils.loadAnimation(this,R.anim.translate);
ab.setStartOffset(2000);
tv4.startAnimation(ab);
Animation ac= AnimationUtils.loadAnimation(this,R.anim.fadein);
ac.setStartOffset(2500);
btn1.startAnimation(ac);
【讨论】:
【参考方案4】:我不确定这是否是您想要的,但也许您可以使用函数animate()
而不是使用过渡,因为使用此函数,您可以更改有关动画的所有内容(时间、可见性等)。
【讨论】:
以上是关于底部工作表的动画布局更改的主要内容,如果未能解决你的问题,请参考以下文章