Спершу зателефонуйте на RemoveView () батьків


138

Спочатку невелике тло:

У мене макет всередині прокрутки. Спочатку, коли користувач прокручує екран, прокрутка прокручує. Однак, після певної кількості прокрутки, я повинен був відключити прокрутку у вікні прокрутки, щоб перемістити "фокус прокрутки" на веб-перегляд всередині дочірнього макета. Таким чином, паличка перегляду прокрутки і всі події прокрутки переходять до веб-перегляду всередині нього.

Отже, для рішення, коли досягнуто порогу прокрутки, я видаляю дочірню компоновку з перегляду прокрутки і поміщаю її в батьківський список прокрутки. (І роблю прокрутку невидимою).

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

Загальна ідея: (-> засоби містять)

Перед: parentlayout -> scrollview -> scrollChildLayout

Після: parentLayout -> scrollChildLayout

Наведений вище код дає мені такий виняток:

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)

Ви знаєте, що відбувається? Я чітко закликаю deleteView від батьків.

Відповіді:


289

Рішення:

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

Використовуйте дочірній елемент, щоб отримати посилання на батьків. Відкиньте батьківську групу ViewGroup, щоб ви отримали доступ до методу removeView і скористалися цим.

Завдяки @Dongshengcn за рішення


1
Рішення правильне, але чому "scollView.removeView (scrollChildLayout)" не працює? Чи не повинні два рядки бути однаковими?
andrea.rinaldi

@ andrea.spot, схоже, scrollView.removeView(scrollChildLayout)намагається видалити дитину scrollView, а не видалити сам scrollView з його батьківського ViewGroup
Дмитро

1
@ user25 Я знаю, що це може бути занадто пізно для u, але нульове виключення вказівника пов'язане з тим, що батьківський порожній означає, що подання не приєднано до жодного з батьків. оскільки на початку немає батьків, неможливо нічого видалити. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Тарек

@kasgoku чи можете ви мені допомогти. Я намагаюся показати фрагмент у відносному макеті при натисканні кнопки. але помилка показу "У вказаної дитини вже є батько. Спершу потрібно зателефонувати на RemoveView () батьків". як це вирішити?
Imranrana07

Я також отримав цю помилку в моєму додатку, який є одним із чат-додатків. Я намагаюся вирішити цю проблему. цей значок видалено, але мені знову потрібен значок для завантаження зображень. ( stackoverflow.com/q/58117428/10971384 ) це моє запитання
Thangapandi

21

Спробуйте спочатку видалити scrollChildLayout з його батьківського перегляду?

scrollview.removeView(scrollChildLayout)

Або видаліть всю дитину з батьківського подання та додайте їх знову.

scrollview.removeAllViews()

Я вже закликаю deleteView в коді в своєму запитанні вище. RemoveAllViews () також не працює.
kasgoku

Ви впевнені, що це батько, якого ви називаєте RemoveView () / removeAllViews ()? Я роблю дуже подібну річ, і це працює на мене.
dongshengcn

4
Ви можете подивитися на його батьків, переглянувши: view.getParent () developer.android.com/reference/android/view/…
dongshengcn

@dongshengcn чи можете ви мені допомогти. Я намагаюся показати фрагмент у відносному макеті при натисканні кнопки. але помилка показу "У вказаної дитини вже є батько. Спершу потрібно зателефонувати на RemoveView () батьків". як це вирішити?
Imranrana07

19

У onCreate з активністю або в onCreateView з фрагментом.

 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

Гаразд, назвіть мене параноїком, але я пропоную:

  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

кастинг без instanceofпросто здається неправильним. І (спасибі IntelliJ IDEA за те, що мені сказали) removeViewє частиною ViewManagerінтерфейсу. І не слід кидати конкретний клас, коли є ідеально підходящий інтерфейс.


3

Все, що вам потрібно зробити, це опублікувати () Runnable, який виконує addView ().


Не працювало. Це те, що я спробував: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (новий Runnable () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku

1

Я дзвонив parentView.removeView (childView), і childView все ще показував. Зрештою я зрозумів, що метод якимось чином запускається двічі і додав childView до parentView двічі.

Отже, використовуйте parentView.getChildCount (), щоб визначити, скільки дітей має батько до того, як ви додасте подання і потім. Якщо дитину додано занадто багато разів, то видаляється найбільша частина дитини, а копія childView залишається - схоже, що RemoveView працює навіть тоді, коли він є.

Також не слід використовувати View.GONE для видалення подання. Якщо він справді видалений, то вам не потрібно буде його ховати, інакше він все ще є, і ви просто ховаєте його від себе :(


1

У моєму випадку у мене є BaseFragment, і всі інші фрагменти успадковуються від цього.

Тож моє соліціонування було додавати ці рядки в OnDestroyView()метод

@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();
}

ви спробували вибрати наступний фрагмент і занадто швидко натиснути назад?
iamthevoid

1

Рішення Котліна

Kotlin спрощує батьківське кастинг as?, повертаючи null, якщо ліва сторона є нульовою або не виконана передача.

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

Рішення розширення Kotlin

Якщо ви хочете ще більше спростити це, ви можете додати це розширення.

childView.removeSelf()

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

Він безпечно нічого не зробить, якщо цей перегляд є нульовим, батьківський вигляд - нульовим або батьківський подання не є ViewGroup

ПРИМІТКА. Якщо ви також хочете, щоб безпечне вилучення дитячих поглядів від батьків, додайте це:

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

0

Ви також можете зробити це, перевіривши, чи метод ViewOdViewOfView, якщо метод indexOfView повертає -1, то ми можемо використовувати.

DetachViewFromParent (v) ViewGroup; слідує видалити ViewDatachedView ViewGroup (v, правда / хибність);


0

Що я робив неправильно, тому я отримав цю помилку, це те, що я не створив динамічний макет і додав до нього дітей, тому отримав цю помилку


0

Ось моє рішення.

Скажімо, у вас є два TextViewsі покладіть їх на LinearLayout(названі ll). Ви покладете це LinerLayoutна інший 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> 

Коли ви хочете створити цю структуру, вам потрібно надати батьківщину як спадщину.

Якщо ви хочете використовувати його в onCreateметоді thisбуде достатньо.

Інакше ось рішення:

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());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.