Gọi removeView () trên cha mẹ của đứa trẻ trước


138

Đầu tiên một chút nền tảng:

Tôi có một bố cục bên trong một scrollview. Lúc đầu, khi người dùng cuộn trên màn hình, cuộn cuộn sẽ cuộn. Tuy nhiên, sau một số lần cuộn nhất định, tôi đã vô hiệu hóa cuộn trên chế độ xem cuộn để di chuyển "tiêu điểm cuộn" lên một chế độ xem web bên trong bố cục con. Bằng cách này, các thanh cuộn xem và tất cả các sự kiện cuộn đi đến webview bên trong nó.

Vì vậy, đối với một giải pháp, khi đạt đến ngưỡng cuộn, tôi xóa bố cục con khỏi chế độ xem cuộn và đặt nó vào cha mẹ của cuộn xem (Và làm cho chế độ xem cuộn không hiển thị).

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

Ý tưởng chung: (-> có nghĩa là chứa)

Trước: Parentlayout -> scrollview -> scrollChildLayout

Sau: ParentLayout -> scrollChildLayout

Đoạn mã trên cho tôi ngoại lệ này:

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)

Bạn có biết những gì đang xảy ra? Tôi rõ ràng đang gọi removeView trên cha mẹ.

Câu trả lời:


289

Giải pháp:

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

Sử dụng phần tử con để có được một tham chiếu đến cha mẹ. Truyền cha mẹ đến Viewgroup để bạn có quyền truy cập vào phương thức removeView và sử dụng phương thức đó.

Cảm ơn @Dongshengcn về giải pháp


1
Giải pháp là đúng, nhưng tại sao "scollView.removeView (scrollChildLayout)" sẽ không hoạt động? Không phải hai dòng giống nhau sao?
andrea.rinaldi

@ andrea.spot, có vẻ như scrollView.removeView(scrollChildLayout)cố gắng loại bỏ con của scrollView, không xóa chính scrollView khỏi mẹ của nó là Viewgroup
Dmitry Gryazin

1
@ user25 Tôi biết điều này có thể quá muộn đối với bạn nhưng ngoại lệ con trỏ null là do cha mẹ trống có nghĩa là chế độ xem không được đính kèm với bất kỳ cha mẹ nào. vì không có cha mẹ lúc ban đầu, không có gì để loại bỏ. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek

@kasgoku bạn có thể giúp tôi không. tôi đang cố gắng để hiển thị một đoạn trong bố trí tương đối trên một nút bấm. nhưng lỗi hiển thị của nó "Đứa trẻ được chỉ định đã có cha mẹ. Bạn phải gọi removeView () trên cha mẹ của đứa trẻ trước." Làm thế nào để giải quyết điều này?
Imranrana07

Tôi cũng gặp lỗi này trong ứng dụng của mình, đó là một trong những ứng dụng trò chuyện. Tôi đang cố gắng giải quyết vấn đề này. biểu tượng đó đã bị xóa nhưng tôi cần lại biểu tượng để tải lên hình ảnh. ( stackoverflow.com/q/58117428/10971384 ) đây là liên kết câu hỏi của tôi
Thangapandi

21

Trước tiên hãy thử gỡ scrollChildLayout khỏi chế độ xem chính của nó?

scrollview.removeView(scrollChildLayout)

Hoặc loại bỏ tất cả trẻ em khỏi chế độ xem cha mẹ và thêm chúng một lần nữa.

scrollview.removeAllViews()

Tôi đã gọi removeView trong mã trong câu hỏi của tôi ở trên. removeAllViews () cũng không hoạt động.
kasgoku

Bạn có chắc chắn đó là cha mẹ mà bạn đang gọi removeView () / removeAllViews () không? Tôi đang làm điều tương tự, và nó đã làm việc cho tôi.
dongshengcn

4
Bạn có thể nhìn vào cha mẹ của nó bằng cách xem: view.getParent () developer.android.com/reference/android/view/
dongshengcn

