最初に子の親でremoveView()を呼び出します


138

最初に少し背景:

スクロールビュー内にレイアウトがあります。最初に、ユーザーが画面をスクロールすると、scrollviewがスクロールします。ただし、一定量のスクロールの後、スクロールビューでスクロールを無効にし、「スクロールフォーカス」を子レイアウト内のWebビューに移動しました。このように、scrollviewは固定され、すべてのスクロールイベントはその内部のWebviewに移動します。

したがって、解決策として、スクロールしきい値に達したときに、子レイアウトをスクロールビューから削除し、スクロールビューの親に配置します(そしてスクロールビューを非表示にします)。

// 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を明確に呼び出しています。

回答:


289

解決:

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

子要素を使用して、親への参照を取得します。親をViewGroupにキャストして、removeViewメソッドにアクセスし、それを使用できるようにします。

ソリューションを提供してくれた@Dongshengcnに感謝


1
解決策は正しいですが、「scollView.removeView(scrollChildLayout)」が機能しないのはなぜですか?2つの線が同じであるべきではありませんか?
andrea.rinaldi 2014年

@ andrea.spotは、scrollView scrollView.removeView(scrollChildLayout)の子を削除しようとするようであり、親のViewGroupからscrollView自体を削除しようとしないようです
Dmitry Gryazin

1
@ user25私はこれが多分遅すぎるのを知っていますが、nullポインタ例外は、ビューがどの親にもアタッチされていないことを意味する親が空であることによるものです。最初は親がいないため、削除するものはありません。 if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek、2016

@kasgokuお願いします。ボタンをクリックすると、相対レイアウトでフラグメントを表示しようとしています。しかし、「指定された子にはすでに親があります。最初に子の親でremoveView()を呼び出す必要があります」というエラーが表示されます。これを解決するには?
Imranrana07

チャットアプリケーションの1つであるアプリケーションでもこのエラーが発生しました。私はこの問題を解決しようとしています。そのアイコンは削除されましたが、画像をアップロードするにはもう一度アイコンが必要です。(stackoverflow.com/q/58117428/10971384)これは私の質問リンクです
タンガパンディ

21

最初に親ビューからscrollChildLayoutを削除してみますか?

scrollview.removeView(scrollChildLayout)

または、親ビューからすべての子を削除して、もう一度追加します。

scrollview.removeAllViews()

上記の質問のコードですでにremoveViewを呼び出しています。removeAllViews()も機能しません。
kasgoku

それがremoveView()/ removeAllViews()を呼び出す親であると確信していますか?私は非常に似たようなことをやっていて、それは私のために働いています。
dongshengcn 2011年

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に教えてくれてありがとう) removeViewViewManagerインターフェースの一部です。そして、完全に適切なインターフェースが利用可能な場合、具象クラスにキャストすべきではありません。


3

addView()を実行するRunnableをpost()するだけです。


うまくいきませんでした。これは私が試したものです:scrollView.removeView(scrollChildLayout); scrollView.setVisibility(View.GONE); parentLayout.post(new Runnable(){@Override public void run(){parentLayout.addView(scrollChildLayout);}});
kasgoku

1

parentView.removeView(childView)を呼び出していましたが、childViewはまだ表示されていました。最終的にメソッドが2回トリガーされていることに気づき、childViewをparentViewに2回追加しました。

そのため、parentView.getChildCount()を使用して、ビューを追加する前と後で親が持つ子の数を判別します。子が何度も追加された場合、一番上の子が削除され、copy 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ソリューション

Kotlinはを使用して親のキャストを簡略化しas?、左側がnullであるかキャストが失敗した場合はnullを返します。

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

Kotlin拡張ソリューション

これをさらに単純化したい場合は、この拡張機能を追加できます。

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

0

また、ビューのindexOfViewメソッドがindexOfViewメソッドが-1を返した場合に使用できるかどうかを確認することによっても実行できます。

ViewGroupのdetachViewFromParent(v); 続いてViewGroupのremoveDetachedView(v、true / false);


0

私が間違っていたのでこのエラーが発生したのは、動的レイアウトをインスタンス化してそれに子を追加していないため、このエラーが発生しました


0

これが私の解決策です。

あなたが2つ持って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は十分です。

それ以外の場合は、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());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.