动画开始时从视图层次结构中删除片段

时间:2019-06-09 18:19:51

标签: android android-fragments android-animation fragmenttransaction

我在其他两个视图之间放置了一个片段,需要平滑地过渡到其他视图之外。我设置了一个片段动画以将片段缩放到视线之外。这很好。但是,一旦动画开始,片段的视图就会立即从视图层次结构中移出,从而导致片段下方的视图在片段的视图上方折叠。如何获取片段下方的视图以随着片段的缩放平滑地上下过渡?

以下是发生的情况的一个示例:

enter image description here

这是MainActivity.java

public class MainActivity extends AppCompatActivity {

public final String TAG = "MainActivity";

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button btnHide = findViewById(R.id.btn_hide);
    Button btnShow = findViewById(R.id.btn_show);

    final FragmentManager fm = getSupportFragmentManager();
    final Fragment fragment = fm.findFragmentById(R.id.frag_middle);

    btnHide.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(fragment != null) {
                FragmentTransaction ft = fm.beginTransaction();
                ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
                ft.hide(fragment);
                ft.commit();
            }else{
                Log.d(TAG, "fragment is null!");
            }
        }
    });

    btnShow.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(fragment != null){
                FragmentTransaction ft = fm.beginTransaction();
                ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
                ft.show(fragment);
                ft.commit();
            }else{
                Log.d(TAG, "fragment is null!");
            }
        }
    });

}

}

这是activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
tools:context=".MainActivity">

<TextView
    android:id="@+id/tv_top"
    android:layout_height="wrap_content"
    android:layout_width="0dp"
    android:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    android:padding="16dp"
    android:text="TextViewTop"
    android:textAlignment="center"
    android:textStyle="bold"
    android:textColor="@android:color/white"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    android:background="@color/colorPrimary"/>

<fragment
    android:id="@+id/frag_middle"
    android:name="my.packagename.mytestapplication.TestFragment"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@id/tv_top"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"/>

<TextView
    android:id="@+id/tv_bottom"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    android:padding="16dp"
    android:text="TextViewBottom"
    android:textAlignment="center"
    android:textStyle="bold"
    android:textColor="@android:color/white"
    app:layout_constraintTop_toBottomOf="@+id/frag_middle"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    android:background="@color/colorPrimary"/>

<Button
    android:id="@+id/btn_hide"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hide Fragment"
    app:layout_constraintTop_toBottomOf="@id/tv_bottom"
    app:layout_constraintStart_toStartOf="parent"
    />

<Button
    android:id="@+id/btn_show"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Show Fragment"
    app:layout_constraintTop_toBottomOf="@id/tv_bottom"
    app:layout_constraintEnd_toEndOf="parent"/>

这是动画xml的示例:

<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000">

<scale
    android:fromYScale="0"
    android:toYScale="1"
    android:fromXScale="1"
    android:toXScale="1" />

任何帮助将不胜感激!谢谢

2 个答案:

答案 0 :(得分:1)

使用Transition API实现此动画的简便方法。 TransitionManager可以处理视图或视图层次结构更改并为其设置动画。隐藏/显示片段时,您只需更改片段视图的可见性即可。

private void toggle() {
    final FragmentManager fm = getSupportFragmentManager();
    final Fragment fragment = fm.findFragmentById(R.id.frag_middle);
    ViewGroup parentViewGroup = findViewById(R.id.parentViewGroup);

    TransitionManager.beginDelayedTransition(parentViewGroup, new AutoTransition());
    FragmentTransaction ft = fm.beginTransaction();
    if (show) {
        ft.show(fragment);
    } else {
        ft.hide(fragment);
    }
    ft.commitNow();

    show = !show;
}

这里重要的是使用commitNow方法而不是commit。因为commitNow立即执行片段事务,这就是TransitionManager处理视图更改的原因。使用commit无效,因为commit异步执行事务。

<android.support.constraint.ConstraintLayout 
    ...
    android:id="@+id/parentViewGroup">

    <fragment
        android:id="@+id/frag_middle"
        android:name="TestFragment"
        android:layout_width="300dp"
        android:layout_height="200dp"
        app:layout_constraintTop_toBottomOf="@id/tv_top"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>

</android.support.constraint.ConstraintLayout>

我已在此xml中将widthheight添加到fragment中。结果如下:

enter image description here

答案 1 :(得分:0)

经过几个小时的研究,我想出了自己的解决方案。它不是完美的,我不确定这是正确的方法还是最好的方法,但是确实如此。

我完全放弃了使用FragmentTransaction的setCustomAnimations方法的想法,并改为使用ObjectAnimator对片段的视图进行动画处理。

我从上面更改的唯一代码是两个按钮onClick侦听器。这是更新的onClickListener代码:

 btnHide.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(fragment != null  && fragment.getView() != null) {

                final ViewGroup.LayoutParams params = fragment.getView().getLayoutParams();
                final int startHeight = fragment.getView().getMeasuredHeight();
                Log.d(TAG, "startHeight is " + startHeight);
                ObjectAnimator animator = ObjectAnimator.ofFloat(fragment.getView(), "scaleY", 0f).setDuration(500);

                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float yVal = (float)animation.getAnimatedValue();
                        params.height = (int)(yVal * startHeight);
                        fragment.getView().requestLayout();
                    }
                });

                animator.addListener(new Animator.AnimatorListener() {
                    @Override public void onAnimationStart(Animator animation) {}
                    @Override public void onAnimationEnd(Animator animation) {
                        FragmentTransaction ft = fm.beginTransaction();
                        ft.hide(fragment);
                        ft.commit();
                    }
                    @Override public void onAnimationCancel(Animator animation) {}
                    @Override public void onAnimationRepeat(Animator animation) {}
                });

                animator.start();

            }else{
                Log.d(TAG, "fragment is null!");
            }
        }
    });

    btnShow.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(fragment != null && fragment.getView() != null){

                final ViewGroup.LayoutParams params = fragment.getView().getLayoutParams();
                fragment.getView().measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                final int endHeight = fragment.getView().getMeasuredHeight();
                Log.d(TAG, "endHeight is " + endHeight);
                ObjectAnimator animator = ObjectAnimator.ofFloat(fragment.getView(), "scaleY", 1f).setDuration(500);

                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float yVal = (float)animation.getAnimatedValue();
                        Log.d(TAG, "animation height is " + yVal);
                        params.height = (int)(yVal * endHeight);
                        Log.d(TAG, "height is " + params.height);
                        fragment.getView().requestLayout();
                    }
                });

                animator.addListener(new Animator.AnimatorListener() {
                    @Override public void onAnimationStart(Animator animation) {
                        FragmentTransaction ft = fm.beginTransaction();
                        ft.show(fragment);
                        ft.commit();
                    }
                    @Override public void onAnimationEnd(Animator animation) {}
                    @Override public void onAnimationCancel(Animator animation) {}
                    @Override public void onAnimationRepeat(Animator animation) {}
                });

                animator.start();

            }else{
                Log.d(TAG, "fragment is null!");
            }
        }
    });

这是现在的样子:

enter image description here

它仍然不完美,但是更接近我想要的。