Сначала вызовите removeView() у родителя ребенка

Сначала немного предыстории:

У меня есть макет внутри прокрутки. Сначала, когда пользователь прокручивает на экране, прокрутка прокручивается. Однако после определенного количества прокрутки я должен был отключить прокрутку в представлении прокрутки и переместить "фокус прокрутки" на веб-просмотр внутри дочернего макета. Таким образом, скроллвид палки и все события прокрутки переходят в веб-просмотр внутри него.

Таким образом, для решения, когда порог прокрутки достигнут, я удаляю дочерний макет из scrollview и помещаю его в родительский элемент scrollview (и делаю scrollview невидимым).

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

Вы знаете, что происходит? Я явно вызываю removeView на родителя.

10 ответов

Решение

Решение:

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

Используйте дочерний элемент, чтобы получить ссылку на родителя. Приведите родителя к ViewGroup, чтобы вы получили доступ к методу removeView и использовали его.

Спасибо @Dongshengcn за решение

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

scrollview.removeView(scrollChildLayout)

Или удалите все дочерние элементы из родительского представления и добавьте их снова.

scrollview.removeAllViews()

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

}

Хорошо, называй меня параноиком, но я предлагаю:

  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 интерфейс. И не следует приводить к конкретному классу, когда доступен идеально подходящий интерфейс.

Котлин Решение

Kotlin упрощает родительское приведение с помощью as?, возвращает null, если левая сторона имеет значение null или приведение не выполняется.

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

Kotlin Extension Solution

Если вы хотите еще больше упростить это, вы можете добавить это расширение.

childView.removeSelf()

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

Он не будет безопасно ничего делать, если это представление имеет значение null, родительское представление имеет значение null или родительское представление не является ViewGroup.

ПРИМЕЧАНИЕ: Если вы также хотите безопасное удаление дочерних представлений родителем, добавьте это:

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

Все, что вам нужно сделать, это опубликовать () Runnable, который делает addView().

Я звонил parentView.removeView(childView), и childView все еще показывал. В конце концов я понял, что метод как-то запускается дважды, и дважды добавил childView к parentView.

Поэтому используйте parentView.getChildCount(), чтобы определить, сколько дочерних элементов имеет родительский объект до добавления представления и после него. Если дочерний объект добавляется слишком много раз, удаляется самый верхний дочерний элемент, и копия childView остается, что похоже на то, что removeView работает, даже если это так.

Кроме того, вы не должны использовать View.GONE, чтобы удалить представление. Если он действительно удален, вам не нужно его скрывать, иначе он все еще там, и вы просто скрываете это от себя:(

В моем случае у меня есть 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();
}

Что я делал неправильно, поэтому у меня возникла ошибка: я не создавал динамический макет и не добавлял в него дочерние элементы, поэтому получил эту ошибку

Вы также можете сделать это, проверив, если метод View indexOfView, если метод indexOfView возвращает -1, то мы можем использовать.

ViewGroup's detachViewFromParent (v); затем следует RemoveDetachedView от ViewGroup (v, true/false);

Вот мое решение.

Допустим, у вас есть два 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> 

Когда вы хотите создать эту структуру, вы должны предоставить parent как наследство.

Если вы хотите использовать его в 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());
Другие вопросы по тегам