簡體   English   中英

android on view 從父級中移除

[英]android on view removed from parent

在子布局(視圖)上是否有從父視圖中刪除視圖時的回調? 視圖完成后,我需要回收一些圖像。 我一直在網上四處尋找該怎么做,但還沒有找到任何有用的東西。

我也一直在尋找這樣的東西。 我能找到的最好的是 View.OnAttachStateChangeListener。 我懷疑它是否理想,因為它是從窗口添加和刪除視圖時的回調 - 不是父級,但它足以滿足我的需要。

您可以在自定義View代碼中覆蓋onDetachedFromWindow ,而不是注冊新的偵聽器。

我掉進了馬爾默所說的那個陷阱:)

@Override
protected void onDetachedFromWindow() { I want to do something here, sometimes called sometimes not!!}

protected void onAttachedToWindow() {It is working fine, always}

此代碼位於CustomView

調用代碼為:

    contentHolder.removeAllViews();
    // ... init my  CustomView   ...
    contentHolder.addView(myCustomView);
    contentHolder.requestLayout();// useless, not need
    contentHolder.invalidate();// useless, not need

要了解為什么不起作用,您必須進入 Android API:

public void removeAllViews() {
    removeAllViewsInLayout();
    requestLayout();
    invalidate(true);
}

public void removeAllViewsInLayout() {
    final int count = mChildrenCount;
    if (count <= 0) {
        return;
    }

    final View[] children = mChildren;
    mChildrenCount = 0;

    final View focused = mFocused;
    final boolean detach = mAttachInfo != null;
    boolean clearChildFocus = false;

    needGlobalAttributesUpdate(false);

    for (int i = count - 1; i >= 0; i--) {
        final View view = children[i];

        if (mTransition != null) {
            mTransition.removeChild(this, view);
        }

        if (view == focused) {
            view.unFocus(null);
            clearChildFocus = true;
        }

        view.clearAccessibilityFocus();

        cancelTouchTarget(view);
        cancelHoverTarget(view);

        if (view.getAnimation() != null ||
                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
            addDisappearingView(view);
        } else if (detach) {
           view.dispatchDetachedFromWindow();
        }

        if (view.hasTransientState()) {
            childHasTransientStateChanged(view, false);
        }

        dispatchViewRemoved(view);

        view.mParent = null;
        children[i] = null;
    }

    if (clearChildFocus) {
        clearChildFocus(focused);
        if (!rootViewRequestFocus()) {
            notifyGlobalFocusCleared(focused);
        }
    }
}

關鍵在這里:

        if (view.getAnimation() != null ||
                (mTransitioningViews != null && mTransitioningViews.contains(view))) {

所以,如果你有動畫(在 1 種情況下我有,在 9 種情況下沒有)它不會調用onDetachedFromWindow()並且它會弄亂整個 UI :)

public void endViewTransition(View view) {
    if (mTransitioningViews != null) {
        mTransitioningViews.remove(view);
        final ArrayList<View> disappearingChildren = mDisappearingChildren;
        if (disappearingChildren != null && disappearingChildren.contains(view)) {
            disappearingChildren.remove(view);
            if (mVisibilityChangingChildren != null &&
                    mVisibilityChangingChildren.contains(view)) {
                mVisibilityChangingChildren.remove(view);
            } else {
                if (view.mAttachInfo != null) {
                    view.dispatchDetachedFromWindow();
                }
                if (view.mParent != null) {
                    view.mParent = null;
                }
            }
            invalidate();
        }
    }
}

同樣在某些情況下,即使有動畫也會被調用。 addDisappearingView(view);

接受的答案建議是這樣的:

    addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View v) {
        }

        @Override
        public void onViewDetachedFromWindow(View v) {
            System.out.println("MyCustomView.onViewDetachedFromWindow");
        }
    });

可悲的是動畫不會打印所需的文本。

來自 android.view.ViewGroup API 的一些重要代碼:

void dispatchViewRemoved(View child) {
    onViewRemoved(child);
    if (mOnHierarchyChangeListener != null) {
        mOnHierarchyChangeListener.onChildViewRemoved(this, child);
    }
}

public void onViewRemoved(View child) {
}

因此,您可以為此方法覆蓋您的RelativeLayout 我的動畫是無限動畫,不會很快調用任何方法!

如果您有無限動畫,正確的方法是編寫此代碼,當您調用刪除所有視圖時:

    if(contentHolder.getChildCount() > 0 ){
        View child0 = contentHolder.getChildAt(0);
        Animation animation = child0.getAnimation();
        if(animation != null) {
            animation.cancel();
            child0.clearAnimation();
        }
    }
    contentHolder.removeAllViews();

現在它將被稱為protected void onDetachedFromWindow()

Android KTX (Core KTX)庫為此提供了一個很好的解決方案。

您將需要此依賴項:androidx.core:core-ktx:1.3.0

然后,您可以調用函數“doOnDetach”來表示您希望在從窗口中刪除視圖時運行一些代碼(一次):

fun myInitCode() {
    ...
    myView.doOnDetach(this::doOnMyViewDetachFromWindow)
    ...
}

fun doOnMyViewDetachFromWindow(view: View) {
    ... put your image cleanup code here ...
}

您可以將 lambda 傳遞給“doOnDetach”,但如上所示的方法引用可能更清晰,具體取決於您必須執行的工作量。

doOnDetach 的描述如下:

androidx.core.view ViewKt.class public inline fun View.doOnDetach( crossinline action: (View) → Unit ): Unit

當此視圖與窗口分離時執行給定的操作。 如果視圖未附加到窗口,則操作將立即執行,否則將在視圖與其當前窗口分離后執行操作。 該操作只會被調用一次,然后將刪除所有偵聽器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM