In meiner Anwendung verwende ich ein unteres Blatt (aus der Support-Bibliothek), das hervorragend funktioniert. Jetzt möchte ich eine Layoutänderung animieren, während das Blatt nach oben gezogen wird. Hierfür habe ich eine Unterklasse von BottomSheetCallback
erstellt (dies ist normalerweise eine innere Klasse eines Fragments, daher werden nicht alle in dieser Klasse verwendeten Objekte hier initialisiert):
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;
}
}
Wie Sie sehen, habe ich auch zwei Scene
aus verschiedenen Layoutdateien und eine benutzerdefinierte Transition
erstellt, um die Szenen mit der TransitionManager
zu animieren. Mein Problem ist, dass die Transition
auf dem slideOffset
-Parameter (im Bereich von 0-1) basieren sollte, die TransitionManager
jedoch die Animation
-Klasse im Hintergrund verwendet, die normalerweise auf Android basiert.
Ich habe versucht, den benutzerdefinierten Intapolator zu erstellen, dies funktioniert jedoch nicht ordnungsgemäß. Wie kann ich also eine Transition
erstellen, die auf einer externen Variablen basiert und nicht rechtzeitig?
Basierend auf Ihrer Beschreibung, denke ich, versuchen Sie so etwas wie Google Maps-Bottom-Sheet-Verhalten. Das Layout ändert sich, wenn das Bottomsheet nach oben gezogen wird.
Wenn Sie dies erreichen möchten, müssen Sie keine benutzerdefinierten Animationen erzwingen, da der bottomsheetdialog selbst dieses Animationsverhalten aufweist, wenn er in ein übergeordnetes Koordinatorlayout integriert ist.
Hier ist ein Beispielcode, wie ich dasselbe Verhalten implementiere. Dadurch wird FloatingActionButton unsichtbar, wenn das Bottom Sheet auf die volle Bildschirmgröße gezogen wird:
Erstellen Sie ein unteres Dialogfenster, das Sie in Ihrem Hauptlayout verwenden möchten
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>
Aufruf dieses BottomSheet aus Ihrer Aktivität:
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
}
Hoffe, das löst, was du erreichen willst.
## 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>
## Hauptaktivität ##
@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);
}
Um etwas vom unteren Rand des Bildschirms zu verschieben, können Sie folgenden Code verwenden:
final int activityHeight = findViewById(Android.R.id.content).getHeight();
cardContainer.animate().yBy(activityHeight - cardContainer.getY()).setDuration(SLIDE_OUT_DURATION);
dabei ist cardContainer
die Ansicht, die Sie vom Bildschirm verschieben möchten.
In diesem Blogbeitrag finden Sie das vollständige Beispiel. Beachten Sie, dass Sie anstelle von translationY
auch yBy
verwenden können. Eine andere, allgemeinere Methode ist der folgende 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));
}
Ich bin mir nicht sicher, ob Sie das wollen, aber anstatt Übergang zu verwenden, können Sie die Funktion animate()
verwenden, da Sie mit dieser Funktion alle Dinge zu Ihrer Animation (Zeit, Sichtbarkeit usw.) ändern können.