Call removeViewInternal, removeView screen or display interface is deleted and source code analysis solutions

This is a problem encountered in the use of Fragmentation, in this library many people have encountered this problem. The pursuit of the ultimate experience, I had to modify the source code. The source of the problem, I have modified, it will open up in the near future.

Here the core of the problem extracted for analysis.

problem:

1, after removeViewInternal, or displayed on the screen is deleted layout interface
2, although the display interface layout that is deleted on the screen, but you can click on the event can be passed to the back of the layout.
3, using Layout Inspector, analyzing the layout, the display layout is behind the current layout of the screen does not have any data

As shown below:
corresponding to point 2 above, clicks the login button to prompt toast

Here Insert Picture Description

The above corresponds to point 3
Here Insert Picture Description

Source analysis:

The root cause of the problem is to remove view at the time, animated view has not been executed.

We begin to analyze the function of removeViewInternal ViewGroup

    /**
     * Removes a view during layout. This is useful if in your onLayout() method,
     * you need to remove more views.
     *
     * <p><strong>Note:</strong> do not invoke this method from
     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
     *
     * @param view the view to remove from the group
     */
    public void removeViewInLayout(View view) {
        removeViewInternal(view);
    }
    private boolean removeViewInternal(View view) {
        //获取参数view  在viewGroup中mChildren(view 数组)的索引位置
        final int index = indexOfChild(view);
        if (index >= 0) {
            //调用函数进行删除操作
            removeViewInternal(index, view);
            return true;
        }
        return false;
    }
private void removeViewInternal(int index, View view) {

		...省略若干代码.....
		//判断当前的view 正在播放,或预定播放的动画
        if (view.getAnimation() != null ||
                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
            addDisappearingView(view);
        } else if (view.mAttachInfo != null) {
           view.dispatchDetachedFromWindow();
        }
		...省略若干代码.....

    }

In removeViewInternal function, the code is omitted nothing to do with this issue.

view.getAnimation () is very simple, the focus is to analyze what it means mTransitioningViews

    // The set of views that are currently being transitioned. This list is used to track views
    // being removed that should not actually be removed from the parent yet because they are
    // being animated.
    private ArrayList<View> mTransitioningViews;

It means that there is an array to store the list view of the transition animation. Because they already have animation, and therefore should not actually deleted from the parent view.

Transition animation here refers to the layout container Animation (LayoutTransition official website ), the popular talk is to add, hide the child view, when there is animation.

If these animation effects will be executed addDisappearingView ()

    /**
     * Add a view which is removed from mChildren but still needs animation
     *
     * @param v View to add
     */
    private void addDisappearingView(View v) {
        ArrayList<View> disappearingChildren = mDisappearingChildren;

        if (disappearingChildren == null) {
            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
        }

        disappearingChildren.add(v);
    }

As can be seen from the comments, these have animated deleted view, add to the list an array mDisappearingChildren

When dispatchDraw ViewGroup first call next, will mDisappearingChildren drawn in view

    @Override
    protected void dispatchDraw(Canvas canvas) {
       ...省略若干代码.....
        // Draw any disappearing views that have animations
        if (mDisappearingChildren != null) {
            final ArrayList<View> disappearingChildren = mDisappearingChildren;
            final int disappearingCount = disappearingChildren.size() - 1;
            // Go backwards -- we may delete as animations finish
            for (int i = disappearingCount; i >= 0; i--) {
                final View child = disappearingChildren.get(i);
                //在当前的viewGroup中绘制有动画但是被删除的view
                more |= drawChild(canvas, child, drawingTime);
            }
        }

     ...省略若干代码.....
  }

At this point, I know why some view after remove, or will be displayed

Solution:

Know the cause, the solution is very simple, before the remove view, ensure that the animation executed, or to manuallyviewclearAnimation();

Published 242 original articles · won praise 775 · Views 2.24 million +

Guess you like

Origin blog.csdn.net/xx326664162/article/details/103616005