繼續入自定義View的坑,最近實現一個效果的時候,需要動態添加和刪除View,所以就要用到ViewGroup中的removeView和addView,按理來說應該很簡單,但是我遇到了一個問題,發現removeView無效。
最后發現:當你要remove的View正在執行Animation效果的時候,是無法remove掉的,所以需要先clearAnimation,再remove
從源碼中證實了我的觀點:
public void removeViewAt(int index) {
removeViewInternal(index, getChildAt(index));
requestLayout();
invalidate(true);
}
我調用的是removeViewAt方法,可以看到,實際上起作用的是removeViewInternal方法
private void removeViewInternal(int index, View view) {
...
if (view.getAnimation() != null || (mTransitioningViews != null
&&mTransitioningViews.contains(view))) {
addDisappearingView(view);
} else if (view.mAttachInfo != null) {
view.dispatchDetachedFromWindow();
}
...
}
一樣,當我第一樣看到這個方法,我是拒絕的,很長的方法體,非常多的變量不知道含義,第一次看我沒有找到原因。第二次再看的時候,我發現了上面這段代碼,非常符合我要尋找的問題,當View的Animation不是null的時候,會執行addDisappearingView(view)
/**
* 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);
}
可以看到,Google的解釋其實已經很清楚了,添加一個帶有動畫效果的View。
我看到這還是有點不確定,這里面沒有真正意義上的將Remove的View重繪到組件上。
所以我查詢了mDisappearingChildren這個對象,看在哪里使用了這個對象
@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);
more |= drawChild(canvas, child, drawingTime);
}
}
...
}
可以看到,我在dispatchDraw方法中找到了我想要的結果,可以看到,注釋寫的也很清楚,在重繪的時候,會將仍然有Animation的View繪制出來。
可以看到,這里遍歷了mDisappearingChildren,調用了drawChild進行繪制。
到此問題解決,小小的看了一下源碼,也是很有趣的