未知视图尺寸时如何移动视图?ImageView尺寸位置动画疑问
搞定ImageView尺寸位置动画,以及未知视图尺寸下的移动方案
嘿,我来帮你梳理下这个动画实现的问题,先给你修正下当前代码里的小坑,再解答你关于未知视图尺寸时移动视图的疑问~
一、先修正你的缩放比例计算
你现在直接拿R.attr.actionBarSize来算比例是不对的,这玩意儿只是个属性ID,不是实际的像素值。得先把这个属性解析成真实的ActionBar高度,代码改这样:
void doAnimation() { ImageView logo = findViewById(R.id.logo); // 正确获取ActionBar的实际像素高度 TypedValue tv = new TypedValue(); if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); // 计算缩放比例(注意转成float避免整数除法) float scaleVal = actionBarHeight / (float) logo.getHeight(); // 用属性动画实现平滑缩放 ObjectAnimator scaleX = ObjectAnimator.ofFloat(logo, "scaleX", scaleVal); ObjectAnimator scaleY = ObjectAnimator.ofFloat(logo, "scaleY", scaleVal); AnimatorSet scaleAnimSet = new AnimatorSet(); scaleAnimSet.playTogether(scaleX, scaleY); scaleAnimSet.setDuration(300); // 动画时长,单位毫秒 scaleAnimSet.start(); } // 获取屏幕密度的代码可以保留,不过现在更推荐直接从Resources拿 DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float density = displayMetrics.density; }
二、未知视图尺寸时怎么移动视图?
很多新手都会遇到这个问题:在onCreate里直接拿视图宽高得到的是0,因为视图还没完成测量和布局。这时候得等视图准备好再操作,给你几个靠谱的方案:
1. 用View.post()最省心
视图的post()方法会把任务放到它的消息队列里,等视图完成布局后再执行,代码简单还靠谱:
ImageView logo = findViewById(R.id.logo); logo.post(new Runnable() { @Override public void run() { // 这里可以安全拿到logo的真实宽高 int logoWidth = logo.getWidth(); int logoHeight = logo.getHeight(); // 举个例子:把logo向右移动自身宽度的距离 ObjectAnimator moveAnim = ObjectAnimator.ofFloat(logo, "translationX", logoWidth); moveAnim.setDuration(300); moveAnim.start(); } });
2. 监听视图树的布局完成事件
如果需要更精确的时机,可以用ViewTreeObserver监听布局完成,拿到尺寸后记得移除监听,避免重复触发:
ImageView logo = findViewById(R.id.logo); ViewTreeObserver observer = logo.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 适配不同API版本移除监听 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { logo.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { logo.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // 拿到真实尺寸 int realWidth = logo.getWidth(); int realHeight = logo.getHeight(); // 比如把logo移动到屏幕右下角 DisplayMetrics dm = getResources().getDisplayMetrics(); float targetX = dm.widthPixels - realWidth; float targetY = dm.heightPixels - realHeight; AnimatorSet moveSet = new AnimatorSet(); moveSet.playTogether( ObjectAnimator.ofFloat(logo, "translationX", targetX), ObjectAnimator.ofFloat(logo, "translationY", targetY) ); moveSet.setDuration(500); moveSet.start(); } });
3. 用ValueAnimator动态计算(小众场景)
如果不想提前等尺寸,也可以用ValueAnimator在动画过程中实时获取尺寸,但这种场景不多,一般还是前面两种方法更稳妥:
ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float progress = animation.getAnimatedFraction(); int logoWidth = logo.getWidth(); // 按动画进度移动 logo.setTranslationX(progress * logoWidth); } }); animator.setDuration(300); animator.start();
最后提个小建议:移动视图时尽量用translationX、translationY这类属性动画,别直接改LayoutParams——属性动画会自动处理平滑过渡,还不会触发视图重新布局,性能和体验都更好。
内容的提问来源于stack exchange,提问作者nikolouzos
相关产品推荐
相关产品推荐

