Önce çocuğun üst öğesinde removeView () öğesini çağırın


138

Önce biraz arka plan:

Bir kaydırma görüntüsünün içinde bir düzen var. İlk başta, kullanıcı ekranda ilerlediğinde kaydırma görünümü kayar. Ancak, belirli bir miktar kaydırmadan sonra, kaydırma görünümündeki kaydırmayı devre dışı bırakmak için "kaydırma odağını" alt yerleşimin içindeki bir web görünümüne taşıyordum. Bu şekilde, kaydırma görünümü çubukları ve tüm kaydırma etkinlikleri içindeki web görünümüne gider.

Bu nedenle, bir çözüm için, kaydırma eşiğine ulaşıldığında, çocuk mizanpajını kaydırma görünümünden kaldırırım ve kaydırma görüntüsünün üst öğesine koyarım. (Ve kaydırma görünümünü görünmez yapar).

// Remove the child view from the scroll view
scrollView.removeView(scrollChildLayout);

// Get scroll view out of the way
scrollView.setVisibility(View.GONE);

// Put the child view into scrollview's parent view
parentLayout.addView(scrollChildLayout);

Genel Fikir: (-> içerir içerir)

Önce: parentlayout -> scrollview -> scrollChildLayout

Sonra: parentLayout -> scrollChildLayout

Yukarıdaki kod bana bu istisnayı veriyor:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
           at android.view.ViewGroup.addViewInner(ViewGroup.java:1976)
           at android.view.ViewGroup.addView(ViewGroup.java:1871)
           at android.view.ViewGroup.addView(ViewGroup.java:1828)
           at android.view.ViewGroup.addView(ViewGroup.java:1808)

Neler olduğunu biliyor musun? Ben açıkça ebeveyn üzerinde removeView çağırıyorum.

Yanıtlar:


289

Çözüm:

((ViewGroup)scrollChildLayout.getParent()).removeView(scrollChildLayout);
//scrollView.removeView(scrollChildLayout);

Üst öğeye başvuru almak için alt öğeyi kullanın. RemoveView yöntemine erişip bunu kullanabilmeniz için üst öğeyi bir ViewGroup öğesine yayınlayın.

Çözüm için @ Dongshengcn'e teşekkürler


1
Çözüm doğru, ancak neden "scollView.removeView (scrollChildLayout)" çalışmıyor? İki çizgi aynı olmamalı mı?
andrea.rinaldi

@ andrea.spot, scrollView.removeView(scrollChildLayout)scrollView öğesinin üst satırından kaldırılmaması için scrollView öğesinin çocuğunu kaldırmaya çalışıyor gibi görünüyor
Dmitry Gryazin

1
@ user25 i bu u için belki çok geç biliyorum ama null pointer istisna ebeveyn boş olması nedeniyle görünüm herhangi bir ebeveyn bağlı değildir. başlangıçta ebeveyn olmadığı için kaldırılacak hiçbir şey yoktur. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek

@kasgoku lütfen bana yardım edebilir misin? bir düğmeye tıklama göreceli düzeninde bir parça göstermeye çalışıyorum. ancak "Belirtilen alt öğenin zaten bir üst öğesi var. Önce çocuğun üst öğesinde removeView () öğesini çağırmalısınız." Bunu nasıl çözebilirim?
Imranrana07

Sohbet uygulamasından biri olan uygulamamda da bu hatayı aldım. Bu sorunu çözmeye çalışıyorum. bu simge kaldırıldı ancak resimleri yüklemek için simgeye tekrar ihtiyacım var. ( stackoverflow.com/q/58117428/10971384 ) Bu benim soru bağlantım
Thangapandi

21

Önce scrollChildLayout'u üst görünümden kaldırmayı deneyin?

scrollview.removeView(scrollChildLayout)

Veya tüm alt öğeyi üst görünümden kaldırın ve tekrar ekleyin.

scrollview.removeAllViews()

Zaten yukarıdaki soruya kodunda removeView çağırıyorum. removeAllViews () da çalışmaz.
kasgoku

RemoveView () / removeAllViews () olarak adlandırdığınız üst öğe olduğundan emin misiniz? Çok benzer bir şey yapıyorum ve bu benim için çalışıyor.
dongshengcn

