Android中获取View宽高引发的Bug

/**

* 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

你可能感兴趣的:(Android中获取View宽高引发的Bug)