底部工作表的动画布局更改

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() 而不是使用过渡,因为使用此函数,您可以更改有关动画的所有内容(时间、可见性等)。

【讨论】:

以上是关于底部工作表的动画布局更改的主要内容,如果未能解决你的问题,请参考以下文章

Android 底部工作表布局边距

如何更改属性表向导按钮的位置?

如何在颤动中更改底部工作表对话框内的文本?

根据深色模式更改的默认背景颜色 res 是啥? [安卓]

AutoLayout常量更改不动画

保存工作表的副本并撤销对原始文件的所有更改