4
) (View.getParent: Sen bakarak kendi üst bakabilirsiniz developer.android.com/reference/android/view/...
dongshengcn

@dongshengcn lütfen bana yardım edebilir misin? bir düğmeye tıklama göreceli düzeninde bir parça göstermeye çalışıyorum. ancak "Belirtilen alt öğenin zaten bir üst öğesi var. Önce çocuğun üst öğesinde removeView () öğesini çağırmalısınız." Bunu nasıl çözebilirim?
Imranrana07

19

Etkinlik ile onCreate veya parça ile onCreateView içinde.

 if (view != null) {
    ViewGroup parent = (ViewGroup) view.getParent();
    if (parent != null) {
        parent.removeView(view);
    }
}
try {
    view = inflater.inflate(R.layout.fragment_main, container, false);
} catch (InflateException e) {

}

15

Tamam, bana paranoyak deyin ama şunu öneririm:

  final android.view.ViewParent parent = view.getParent ();

  if (parent instanceof android.view.ViewManager)
  {
     final android.view.ViewManager viewManager = (android.view.ViewManager) parent;

     viewManager.removeView (view);
  } // if

olmadan döküm instanceofyanlış görünüyor. Ve (bana söylediği için IntelliJ IDEA'ya teşekkürler) arayüzün bir removeViewparçası ViewManager. Ve mükemmel uygun bir arayüz mevcut olduğunda somut bir sınıfa dökülmemelidir.


3

Tek yapmanız gereken postView () 'i addView ()' i yapan bir Runnable 'dır.


İşe yaramadı. Ne denedim: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (new Runnable () {@Over public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku

1

ParentView.removeView (childView) çağırıyordum ve childView hala gösteriliyordu. Sonunda bir yöntem bir şekilde iki kez tetiklendi ve childView parentView iki kez ekledi fark etti.

Bu nedenle, bir görünüm eklemeden önce ve daha sonra ebeveynin kaç çocuğuna sahip olduğunu belirlemek için parentView.getChildCount () öğesini kullanın. Alt öğe çok fazla kez eklenirse, en üstteki alt öğe kaldırılır ve childView kopyası kalır; bu, removeView bile çalışıyor gibi görünüyor.

Ayrıca, bir görünümü kaldırmak için View.GONE kullanmamalısınız. Gerçekten kaldırılmışsa, gizlemenize gerek yoktur, aksi takdirde hala oradadır ve sadece kendinizden gizlersiniz :(


1

Benim durumumda, BaseFragment var ve diğer tüm parça bundan miras.

Solytion'um bu satırları OnDestroyView()metoda eklemekti

@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (mRootView == null)
    {
        mRootView = (inflater == null ? getActivity().getLayoutInflater() : inflater).inflate(mContentViewResourceId, container, false);
    }
....////
}

@Override
public void onDestroyView()
{
    if (mRootView != null)
    {
        ViewGroup parentViewGroup = (ViewGroup) mRootView.getParent();

        if (parentViewGroup != null)
        {
            parentViewGroup.removeAllViews();
        }
    }

    super.onDestroyView();
}

sonraki parçayı seçip çok hızlı geri basmayı denediniz mi?
iamthevoid

1

Kotlin Çözümü

Kotlin, ebeveyn dökümünü basitleştirir as?, sol taraf boşsa veya döküm başarısız olursa boş döndürür.

(childView.parent as? ViewGroup)?.removeView(childView)

Kotlin Uzatma Çözümü

Bunu daha da basitleştirmek istiyorsanız, bu uzantıyı ekleyebilirsiniz.

childView.removeSelf()

fun View?.removeSelf() {
    this ?: return
    val parentView = parent as? ViewGroup ?: return
    parentView.removeView(this)
}

Bu Görünüm null, üst görünüm null veya üst görünüm bir ViewGroup değilse güvenli bir şekilde hiçbir şey yapmaz

NOT: Çocuk görünümlerinin ebeveyn tarafından da güvenli bir şekilde kaldırılmasını istiyorsanız, şunu ekleyin:

fun ViewGroup.removeViewSafe(toRemove: View) {
    if (contains(toRemove)) removeView(toRemove)
}

0

Ayrıca, ViewO'nun indexOfView yönteminin indexOfView yöntemi -1 döndürüp döndürmediğini kontrol ederek de yapabiliriz.

ViewGroup'un detachViewFromParent (v); ardından ViewGroup'un removeDetachedView (v, true / false);


0

Ne yanlış yapıyordum bu yüzden bu hatayı aldım dinamik düzen örnekleme ve ona childs ekleyerek bu hatayı aldım


0

İşte benim çözümüm.

Diyelim ki iki tane var TextViewsve onları LinearLayout(adlı ll) koy . Bunu bir LinerLayoutbaşkasına koyacaksın LinerLayout.

< lm Linear Layout> 
       < ll Linear Layout> 
             <name Text view>
             </name Text view>
             <surname Text view>
             </surname Text view>
       </ll Linear Layout> 
</lm Linear Layout> 

Bu yapıyı oluşturmak istediğinizde ebeveynlere miras vermeniz gerekir.

İsterseniz bir onCreateyöntemde kullanmak thisyeterli olacaktır.

Aksi takdirde burada çözüm:

LinerLayout lm = new LinearLayout(this); // You can use getApplicationContext() also
LinerLayout ll = new LinearLayout(lm.getContext());
TextView name = new TextView(ll.getContext());
TextView surname = new TextView(ll.getContext());
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.