Panggil removeView () pada orang tua anak terlebih dahulu

138

Pertama sedikit latar belakang:

Saya memiliki tata letak di dalam scrollview. Pada awalnya, ketika pengguna menggulir di layar, scrollview akan bergulir. Namun, setelah sejumlah gulir, saya harus menonaktifkan gulir pada gulir, melihat pindahkan "gulir fokus" ke tampilan web di dalam tata letak anak. Dengan cara ini, scrollview stick dan semua acara scroll pergi ke tampilan web di dalamnya.

Jadi, untuk solusi, ketika ambang gulir tercapai, saya menghapus tata letak anak dari scrollview dan meletakkannya di induk scrollview. (Dan membuat scrollview tidak terlihat).

// 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);

Gagasan Umum: (-> berarti mengandung)

Sebelum: parentlayout -> scrollview -> scrollChildLayout

Setelah: parentLayout -> scrollChildLayout

Kode di atas memberi saya pengecualian ini:

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)

Apakah Anda tahu apa yang sedang terjadi? Saya jelas memanggil removeView pada induknya.

kasgoku
sumber

Jawaban:

289

Larutan:

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

Gunakan elemen anak untuk mendapatkan referensi ke orang tua. Keluarkan induk ke ViewGroup sehingga Anda mendapatkan akses ke metode removeView dan gunakan itu.

Terima kasih kepada @Dongshengcn untuk solusinya

kasgoku
sumber
1
Solusinya benar, tetapi mengapa "scollView.removeView (scrollChildLayout)" tidak akan berfungsi? Bukankah kedua garis itu harus sama?
andrea.rinaldi
@ andrea.spot, sepertinya scrollView.removeView(scrollChildLayout)mencoba menghapus anak scrollView, bukan menghapus scrollView itu sendiri dari induknya ViewGroup
Dmitry Gryazin
1
@ user25 saya tahu ini mungkin sudah terlambat untuk Anda tetapi pengecualian pointer nol disebabkan oleh orangtua yang kosong yang berarti tampilan tidak melekat pada orangtua mana pun. karena tidak ada orang tua di awal, tidak ada yang dihapus. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek
@kasgoku, bisakah Anda membantu saya? Saya mencoba untuk menunjukkan fragmen dalam tata letak relatif pada klik tombol. tetapi kesalahan yang ditampilkan "Anak yang ditentukan sudah memiliki orangtua. Anda harus memanggil removeView () pada orangtua anak terlebih dahulu." bagaimana mengatasi ini?
Imranrana07
Saya juga mendapatkan kesalahan ini di aplikasi saya yang merupakan salah satu aplikasi chat. Saya mencoba menyelesaikan masalah ini. ikon itu dihapus tetapi saya perlu ikon itu lagi untuk mengunggah gambar. ( stackoverflow.com/q/58117428/10971384 ) ini adalah tautan pertanyaan saya
Thangapandi
21

Coba hapus scrollChildLayout dari tampilan induknya terlebih dahulu?

scrollview.removeView(scrollChildLayout)

Atau hapus semua anak dari tampilan induk, dan tambahkan lagi.

scrollview.removeAllViews()
dongshengcn
sumber
Saya sudah memanggil removeView dalam kode di pertanyaan saya di atas. removeAllViews () juga tidak berfungsi.
kasgoku
Apakah Anda yakin itu adalah orang tua yang Anda panggil removeView () / removeAllViews ()? Saya melakukan hal yang sangat mirip, dan itu berhasil bagi saya.
dongshengcn
4
Anda dapat melihat induknya dengan melihat: view.getParent () developer.android.com/reference/android/view/…
dongshengcn
@dongshengcn bisa tolong bantu saya. Saya mencoba untuk menunjukkan fragmen dalam tata letak relatif pada klik tombol. tetapi kesalahan yang ditampilkan "Anak yang ditentukan sudah memiliki orangtua. Anda harus memanggil removeView () pada orangtua anak terlebih dahulu." bagaimana mengatasi ini?
Imranrana07
19

Di onCreate dengan aktivitas atau di onCreateView dengan fragmen.

 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) {

}
Cabezas
sumber
15

Ok, panggil aku paranoid tapi aku sarankan:

  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

casting tanpa instanceofsepertinya salah. Dan (terima kasih IntelliJ IDEA karena memberi tahu saya) removeViewadalah bagian dari ViewManagerantarmuka. Dan seseorang seharusnya tidak menggunakan kelas beton ketika antarmuka yang sangat cocok tersedia.

Martin
sumber
3

Yang harus Anda lakukan adalah memposting () suatu Runnable yang melakukan addView ().

Guy Romain
sumber
Tidak bekerja Inilah yang saya coba: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (Runnable baru () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku
1

Saya menelepon parentView.removeView (childView) dan childView masih ditampilkan. Saya akhirnya menyadari bahwa suatu metode entah bagaimana dipicu dua kali dan menambahkan childView ke parentView dua kali.

Jadi, gunakan parentView.getChildCount () untuk menentukan berapa banyak anak yang dimiliki orang tua sebelum Anda menambahkan tampilan dan sesudahnya. Jika anak ditambahkan terlalu banyak maka anak paling atas sedang dihapus dan salinan childView tetap ada - yang tampak seperti removeView berfungsi bahkan ketika itu.

Selain itu, Anda tidak boleh menggunakan View.GONE untuk menghapus tampilan. Jika itu benar-benar dihapus maka Anda tidak perlu menyembunyikannya, kalau tidak itu masih ada dan Anda hanya menyembunyikannya dari diri sendiri :(

Chris Sprague
sumber
1

Dalam kasus saya, saya memiliki BaseFragment dan semua fragmen lain dari ini.

Jadi solytion saya adalah menambahkan baris ini dalam OnDestroyView()metode

@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();
}
Aleksey Timoshchenko
sumber
Sudahkah Anda mencoba memilih fragmen berikutnya dan menekan kembali terlalu cepat?
iamthevoid
1

Solusi Kotlin

Kotlin menyederhanakan casting orangtua dengan as?, mengembalikan nol jika sisi kiri adalah nol atau gips gagal.

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

Solusi Ekstensi Kotlin

Jika Anda ingin menyederhanakan ini lebih jauh, Anda dapat menambahkan ekstensi ini.

childView.removeSelf()

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

Ini tidak akan melakukan apa pun jika Tampilan ini adalah nol, tampilan induk adalah nol, atau tampilan induk bukan merupakan ViewGroup

CATATAN: Jika Anda juga ingin penghapusan aman dilihat anak oleh orang tua, tambahkan ini:

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

Anda juga dapat melakukannya dengan memeriksa apakah metode indexOfView View jika metode indexOfView mengembalikan -1 maka kita dapat menggunakan.

DetachViewFromParent ViewGroup (v); diikuti oleh removeDetachedView dari ViewGroup (v, true / false);

Arun Gupta
sumber
0

Apa yang saya lakukan salah jadi saya mendapatkan kesalahan ini adalah saya tidak instantiating tata letak dinamis dan menambahkan childs ke dalamnya sehingga mendapat kesalahan ini

Elang Hitam
sumber
0

Ini solusinya.

Katakanlah Anda memiliki dua TextViewsdan menaruhnya di LinearLayout(bernama ll). Anda akan menempatkan ini LinerLayoutdi yang lain 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> 

Saat Anda ingin membuat struktur ini, Anda harus memberikan induk sebagai warisan.

Jika Anda ingin menggunakannya dalam suatu onCreatemetodethis akan cukup.

Kalau tidak di sini solition:

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());
ishak O.
sumber