@dongshengcn bạn có thể giúp tôi xin vui lòng. tôi đang cố gắng để hiển thị một đoạn trong bố trí tương đối trên một nút bấm. nhưng lỗi hiển thị của nó "Đứa trẻ được chỉ định đã có cha mẹ. Bạn phải gọi removeView () trên cha mẹ của đứa trẻ trước." Làm thế nào để giải quyết điều này?
Imranrana07

19

Trong onCreate với hoạt động hoặc trong onCreateView với đoạn.

 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

Ok, gọi tôi là hoang tưởng nhưng tôi đề nghị:

  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

đúc mà không instanceofcó vẻ sai. Và (cảm ơn IntelliJ IDEA đã nói với tôi) removeViewlà một phần của ViewManagergiao diện. Và người ta không nên chuyển sang một lớp cụ thể khi có sẵn một giao diện hoàn toàn phù hợp.


3

Tất cả những gì bạn phải làm là đăng () một Runnable thực hiện addView ().


Không hoạt động. Đây là những gì tôi đã thử: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); ParentLayout.post (new Runnable () {@Override public void run () {ParentLayout.addView (scrollChildLayout);}});
kasgoku

1

Tôi đã gọi ParentView.removeView (childView) và childView vẫn hiển thị. Cuối cùng tôi nhận ra rằng một phương thức nào đó đã được kích hoạt hai lần và thêm childView vào ngoặc đơn hai lần.

Vì vậy, hãy sử dụng ParentView.getChildCount () để xác định số lượng cha mẹ có trước khi bạn thêm chế độ xem và sau đó. Nếu đứa trẻ được thêm quá nhiều lần thì phần lớn đứa trẻ hàng đầu sẽ bị xóa và bản sao conView vẫn còn - có vẻ như removeView đang hoạt động ngay cả khi nó còn.

Ngoài ra, bạn không nên sử dụng View.GONE để xóa chế độ xem. Nếu nó thực sự bị xóa thì bạn sẽ không cần phải che giấu nó, nếu không nó vẫn ở đó và bạn chỉ đang che giấu nó khỏi chính mình :(


1

Trong trường hợp của tôi, tôi có BaseFragment và tất cả các đoạn khác được thừa hưởng từ điều này.

Vì vậy, giải pháp của tôi là thêm dòng này vào OnDestroyView()phương thức

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

Bạn đã thử chọn đoạn tiếp theo và nhấn trở lại quá nhanh?
iamthevoid

1

Giải pháp Kotlin

Kotlin đơn giản hóa việc truyền phụ huynh với as?, trả về null nếu bên trái là null hoặc truyền không thành công.

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

Giải pháp mở rộng Kotlin

Nếu bạn muốn đơn giản hóa điều này hơn nữa, bạn có thể thêm tiện ích mở rộng này.

childView.removeSelf()

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

Nó sẽ không làm gì một cách an toàn nếu Chế độ xem này là null, chế độ xem chính là null hoặc chế độ xem chính không phải là một Viewgroup

LƯU Ý: Nếu bạn cũng muốn loại bỏ an toàn các chế độ xem con của cha mẹ, hãy thêm vào đây:

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

0

Bạn cũng có thể làm điều đó bằng cách kiểm tra xem phương thức indexOfView của View nếu phương thức indexOfView trả về -1 thì chúng ta có thể sử dụng.

DetachViewFromParent (v) của Viewgroup; theo sau là removeDetachedView của Viewgroup (v, true / false);


0

Điều tôi đã làm sai nên tôi gặp lỗi này là tôi đã không khởi tạo bố cục động và thêm con vào đó nên đã gặp lỗi này


0

Đây là giải pháp của tôi.

Hãy nói rằng bạn có hai TextViewsvà đặt chúng vào một LinearLayout(được đặt tên ll). Bạn sẽ đặt cái này LinerLayoutlên cái khác 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> 

Khi bạn muốn tạo cấu trúc này, bạn cần phải cho cha mẹ làm thừa kế.

Nếu bạn muốn sử dụng nó trong một onCreatephương pháp thissẽ đủ.

Nếu không thì đây là sự giải quyết:

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());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.