TL; DR: Szukam kompletnej, działającej próbki tego, co będę nazywać scenariuszem „trzyczęściowej animacji Gmaila”. W szczególności chcemy zacząć od dwóch fragmentów, takich jak ten:
Po jakimś zdarzeniu interfejsu użytkownika (np. Dotknięciu czegoś we fragmencie B) chcemy:
- Fragment A, aby zsunąć się z ekranu w lewo
- Fragment B przesuwa się do lewej krawędzi ekranu i zmniejsza się, aby zająć miejsce zwolnione przez Fragment A
- Fragment C, aby wślizgnąć się z prawej strony ekranu i zająć miejsce zwolnione przez Fragment B.
A po naciśnięciu przycisku WSTECZ chcemy, aby ten zestaw operacji został odwrócony.
Teraz widziałem wiele częściowych implementacji; Poniżej omówię cztery z nich. Poza tym, że są niekompletne, wszystkie mają swoje problemy.
@Reto Meier przesłał tę popularną odpowiedź na to samo podstawowe pytanie, wskazując, że użyjesz setCustomAnimations()
pliku FragmentTransaction
. W przypadku scenariusza z dwoma fragmentami (np. Początkowo widzisz tylko Fragment A i chcesz go zastąpić nowym Fragmentem B przy użyciu animowanych efektów), zgadzam się całkowicie. Jednak:
- Ponieważ możesz określić tylko jedną animację „wchodzącą” i jedną „wychodzącą”, nie widzę, jak poradzisz sobie ze wszystkimi różnymi animacjami wymaganymi w scenariuszu z trzema fragmentami
- W
<objectAnimator>
swoim przykładowym kodzie używa ustalonych pozycji w pikselach, co wydaje się niepraktyczne biorąc pod uwagę różne rozmiary ekranu, alesetCustomAnimations()
wymaga zasobów animacji, wykluczając możliwość zdefiniowania tych rzeczy w Javie - Nie wiem, jak animatory obiektów dla skali wiążą się z takimi rzeczami, jak
android:layout_weight
wLinearLayout
przypadku przydzielania miejsca na podstawie procentowej - Jestem w rozterce, w jaki Fragment C odbywa się na początku (
GONE
?android:layout_weight
O0
? Pre-animowane w skali od 0? Coś innego?)
@Roman Nurik zwraca uwagę, że możesz animować każdą właściwość , w tym tę, którą sam zdefiniujesz. Może to pomóc rozwiązać problem stałych pozycji kosztem wynalezienia własnej podklasy menedżera niestandardowego układu. To pomaga niektórym, ale nadal jestem zdumiony resztą rozwiązania Reto.
Autor tego wpisu w pastebin pokazuje jakiś kuszący pseudokod, mówiąc w zasadzie, że wszystkie trzy fragmenty znajdowałyby się początkowo w kontenerze, z Fragmentem C ukrytym na początku w wyniku hide()
operacji transakcyjnej. Następnie show()
C i hide()
A, gdy wystąpi zdarzenie UI. Jednak nie rozumiem, jak to radzi sobie z faktem, że B zmienia rozmiar. Polega to również na tym, że najwyraźniej można dodać wiele fragmentów do tego samego kontenera i nie jestem pewien, czy jest to niezawodne zachowanie w dłuższej perspektywie (nie wspominając o tym, że powinno się zepsuć findFragmentById()
, chociaż mogę z tym żyć).
Autor tego posta na blogu wskazuje, że Gmail setCustomAnimations()
w ogóle nie używa , ale zamiast tego bezpośrednio używa animatorów obiektów („po prostu zmień lewy margines widoku głównego + zmień szerokość prawego widoku”). Jednak nadal jest to dwuczęściowe rozwiązanie AFAICT, a implementacja pokazała po raz kolejny sztywne wymiary w pikselach.
Będę dalej się tym zajmował, więc może kiedyś sam na to odpowiem, ale naprawdę mam nadzieję, że ktoś opracował rozwiązanie z trzema fragmentami dla tego scenariusza animacji i może opublikować kod (lub link do niego). Animacje w Androidzie sprawiają, że chcę wyrywać sobie włosy, a ci z Was, którzy mnie widzieli, wiedzą, że jest to w dużej mierze bezowocne przedsięwzięcie.
źródło
Odpowiedzi:
Przesłałem moją propozycję na github (działa ze wszystkimi wersjami Androida, chociaż akceleracja sprzętowa widoku jest zdecydowanie zalecana dla tego rodzaju animacji. W przypadku urządzeń bez akceleracji sprzętowej implementacja buforowania bitmapy powinna pasować lepiej)
Film demonstracyjny z animacją jest tutaj (powolna liczba klatek na sekundę powoduje wyświetlanie ekranu. Rzeczywista wydajność jest bardzo szybka)
Stosowanie:
layout = new ThreeLayout(this, 3); layout.setAnimationDuration(1000); setContentView(layout); layout.getLeftView(); //<---inflate FragmentA here layout.getMiddleView(); //<---inflate FragmentB here layout.getRightView(); //<---inflate FragmentC here //Left Animation set layout.startLeftAnimation(); //Right Animation set layout.startRightAnimation(); //You can even set interpolators
Wyjaśnienie :
Utworzono nowy niestandardowy RelativeLayout (ThreeLayout) i 2 niestandardowe animacje (MyScalAnimation, MyTranslateAnimation)
ThreeLayout
pobiera wagę lewego okienka jako parametr, zakładając, że ma inny widoczny widokweight=1
.new ThreeLayout(context,3)
Tworzy więc nowy widok z trojgiem dzieci, a lewe okienko ma 1/3 całego ekranu. Drugi widok zajmuje całą dostępną przestrzeń.Animacje skalowania i tłumaczenia w rzeczywistości zmieniają rozmiar i przesuwają widok, a nie pseudo [skalowanie, przesuwanie]. Zauważ, że
fillAfter(true)
nie jest używany nigdzie.Widok2 jest właściwy z Widokiem1
i
Widok3 jest prawy_widokiem2
Po ustaleniu tych reguł RelativeLayout zajmie się wszystkim innym. Animacje zmieniają
margins
(w ruchu) i[width,height]
w skaliAby uzyskać dostęp do każdego dziecka (abyś mógł go nadmuchać swoim Fragmentem, możesz zadzwonić
public FrameLayout getLeftLayout() {} public FrameLayout getMiddleLayout() {} public FrameLayout getRightLayout() {}
Poniżej przedstawiono 2 animacje
Scena 1
Etap 2
źródło
View
mniejszym rozmiarze), ale w Gmailu / e-mailu nie otrzymujemy mniejszych czcionek, tylko mniej słów.scaleX
wartościView
, chociaż mogę błędnie interpretować pewne rzeczy.OK, oto moje własne rozwiązanie, pochodzące z aplikacji Email AOSP, zgodnie z sugestią @ Christophera w komentarzach do pytania.
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane
Rozwiązanie @ słabewire przypomina moje, chociaż używa
Animation
raczej klasyki niż animatorów i używaRelativeLayout
reguł do wymuszania pozycjonowania. Z punktu widzenia nagrody, prawdopodobnie otrzyma nagrodę, chyba że ktoś inny z lepszym rozwiązaniem jeszcze opublikuje odpowiedź.Krótko mówiąc,
ThreePaneLayout
w tym projekcie jestLinearLayout
podklasa, zaprojektowana do pracy w krajobrazie z trójką dzieci. Szerokości tych dzieci można ustawić w formacie XML układu, za pomocą dowolnych środków - pokazuję za pomocą wag, ale możesz mieć określone szerokości ustawione przez zasoby wymiarów lub cokolwiek innego. Trzecie dziecko - Fragment C w pytaniu - powinno mieć szerokość zerową.package com.commonsware.android.anim.threepane; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; public class ThreePaneLayout extends LinearLayout { private static final int ANIM_DURATION=500; private View left=null; private View middle=null; private View right=null; private int leftWidth=-1; private int middleWidthNormal=-1; public ThreePaneLayout(Context context, AttributeSet attrs) { super(context, attrs); initSelf(); } void initSelf() { setOrientation(HORIZONTAL); } @Override public void onFinishInflate() { super.onFinishInflate(); left=getChildAt(0); middle=getChildAt(1); right=getChildAt(2); } public View getLeftView() { return(left); } public View getMiddleView() { return(middle); } public View getRightView() { return(right); } public void hideLeft() { if (leftWidth == -1) { leftWidth=left.getWidth(); middleWidthNormal=middle.getWidth(); resetWidget(left, leftWidth); resetWidget(middle, middleWidthNormal); resetWidget(right, middleWidthNormal); requestLayout(); } translateWidgets(-1 * leftWidth, left, middle, right); ObjectAnimator.ofInt(this, "middleWidth", middleWidthNormal, leftWidth).setDuration(ANIM_DURATION).start(); } public void showLeft() { translateWidgets(leftWidth, left, middle, right); ObjectAnimator.ofInt(this, "middleWidth", leftWidth, middleWidthNormal).setDuration(ANIM_DURATION) .start(); } public void setMiddleWidth(int value) { middle.getLayoutParams().width=value; requestLayout(); } private void translateWidgets(int deltaX, View... views) { for (final View v : views) { v.setLayerType(View.LAYER_TYPE_HARDWARE, null); v.animate().translationXBy(deltaX).setDuration(ANIM_DURATION) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { v.setLayerType(View.LAYER_TYPE_NONE, null); } }); } } private void resetWidget(View v, int width) { LinearLayout.LayoutParams p= (LinearLayout.LayoutParams)v.getLayoutParams(); p.width=width; p.weight=0; } }
Jednak w czasie wykonywania, bez względu na to, jak pierwotnie ustawiłeś szerokości, zarządzanie szerokością jest przejmowane przy
ThreePaneLayout
pierwszym użyciu,hideLeft()
aby przełączyć się z pokazywania pytania określanego jako fragmenty A i B do fragmentów B i C. W terminologiiThreePaneLayout
- co ma szczególne związki fragmenty - trzy części sąleft
,middle
, iright
. W momencie wywołaniahideLeft()
, nagrywamy rozmiaryleft
imiddle
i zero obecnie żadnych ciężarów, które zostały wykorzystane na dowolny z trzech, więc możemy całkowicie kontrolować rozmiary. W momencie programuhideLeft()
ustawiliśmy rozmiarright
jako oryginalny rozmiarmiddle
.Animacje są dwojakie:
ViewPropertyAnimator
aby wykonać tłumaczenie trzech widżetów po lewej stronie o szerokośćleft
, używając warstwy sprzętowejObjectAnimator
na niestandardowej pseudo-właściwości of,middleWidth
aby zmienićmiddle
szerokość z tego, od czego się zaczęła, na oryginalną szerokośćleft
(możliwe, że lepszym pomysłem jest użycie
AnimatorSet
iObjectAnimators
dla wszystkich, chociaż to działa na razie)(jest również możliwe, że
middleWidth
ObjectAnimator
neguje wartość warstwy sprzętowej, ponieważ wymaga to dość ciągłej unieważnienia)( zdecydowanie możliwe, że nadal mam luki w zrozumieniu animacji i lubię wyrażenia w nawiasach)
Efekt netto jest taki, że
left
zsuwa się z ekranu,middle
przesuwa się do pierwotnej pozycji i rozmiaruleft
iright
przekłada się zaraz z tyłumiddle
.showLeft()
po prostu odwraca proces, z tą samą mieszanką animatorów, tylko z odwróconymi kierunkami.Aktywność wykorzystuje
ThreePaneLayout
do przechowywania paryListFragment
widżetów iButton
. Zaznaczenie czegoś w lewym fragmencie dodaje (lub aktualizuje zawartość) środkowego fragmentu. Wybranie czegoś w środkowym fragmencie ustawia podpisButton
, plus wykonujehideLeft()
się naThreePaneLayout
. Naciśnięcie BACK, jeśli ukryliśmy lewą stronę, spowoduje wykonanieshowLeft()
; w przeciwnym razie BACK kończy działanie. Ponieważ nie ma toFragmentTransactions
wpływu na animacje, sami utknęliśmy w zarządzaniu tym „stosem wstecznym”.Projekt powiązany z powyższym wykorzystuje natywne fragmenty i natywną strukturę animatora. Mam inną wersję tego samego projektu, która wykorzystuje backport fragmentów Android Support i NineOldAndroids do animacji:
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC
Backport działa dobrze na Kindle Fire pierwszej generacji, chociaż animacja jest nieco nierówna, biorąc pod uwagę niższe specyfikacje sprzętowe i brak obsługi przyspieszania sprzętowego. Obie implementacje wydają się płynne na Nexusie 7 i innych tabletach obecnej generacji.
Z pewnością jestem otwarty na pomysły, jak ulepszyć to rozwiązanie lub inne rozwiązania, które oferują wyraźną przewagę nad tym, co tutaj zrobiłem (lub co wykorzystał @weakwire).
Jeszcze raz dziękujemy wszystkim, którzy wnieśli swój wkład!
źródło
ListView
i szybko nacisnąłem przycisk Wstecz i powtórzyłem, cały układ przesunął się w prawo. Zaczął pokazywać dodatkową kolumnę spacji po lewej stronie. To zachowanie zostało wprowadzone, ponieważ nie pozwoliłbym, aby pierwsza animacja (rozpoczęta przez dotknięcie środkaListView
) zakończyła się i nacisnąłem przycisk Wstecz. Naprawiłem go zastępująctranslationXBy
zetranslationX
wtranslateWidgets
sposobie itranslateWidgets(leftWidth, left, middle, right);
zetranslateWidgets(0, left, middle, right);
wshowLeft()
metodzie.requestLayout();
sięmiddle.requestLayout();
wsetMiddleWidth(int value);
metodzie. Może to nie wpłynąć na wydajność, ponieważ myślę, że GPU nadal będzie wykonywać pełny przebieg układu, jakieś uwagi?Zbudowaliśmy bibliotekę o nazwie PanesLibrary, która rozwiązuje ten problem. Jest jeszcze bardziej elastyczny niż to, co oferowano wcześniej, ponieważ:
Możesz to sprawdzić tutaj: https://github.com/Mapsaurus/Android-PanesLibrary
Oto demo: http://www.youtube.com/watch?v=UA-lAGVXoLU&feature=youtu.be
W zasadzie pozwala w łatwy sposób dodać dowolną liczbę okienek o dynamicznych rozmiarach i dołączyć do nich fragmenty. Mam nadzieję, że okażą się przydatne! :)
źródło
Opierając się na jednym z przykładów, do których utworzyłeś link ( http://android.amberfog.com/?p=758 ), co powiesz na animację
layout_weight
nieruchomości? W ten sposób możesz animować zmianę ciężaru 3 fragmentów razem, ORAZ zyskujesz premię, że wszystkie ładnie się ze sobą ślizgają:Zacznij od prostego układu. Ponieważ będziemy animować
layout_weight
, potrzebujemyLinearLayout
jako głównego widoku trzech paneli .:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/panel1" android:layout_width="0dip" android:layout_weight="1" android:layout_height="match_parent"/> <LinearLayout android:id="@+id/panel2" android:layout_width="0dip" android:layout_weight="2" android:layout_height="match_parent"/> <LinearLayout android:id="@+id/panel3" android:layout_width="0dip" android:layout_weight="0" android:layout_height="match_parent"/> </LinearLayout>
Następnie klasa demonstracyjna:
public class DemoActivity extends Activity implements View.OnClickListener { public static final int ANIM_DURATION = 500; private static final Interpolator interpolator = new DecelerateInterpolator(); boolean isCollapsed = false; private Fragment frag1, frag2, frag3; private ViewGroup panel1, panel2, panel3; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); panel1 = (ViewGroup) findViewById(R.id.panel1); panel2 = (ViewGroup) findViewById(R.id.panel2); panel3 = (ViewGroup) findViewById(R.id.panel3); frag1 = new ColorFrag(Color.BLUE); frag2 = new InfoFrag(); frag3 = new ColorFrag(Color.RED); final FragmentManager fm = getFragmentManager(); final FragmentTransaction trans = fm.beginTransaction(); trans.replace(R.id.panel1, frag1); trans.replace(R.id.panel2, frag2); trans.replace(R.id.panel3, frag3); trans.commit(); } @Override public void onClick(View view) { toggleCollapseState(); } private void toggleCollapseState() { //Most of the magic here can be attributed to: http://android.amberfog.com/?p=758 if (isCollapsed) { PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[3]; arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofFloat("Panel1Weight", 0.0f, 1.0f); arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofFloat("Panel2Weight", 1.0f, 2.0f); arrayOfPropertyValuesHolder[2] = PropertyValuesHolder.ofFloat("Panel3Weight", 2.0f, 0.0f); ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this, arrayOfPropertyValuesHolder).setDuration(ANIM_DURATION); localObjectAnimator.setInterpolator(interpolator); localObjectAnimator.start(); } else { PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[3]; arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofFloat("Panel1Weight", 1.0f, 0.0f); arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofFloat("Panel2Weight", 2.0f, 1.0f); arrayOfPropertyValuesHolder[2] = PropertyValuesHolder.ofFloat("Panel3Weight", 0.0f, 2.0f); ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this, arrayOfPropertyValuesHolder).setDuration(ANIM_DURATION); localObjectAnimator.setInterpolator(interpolator); localObjectAnimator.start(); } isCollapsed = !isCollapsed; } @Override public void onBackPressed() { //TODO: Very basic stack handling. Would probably want to do something relating to fragments here.. if(isCollapsed) { toggleCollapseState(); } else { super.onBackPressed(); } } /* * Our magic getters/setters below! */ public float getPanel1Weight() { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel1.getLayoutParams(); return params.weight; } public void setPanel1Weight(float newWeight) { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel1.getLayoutParams(); params.weight = newWeight; panel1.setLayoutParams(params); } public float getPanel2Weight() { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel2.getLayoutParams(); return params.weight; } public void setPanel2Weight(float newWeight) { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel2.getLayoutParams(); params.weight = newWeight; panel2.setLayoutParams(params); } public float getPanel3Weight() { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel3.getLayoutParams(); return params.weight; } public void setPanel3Weight(float newWeight) { LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) panel3.getLayoutParams(); params.weight = newWeight; panel3.setLayoutParams(params); } /** * Crappy fragment which displays a toggle button */ public static class InfoFrag extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout layout = new LinearLayout(getActivity()); layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); layout.setBackgroundColor(Color.DKGRAY); Button b = new Button(getActivity()); b.setOnClickListener((DemoActivity) getActivity()); b.setText("Toggle Me!"); layout.addView(b); return layout; } } /** * Crappy fragment which just fills the screen with a color */ public static class ColorFrag extends Fragment { private int mColor; public ColorFrag() { mColor = Color.BLUE; //Default } public ColorFrag(int color) { mColor = color; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { FrameLayout layout = new FrameLayout(getActivity()); layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); layout.setBackgroundColor(mColor); return layout; } } }
Również ten przykład nie używa FragmentTransactions do uzyskania animacji (raczej animuje widoki, do których są dołączone fragmenty), więc musisz sam wykonać wszystkie transakcje backstack / fragment, ale w porównaniu z wysiłkiem związanym z uruchomieniem animacji ładnie, to nie wygląda na zły kompromis :)
Okropne wideo w niskiej rozdzielczości przedstawiające to w akcji: http://youtu.be/Zm517j3bFCo
źródło
TextView
zwrap_content
rozciągania się pionowo w miarę postępu animacji). Jednak może się zdarzyć, że animacja wagi polega na zmianie rozmiaru tego, co nazwałem fragmentem B. Dzięki!To nie używa fragmentów ... To niestandardowy układ z trojgiem dzieci. Klikając na wiadomość, zrównoważysz troje dzieci za pomocą
offsetLeftAndRight()
i animatora.W
JellyBean
możesz włączyć opcję „Pokaż granice układu” w ustawieniach „Opcje programisty”. Po zakończeniu animacji slajdu nadal możesz zobaczyć, że lewe menu jest nadal dostępne, ale pod środkowym panelem.Jest podobne do menu aplikacji Fly-in Cyrila Mottiera , ale zawiera 3 elementy zamiast 2.
Dodatkowo
ViewPager
trzecie dziecko jest kolejną oznaką tego zachowania:ViewPager
zwykle używa Fragmentów (wiem, że nie muszą, ale nigdy nie widziałem innej implementacjiFragment
), a ponieważ nie możesz użyćFragments
w innymFragment
trojgu dzieci prawdopodobnie nie są fragmentami ....źródło
TranslateAnimation
, chociaż jestem z pewnością istnieją sposoby wykorzystania animatorów do osiągnięcia tych samych celów. Będę musiał przeprowadzić kilka eksperymentów na tym. Dzięki!Obecnie próbuję coś takiego zrobić, z tym wyjątkiem, że skala Fragmentu B zajmuje dostępne miejsce i że panel 3 może być otwarty w tym samym czasie, jeśli jest wystarczająco dużo miejsca. Oto moje dotychczasowe rozwiązanie, ale nie jestem pewien, czy będę się go trzymać. Mam nadzieję, że ktoś udzieli odpowiedzi wskazującej na właściwą drogę.
Zamiast używać LinearLayout i animować wagę, używam RelativeLayout i animuję marginesy. Nie jestem pewien, czy jest to najlepszy sposób, ponieważ wymaga wywołania requestLayout () przy każdej aktualizacji. Jednak działa płynnie na wszystkich moich urządzeniach.
Więc animuję układ, nie używam transakcji fragmentów. Przycisk Wstecz obsługuję ręcznie, aby zamknąć fragment C, jeśli jest otwarty.
FragmentB używa layout_toLeftOf / ToRightOf, aby zachować wyrównanie do fragmentu A i C.
Kiedy moja aplikacja wyzwoli zdarzenie, aby wyświetlić fragment C, wsuwam fragment C i jednocześnie wysuwam fragment A. (2 osobne animacje). I odwrotnie, gdy Fragment A otwiera się, zamykam C w tym samym czasie.
W trybie portretowym lub na mniejszym ekranie używam nieco innego układu i przesuwam Fragment C po ekranie.
Aby użyć wartości procentowej dla szerokości fragmentu A i C, myślę, że musiałbyś go obliczyć w czasie wykonywania ... (?)
Oto układ zajęć:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootpane" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- FRAGMENT A --> <fragment android:id="@+id/fragment_A" android:layout_width="300dp" android:layout_height="fill_parent" class="com.xyz.fragA" /> <!-- FRAGMENT C --> <fragment android:id="@+id/fragment_C" android:layout_width="600dp" android:layout_height="match_parent" android:layout_alignParentRight="true" class="com.xyz.fragC"/> <!-- FRAGMENT B --> <fragment android:id="@+id/fragment_B" android:layout_width="match_parent" android:layout_height="fill_parent" android:layout_marginLeft="0dip" android:layout_marginRight="0dip" android:layout_toLeftOf="@id/fragment_C" android:layout_toRightOf="@id/fragment_A" class="com.xyz.fragB" /> </RelativeLayout>
Animacja wsuwania lub wysuwania FragmentC:
private ValueAnimator createFragmentCAnimation(final View fragmentCRootView, boolean slideIn) { ValueAnimator anim = null; final RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) fragmentCRootView.getLayoutParams(); if (slideIn) { // set the rightMargin so the view is just outside the right edge of the screen. lp.rightMargin = -(lp.width); // the view's visibility was GONE, make it VISIBLE fragmentCRootView.setVisibility(View.VISIBLE); anim = ValueAnimator.ofInt(lp.rightMargin, 0); } else // slide out: animate rightMargin until the view is outside the screen anim = ValueAnimator.ofInt(0, -(lp.width)); anim.setInterpolator(new DecelerateInterpolator(5)); anim.setDuration(300); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer rightMargin = (Integer) animation.getAnimatedValue(); lp.rightMargin = rightMargin; fragmentCRootView.requestLayout(); } }); if (!slideIn) { // if the view was sliding out, set visibility to GONE once the animation is done anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { fragmentCRootView.setVisibility(View.GONE); } }); } return anim; }
źródło