Dans mon application, j'utilise une feuille de fond (de la bibliothèque de support) qui fonctionne très bien. Maintenant, j'aimerais animer un changement de mise en page pendant que la feuille est déplacée vers le haut. Pour cela, j'ai créé une sous-classe de BottomSheetCallback
(c'est normalement une classe interne d'un fragment, de sorte que tous les objets utilisés dans ce cals ne sont pas initialisés ici):
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;
}
}
Comme vous pouvez le constater, j'ai également créé deux Scene
à partir de fichiers de mise en page différents et un Transition
personnalisé pour animer les scènes avec le TransitionManager
. Mon problème est que la Transition
devrait être basée sur le paramètre slideOffset
(compris entre 0 et 1) mais la TransitionManager
utilise la classe Animation
en arrière-plan, qui est normalement basée sur Android.
J'ai essayé de créer l'Intapolator personnalisé mais cela ne fonctionne pas correctement. Alors, comment puis-je créer une Transition
qui repose sur une variable externe et non sur le temps?
D'après votre description, je pense que vous essayez d'obtenir quelque chose comme le comportement des feuilles de fond de Google Maps. La mise en page change au fur et à mesure que vous faites glisser le bottomsheet .
Si c'est ce que vous essayez d'atteindre, vous n'avez pas besoin d'appliquer des animations personnalisées, car bottomsheetdialog possède lui-même ce comportement d'animation lorsqu'il est intégré à un parent Coordinator Layout .
Voici un exemple de code montrant comment j'implémente le même comportement. Cela rend également le FloatingActionButton invisible lorsque la feuille de fond est déplacée jusqu'à la taille de l'écran plein écran:
Créez un journal de travail que vous souhaitez utiliser dans votre mise en page principale.
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_width="match_parent"
Android:layout_height="match_parent">
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/nav"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
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_width="match_parent"
Android:layout_height="wrap_content"
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>
Appeler cette fiche inférieure de votre activité:
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
}
J'espère que cela résout ce que vous essayez d'atteindre.
## 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>
## Activité principale ##
@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);
}
Pour faire glisser facilement quelque chose au bas de l'écran, vous pouvez utiliser un code tel que:
final int activityHeight = findViewById(Android.R.id.content).getHeight();
cardContainer.animate().yBy(activityHeight - cardContainer.getY()).setDuration(SLIDE_OUT_DURATION);
où cardContainer
est la vue que vous essayez de faire glisser de l'écran.
Voir cet article de blog pour l'exemple complet. Notez que vous pouvez également utiliser translationY
au lieu de yBy
. Une autre façon plus générique de le faire est avec ce code:
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));
}
Je ne sais pas si c'est ce que vous voulez, mais peut-être qu'au lieu d'utiliser transition, vous pouvez utiliser la fonction animate()
puisqu'avec cette fonction, vous pouvez tout changer pour votre animation (heure, visibilité, etc.).