ViewAnimator遇到的坑
前言
在标题栏中想要这种效果(暂定义就叫轮播或者滚动效果)
android 提供了ViewSwitcher类,复用两个View,设置你想要的动画效果。
ViewSwitcher会在showNext()时,会执行View隐藏时的动画和下一个View显示时的动画(假设你都设定)
OK,这个上面效果就出现了。
这就结束了。。。。
No,有图片时,他可不是你想要的效果,除非你能忍受
仔细看,是不是图片会闪一下。
查看源码:
@android.view.RemotableViewMethod
public void showNext() {
setDisplayedChild(mWhichChild + 1);
}
@android.view.RemotableViewMethod
public void setDisplayedChild(int whichChild) {
mWhichChild = whichChild;
if (whichChild >= getChildCount()) {
mWhichChild = 0;
} else if (whichChild < 0) {
mWhichChild = getChildCount() - 1;
}
boolean hasFocus = getFocusedChild() != null;
// This will clear old focus if we had it
showOnly(mWhichChild);
if (hasFocus) {
// Try to retake focus if we had it
requestFocus(FOCUS_FORWARD);
}
}
/**
* Shows only the specified child. The other displays Views exit the screen,
* optionally with the with the {@link #getOutAnimation() out animation} and
* the specified child enters the screen, optionally with the
* {@link #getInAnimation() in animation}.
*
* @param childIndex The index of the child to be shown.
* @param animate Whether or not to use the in and out animations, defaults
* to true.
*/
void showOnly(int childIndex, boolean animate) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (i == childIndex) {
if (animate && mInAnimation != null) {
child.startAnimation(mInAnimation);
}
child.setVisibility(View.VISIBLE);
mFirstTime = false;
} else {
if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
child.startAnimation(mOutAnimation);
} else if (child.getAnimation() == mInAnimation)
child.clearAnimation();
child.setVisibility(View.GONE);
}
}
}
产生原因:在源码ViewAnimator.showNext->会调用到showOnly方法。
在showOnly中:
if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
child.startAnimation(mOutAnimation);
} else if (child.getAnimation() == mInAnimation)
child.clearAnimation();
child.setVisibility(View.GONE);
child.setVisibility(View.GONE);将下一个View设置为不可见,但是mOutAnimation不为null,下一个View会执行child.startAnimation(),在onDraw中将此View又重新绘制出来,造成闪一下。(这里涉及到View动画的原理)
解决方案就很简单:
ViewAnimator拷贝出来,将child.setVisibility(View.GONE) 变为
child.postDelayed(() -> child.setVisibility(View.GONE),mOutAnimation.getDuration());
当动画执行完成后,再将其设置为不可见。
ok 这样就解决了。