Parçaların içindeki parçalar


145

Bunun aslında Android API'de bir hata olup olmadığını merak ediyorum:

Böyle bir kurulumum var:

┌----┬---------┐
|    |         |
|  1 |    2    |
|    |┌-------┐|
|    ||       ||
|    ||   3   ||
└----┴┴-------┴┘
  1. Sağ bölmede 2. parçayı (Bir arama ekranı) yükleyen bir menüdür.
  2. Bir sonuç listesi olan 3 numaralı parçayı içeren bir arama ekranıdır.
  3. Sonuç listesi birkaç yerde kullanılır (kendi başına işleyen bir üst düzey parça olarak dahil).

Bu işlevsellik bir telefonda mükemmel şekilde çalışır (1 & 2 ve 3'ün olduğu yerlerde ActivityFragment).

Ancak, bu kodu kullandığımda:

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();       
    Fragment frag = new FragmentNumber2();
    if(toLoad != null) frag.setArguments(toLoad);
    transaction.replace(R.id.rightPane, frag);      
    transaction.commit();

Nerede R.id.leftPaneve R.id.rightPaneHangi <fragment>yatay doğrusal düzende s.

Anladığım kadarıyla, yukarıdaki kod yerleşik olan parçayı kaldırır ve sonra onu yeni bir parça ile değiştirir. Harika ... Açıkçası böyle olmuyor çünkü bu kod ikinci kez çalıştığında aşağıdaki istisnayı elde edersiniz:

07-27 15:22:55.940: ERROR/AndroidRuntime(8105): Caused by: java.lang.IllegalArgumentException: Binary XML file line #57: Duplicate id 0x7f080024, tag null, or parent id 0x0 with another fragment for FragmentNumber3

Bunun nedeni FragmentNumber3 kabının yinelenmiş olması ve artık benzersiz bir kimliğe sahip olmamasıdır. İlk Parça, yenisi eklenmeden önce (?) Yok edilmedi (?) (Aklımda bu, değiştirilmediği anlamına geliyor ).

Birisi bana bunun mümkün olup olmadığını söyleyebilir mi ( bu cevap öyle olmadığını gösteriyor) veya bir hata mı?


6
@rds bu eski bir sorudur, kopya olarak işaretlemek biraz anlamsız.
pietv8x

Yanıtlar:


204

İç içe geçmiş parçalar şu anda desteklenmemektedir. Başka bir parçanın kullanıcı arayüzüne bir parça yerleştirmeye çalışmak, tanımlanmamış ve muhtemelen bozuk davranışla sonuçlanacaktır.

Güncelleme : İç içe geçmiş parçalar , Android 4.2 (ve Android Destek Kitaplığı rev 11) itibarıyla desteklenmektedir : http://developer.android.com/about/versions/android-4.2.html#NestedFragments

NOT ( bu dokümanlara göre ): " Not: Bir mizanpaj a'yı içerdiğinde mizanpajı bir parçaya <fragment>şişiremezsiniz. İç içe geçmiş parçalar yalnızca bir parçaya dinamik olarak eklendiğinde desteklenir. "


14
İlk uygulama için bir tasarım hedefi olmadığı için desteklenmiyor. Bu özellik için çok sayıda istek duydum, bu yüzden muhtemelen bir noktada yapılacak, ancak her zamanki gibi öncelikli olarak onunla rekabet eden birçok başka şey var.
hackbod

4
Bunu FragmentActivity, FragmentManager ve FragmentTransaction'ı genişleterek başardım. Temel öncül, etkinliklerimdeki DeferringFragmentActivity'yi genişletmek, aynı api'yi sağlamak, böylece başka kod değişiklikleri yapılmamasıdır. GetFragmentManager'ı çağırdığımda, DeferringFragmentManager olan bir örnek alıyorum ve beginTransaction'ı çağırdığımda, bir DeferredTransaction alıyorum. Bu işlem POJO'ları çağrılan yöntem ve argümanlarla depolar. Taahhüt çağrı olduğunda, önce bekleyen Ertelenmiş İşlemleri ararız. Tüm işlemler tamamlandıktan sonra, gerçek bir işlem başlatır ve depolanan tüm yöntemleri args ile çalıştırırız.
dskinner

11
O nokta şimdi. Yuvalanmış FragmentURL'ler artık Android API'nin bir parçası, yaşasın! developer.android.com/about/versions/… .
Alex Lockwood

9
Vay canına, ne kabus: Bir Parça üzerinde <parça> kullanırsanız ve bu Parça alt parçalarını kullanırsa, açık bir hatayla başarısız olmaz ("düzen parçalarına alt parçalar eklenemez") - bu "Fragman bir görünüm yaratmadı" gibi istisnalarla gizemli bir şekilde başarısız oluyor. Hata ayıklama birkaç saat sürer ...
Glenn Maynard

6
@ MartínMarconcini elbette, ancak bu, API tarafından sağlanan işlevselliğe dayalı olarak hiç görünmüyor. Bir şey izin almıyorsa gerektiğini açıkça belgelendirilmesi şey beklediğiniz gibi çalışmadığında, çünkü üzerindeki saç çekme geliştirici bırakmamış.
dcow

98

İç içe geçmiş parçalar android 4.2 ve sonraki sürümlerde desteklenir

Android Destek Kitaplığı artık iç içe geçmiş parçaları da desteklediğinden , Android 1.6 ve sonraki sürümlerde yuvalanmış parça tasarımlarını uygulayabilirsiniz.

Bir parçayı iç içe yerleştirmek için, parça eklemek istediğiniz Parçada getChildFragmentManager () çağırmanız yeterlidir . Bu, parça işlemleri oluşturmak için normalde üst düzey etkinlikten yaptığınız gibi kullanabileceğiniz bir FragmentManager döndürür. Örneğin, mevcut bir Fragment sınıfının içinden bir parça ekleyen bazı kodlar:

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

İç içe geçmiş parçalar hakkında daha fazla fikir edinmek için lütfen bu eğitimleri inceleyin
Bölüm 1
Bölüm 2
Bölüm 3

ve burada iç içe geçmiş parçalar için en iyi uygulamaları tartışan bir SO gönderisi var .


Nestedfragment'ın ana dezavantajı, childfragment'tan optionmenu çağrısı yapamıyoruz :( eğer ABS kullanıyorsak!
LOG_TAG 9'13

Lütfen sorunuma bakar mısınız? Çok benzer .. stackoverflow.com/questions/32240138/… . Benim için çocuk çerçeve ağı koddan şişirilmiyor
Nicks

34

.. iç içe geçmiş parçanızı ana parçanın destroyviewyönteminde temizleyebilirsiniz:

@Override
    public void onDestroyView() {

      try{
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();

        transaction.remove(nestedFragment);

        transaction.commit();
      }catch(Exception e){
      }

        super.onDestroyView();
    }

4
SetAlwaysFinish ( bricolsoftconsulting.com/2011/12/23/… ) ile bazı yaşam döngüsü testleri yaparsanız , her zaman bitiş etkinken başka bir etkinlik zirveye çıktığında bu kodun bir hataya neden olduğunu görürsünüz (IllegalStateException: Bu eylemi gerçekleştiremez onSaveInstanceState'den sonra). Yukarıdaki kodu dene / yakala'ya sarmak en zarif çözüm değil ama her şeyin çalışmasını sağlıyor gibi görünüyor.
Theo

Bu neredeyse işe yaradı. Daha sonra çizim kullanıcı arayüzünde bir Stackoverflow aldım. Kesinlikle ... iç içe parçaları önlemek
neteinstein

14

Parçalar başlatan Eylem Çubuğundaki Sekmeler ile benzer şekilde düzenlenmiş, geliştirmekte olduğum bir uygulamam var, bu Parçalardan bazılarının içinde birden fazla gömülü Parça var.

Uygulamayı çalıştırmaya çalıştığımda da aynı hatayı alıyordum. Bir sekme seçilmeden ve yeniden seçildikten sonra Parçaları xml düzeninde somutlaştırırsanız şişirme hatası alacağım gibi görünüyor.

Bunu, xml'deki tüm parçaları Linearlayouts ile değiştirerek ve ardından fragmanları somutlaştırmak için bir Fragment yöneticisi / fragment işlemi kullanarak çözdüm, her şey şu anda en azından bir test seviyesinde doğru çalışıyor gibi görünüyor.

Umarım bu size yardımcı olur.


Bu yaklaşımın etkinliği hakkında yorum yapan var mı? Fragmentleri yalnızca bir seviye derinliğinde kullanabilmeyi talihsiz buluyorum - o zaman onları hiç kullanmayabilir de. Bunları yer tutucu görünüm gruplarına programlı olarak eklemek, uyarılar olmadan işe yarar mı?
Rafael Nobre

Hala benim için çalışıyor gibi görünüyor, onları görüntü sahibi içine ve dışına takas ediyorum da sorun değil. Bir uyarı, bunu sadece bal peteği üzerinde yapıyorum, Dondurmalı sandviç ile uyumlu değil.
draksia 01

4

Aynı sorunla karşılaştım, birkaç gün uğraştım ve bunun üstesinden gelmenin en kolay yolunun sekme seçildiğinde / seçilmediğinde fragment.hide () / fragment.show () kullanmak olduğunu söylemeliyim ().

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
    if (mFragment != null)
        ft.hide(mFragment);
}

Ekran döndürme gerçekleştiğinde, tüm üst ve alt parçalar doğru şekilde yok edilir.

Bu yaklaşımın ek bir avantajı da vardır - hide () / show () kullanmak parça görünümlerinin durumlarını kaybetmesine neden olmaz, bu nedenle örneğin ScrollViews için önceki kaydırma konumunu geri yüklemeye gerek yoktur.

Sorun şu ki, görünür olmadıkları zaman parçaları ayırmamanın doğru olup olmadığını bilmiyorum. Bence TabListener'ın resmi örneği, parçaların yeniden kullanılabilir olduğu ve bunlarla hafızayı kirletmemeniz gerektiği düşünülerek tasarlandı, ancak sanırım sadece birkaç sekmeniz varsa ve kullanıcıların bunlar arasında sık sık geçiş yapacağını biliyorsunuz. onları mevcut faaliyete bağlı tutmak uygun olacaktır.

Daha deneyimli geliştiricilerin yorumlarını duymak isterim.


0

İç içe geçmiş parçanızın kaldırılmadığını veya çoğaltılmadığını fark ederseniz (örn. Aktivite yeniden başlatıldığında, ekran döndürüldüğünde) değiştirmeyi deneyin:

transaction.add(R.id.placeholder, newFragment);

-e

transaction.replace(R.id.placeholder, newFragment);

Yukarıdakiler yardımcı olmazsa, şunu deneyin:

Fragment f = getChildFragmentManager().findFragmentById(R.id.placeholder);

FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

if (f == null) {
    Log.d(TAG, "onCreateView: fragment doesn't exist");
    newFragment= new MyFragmentType();
    transaction.add(R.id.placeholder, newFragment);
} else {
    Log.d(TAG, "onCreateView: fragment already exists");
    transaction.replace(R.id.placeholder, f);
}
transaction.commit();

Burada öğrendim

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.