Witajcie, dobrzy programiści przepełnienia stosu! Spędziłem dobry tydzień z tym problemem i jestem teraz bardzo zdeterminowany z desperacją dla rozwiązania.Zagnieżdżone fragmenty niepoprawnie przekształcane
Scenariusz
Używam android.app.Fragment nie należy mylić z fragmentami wsparcia.
Mam fragmenty 6 dziecko o nazwie:
FragmentOne
FragmentTwo
FragmentThree
FragmentA
FragmentB
FragmentC
I fragmenty dwa macierzyste nazwie:
FragmentNumeric
FragmentAlpha
I 1 Działanie nazwane:
MainActivity
Zachowują się w następujących przypadkach:
- fragmenty dziećmi są fragmenty, które tylko pokazują widok, nie wykazują ani zawierać fragmenty.
- Fragmenty rodzica wypełniają cały widok jednym fragmentem podrzędnym. Są w stanie zastąpić fragment potomny innymi fragmentami potomnymi.
- Aktywność wypełnia większość swojego widoku fragmentem nadrzędnym. Można go zastąpić innymi fragmentami macierzystymi. Tak więc w tym samym czasie ekran zawiera tylko jeden fragment podrzędny.
Jak już zapewne domyślasz,
FragmentNumeric
pokazuje fragmenty dziecko FragmentOne
, FragmentTwo
i FragmentThree
.
FragmentAlpha
pokazuje fragmenty potomne FragmentA
, FragmentB
i FragmentC
.
Problem
Próbuję przekształceń/animować rodzicem a dzieckiem fragmenty. Fragmenty potomne przechodzą płynnie i zgodnie z oczekiwaniami. Jednak po przejściu na nowy fragment rodzicielski wygląda okropnie. Fragment potomny wygląda tak, jakby uruchamiał niezależne przejście z fragmentu macierzystego.A fragment potomny wygląda tak, jakby został usunięty z fragmentu rodzica. Ten gif można obejrzeć tutaj: https://imgur.com/kOAotvk. Zwróć uwagę, co się stanie, gdy kliknę opcję Pokaż alfa.
Najbliższe pytanie & odpowiedzi Mogę znaleźć tutaj: Nested fragments disappear during transition animation jednak wszystkie odpowiedzi są niesatysfakcjonujące.
Animator XML Pliki
Mam następujące efekty animator (czas trwania jest długa dla celów testowych):
fragment_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="1.0"
android:valueTo="0" />
</set>
fragment_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="0"
android:valueTo="-1.0" />
</set>
fragment_pop.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="0"
android:valueTo="1.0" />
</set>
fragment_push.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="-1.0"
android:valueTo="0" />
</set>
fragment_nothing.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000" />
</set>
MainActivity.kt
warte rozważenia: Pierwszy fragment rodzic, FragmentNumeric, nie wchodzi więc jej efekty zawsze gotowy do działania i nie ma skutków wyjścia, bo nic nie wystaje. Używam również FragmentTransaction#add
z nim gdzie jako FragmentAlpha korzysta FragmentTransaction#replace
class MainActivity : AppCompatActivity {
fun showFragmentNumeric(){
this.fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_nothing,
R.animator.fragment_nothing,
R.animator.fragment_push,
R.animator.fragment_pop)
.add(this.contentId, FragmentNumeric(), "FragmentNumeric")
.addToBackStack("FragmentNumeric")
.commit()
}
fun showFragmentAlpha(){
this.fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentAlpha(), "FragmentAlpha")
.addToBackStack("FragmentAlpha")
.commit()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
showFragmentNumeric()
}
}
}
FragmentNumeric
robi to samo, co pod względem aktywności szybko pokazując swoje pierwsze dziecko fragment.
class FragmentNumeric : Fragment {
fun showFragmentOne(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_nothing,
R.animator.fragment_nothing,
R.animator.fragment_push,
R.animator.fragment_pop)
.add(this.contentId, FragmentOne(), "FragmentOne")
.addToBackStack("FragmentOne")
.commit()
}
fun showFragmentTwo(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentTwo(), "FragmentTwo")
.addToBackStack("FragmentTwo")
.commit()
}
fun showFragmentThree(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentThree(), "FragmentThree")
.addToBackStack("FragmentThree")
.commit()
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (savedInstanceState == null) {
if (this.childFragmentManager.backStackEntryCount <= 1) {
showFragmentOne()
}
}
}
}
inne fragmenty
FragmentAlpha się według tego samego schematu, jak FragmentNumeric zastępując Fragmenty jeden, dwa i trzy w Fragmenty A, B i C odpowiednio.
Fragmenty dzieci pokazują po prostu następujący widok XML i dynamicznie ustawiają odbiornik tekstu i przycisku, aby wywołać funkcję z fragmentu lub działania rodzica.
view_child_example.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<TextView
android:id="@+id/view_child_example_header"
style="@style/Header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/view_child_example_button"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Korzystanie sztylet i kilka umów Mam fragmenty dziecko callback ich fragmentów dominujących i działalności hosting by robić coś jak poniżej:
FragmentOne ustawia Kliknij przycisk słuchacza zrobić:
(parentFragment as FragmentNumeric).showFragmentTwo()
FragmentTwo ustawia kliknij przycisk słuchacza zrobić:
(parentFragment as FragmentNumeric).showFragmentThree()
FragmentThree jest inna, to będzie ustawić kliknięcie słuchacz zrobić:
(activity as MainActivity).showFragmentAlpha()
Czy ktoś ma rozwiązanie tego problemu?
Update 1
Dodałem przykładowym projekcie zgodnie z żądaniem: https://github.com/zafrani/NestedFragmentTransitions
Różnica w nim i że z jednego w moim oryginalnym filmie jest fragment rodzic nie korzysta już z widoku z właściwością xFraction. Wygląda więc na to, że animacja typu "enter" nie ma już takiego efektu nakładania się. Nadal jednak usuwa fragment potomny od rodzica i animuje je obok siebie. Po zakończeniu animacji Fragment 3 zastępuje się natychmiast Fragmentem A.
Aktualizuj 2
Zarówno rodzic i dziecko fragment poglądy są za pomocą właściwości xFraction. Kluczem jest stłumienie animacji dziecka podczas animacji rodzica.
Pytanie jest już bardzo jasne, ale ponieważ wydaje się, że masz czysty projekt pokazujący problem, byłoby fajnie, gdybyś mógł go gdzieś przesłać. – natario
Zaktualizuj gify, wygląda na to, że ich brakuje. UPD. Przepraszam, mój zły, znalazłem obraz. – GensaGames
@natario Dodałem link do githuba. – zafrani