Фрагмент, удаленный из иерархии представления при запуске анимации - PullRequest
0 голосов
/ 09 июня 2019

У меня есть фрагмент, помещенный между двумя другими видами, который мне нужно плавно переместить из поля зрения. Я настроил анимацию фрагмента, чтобы масштабировать фрагмент вне поля зрения. Это отлично работает. Однако представление фрагмента немедленно удаляется из иерархии представления, как только начинается анимация, в результате чего представление под фрагментом сворачивается поверх представления фрагмента. Как я могу получить представление под фрагментом для плавного перехода вверх и вниз с масштабированием фрагмента?

Вот пример того, что происходит:

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 ]

1 голос
/ 14 июня 2019

Есть более простой способ реализовать эту анимацию с помощью 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>

Я добавил width и height к fragment в этом xml. Вот результат:

enter image description here

0 голосов
/ 10 июня 2019

После нескольких часов работы над этим я придумал собственное решение.Это не идеально, и я не уверен, является ли это правильным или лучшим способом сделать это, но вот оно.

Я полностью отказался от идеи использования метода setCustomAnimations FragmentTransaction и пошел с анимацией представлениявместо этого фрагмент с 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

Это все еще не идеально,но это ближе к тому, что я ищу.

...