Dans l'exemple d'action de navigation défini dans le graphique de navigation:
<action
Android:id="@+id/action_fragment1_to_fragment2"
app:destination="@id/fragment2"
app:enterAnim="@anim/right_slide_in"
app:popExitAnim="@anim/left_slide_out"/>
Quand Fragment2
s'ouvre et commence à glisser dans la vue de droite, Fragment1
disparaît instantanément (malheureusement). Quand Fragment2
est fermé et commence à glisser vers la droite, Fragment1
est bien visible en dessous, donnant un bel effet pop stack (comparable à iOS).
Comment puis-je conserver Fragment1
visible pendant que Fragment2
glisse en vue?
Je pense qu'en utilisant le R.anim.hold
l'animation créera l'effet souhaité:
int holdingAnimation = R.anim.hold;
int inAnimation = R.anim.right_slide_in;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(inAnimation, holdingAnimation, inAnimation, holdingAnimation);
/*
... Add in your fragments and other navigation calls
*/
transaction.commit();
getSupportFragmentManager().executePendingTransactions();
Ou étiquetez-le simplement comme vous l'avez fait dans l'action.
Voici la R.anim.hold
animation mentionnée ci-dessus:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:Android="http://schemas.Android.com/apk/res/Android">
<translate
Android:duration="@Android:integer/config_longAnimTime"
Android:fromYDelta="0.0%p"
Android:toYDelta="0.0%p"/>
</set>
Dans mon propre cas, la solution la plus simple était d'utiliser DialogFragment
avec une animation et un style appropriés.
Style:
<style name="MyDialogAnimation" parent="Animation.AppCompat.Dialog">
<item name="Android:windowEnterAnimation">@anim/slide_in</item>
<item name="Android:windowExitAnimation">@anim/slide_out</item>
</style>
<style name="MyDialog" parent="ThemeOverlay.MaterialComponents.Light.BottomSheetDialog">
<item name="Android:windowIsFloating">false</item>
<item name="Android:statusBarColor">@color/transparent</item>
<item name="Android:windowAnimationStyle">@style/MyDialogAnimation</item>
</style>
Disposition:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:animateLayoutChanges="true"
Android:background="@color/colorWhite"
Android:fillViewport="true"
Android:fitsSystemWindows="true"
Android:layout_gravity="bottom"
Android:orientation="vertical"
Android:scrollbars="none"
Android:transitionGroup="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.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:id="@+id/root_view"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
// Your Ui here
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
Java:
public class MyFragmentDialog extends DialogFragment {
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_dialog, container, false);
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
int width = ViewGroup.LayoutParams.MATCH_PARENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
Objects.requireNonNull(dialog.getWindow())
.setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Objects.requireNonNull(dialog.getWindow()).setLayout(width, height);
dialog.getWindow().setWindowAnimations(R.style.MyDialogAnimation);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.MyDialog);
}
}
Afin d'éviter que l'ancien fragment ne disparaisse pendant l'animation coulissante du nouveau fragment, faites d'abord une animation vide composée uniquement de la durée de l'animation coulissante. Je l'appellerai @anim/stationary
:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:duration="@slidingAnimationDuration" />
Ensuite, dans le graphique de navigation, définissez l'animation de sortie de l'action sur l'animation vide nouvellement créée:
<fragment Android:id="@+id/oldFragment"
Android:name="OldFragment">
<action Android:id="@+id/action_oldFragment_to_newFragment"
app:destination="@id/newFragment"
app:enterAnim="@anim/sliding"
app:exitAnim="@anim/stationary"
</fragment>
L'animation de sortie est appliquée à l'ancien fragment et l'ancien fragment sera donc visible pendant toute la durée de l'animation.
Je suppose que l'ancien fragment disparaît si vous ne spécifiez pas d'animation de sortie, l'ancien fragment sera supprimé immédiatement par défaut au début de l'animation d'entrée.