/**
* View放大
*/
void animateZoomIn(View view) {
view.setPivotX(view.getHeight() /2));
view.setPivotY(view.getHeight() /2);
ViewCompat.animate(view).setDuration(100).scaleX(1.25f).scaleY(1.25f).start();
}
如上,如果在ListView或RecycleView中要根据View的宽高来设置放大中心点会出现意想不到的Bug。
有三种情况出现:
情况一:正常情况符合要求显示,放大中心点在(view.getHeight() /2, view.getHeight() /2);
情况二:不符合要求显示,放大中心点在(0, 0);
情况三:不符合要求显示,放大中心点在(不确定位置, 不确定位置),数值取决于复用的View;
造成这种现象的原因是他们的回收复用机制。
如果不懂回收复用机制看这篇RecycleView的回收复用机制原理。
解决方法:
方法1:通过ViewTreeObserver .addOnGlobalLayoutListener来获得宽高,当获得正确的宽高后,请移除这个观察者,否则回调会多次执行
//获得ViewTreeObserver
ViewTreeObserver observer=view.getViewTreeObserver();
//注册观察者,监听变化
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//判断ViewTreeObserver 是否alive,如果存活的话移除这个观察者
if(observer.isAlive()){
observer.removeGlobalOnLayoutListener(this);
//获得宽高
int viewWidth=view.getMeasuredWidth();
int viewHeight=view.getMeasuredHeight();
}
}
});
方法2:通过ViewTreeObserver .addOnPreDrawListener来获得宽高,在执行onDraw之前已经执行了onLayout()和onMeasure(),可以得到宽高了,当获得正确的宽高后,请移除这个观察者,否则回调会多次执行
//获得ViewTreeObserver
ViewTreeObserver observer=view.getViewTreeObserver();
//注册观察者,监听变化
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if(observer.isAlive()){
observer.removeOnDrawListener(this);
}
//获得宽高
int viewWidth=view.getMeasuredWidth();
int viewHeight=view.getMeasuredHeight();
return true;
}
});
方法3:利用view.post方法
void animateZoomIn(final View view, final int position) {
view.post(new Runnable() {
@Override
public void run() {
if (isFirstItem(position)){
animateZoomIn(view, 0, view.getHeight() /2);
Log.d(TAG, "isFirstItem : h=" +view.getHeight() /2);
}else if (isLastItem(position)){
animateZoomIn(view, mCurrentView.getWidth(), view.getHeight() /2);
Log.d(TAG, "isLastItem: w=" +view.getWidth() +", h=" +view.getHeight() /2);
}else {
animateZoomIn(view, view.getWidth() /2, view.getHeight() /2);
Log.d(TAG, "isMeddileItem: w=" +view.getWidth() /2 +", h=" +view.getHeight() /2);
}
}
});
}
总结:三种不同方式等待View完成测绘。
我的GitHub