问题追踪:ImageView执行缩放动画ScaleAnimation之后,图像显示不全的问题。

问题:我有一个ScrollView,嵌套了一个垂直向的LinearLayout,然后这个LinearLayout中有多个ImageView控件,分别显示自己的图像。

接着我新建了一个放大的ScaleAnimation动画,然后设置给LinearLayout或ScrollView。现在我通过监听ScrollView来滚动LinearLayout,使得放大后的ImageView可以全部看得见。

但是当我fling滑动之后,重新设置ImageView的Bitmap,此时的Bitmap虽然是跟着放大了的效果,但是被裁减了,显示不全。

解决方案:一开始,我去ScrollView和LinearLayout的onDraw方法和draw方法中查看,没有发现有什么异常,(by the way,我发现LinearLayout竟然真的能像ListView一样可以设置Divider,我之前没有发现过哟!),然后我去ImageView的onDraw方法中查看,发现有一个mDrawable,这个就是背景Drawable,还有一个mDrawMatrix,如果mDrawMatrix==null,则直接绘制mDrawable,接着我去看了一下这个mDrawMatrix是怎么赋值的。

    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        boolean changed = super.setFrame(l, t, r, b);
        mHaveFrame = true;
        configureBounds();
        return changed;
    }

    private void configureBounds() {
        if (mDrawable == null || !mHaveFrame) {
            return;
        }

        int dwidth = mDrawableWidth;
        int dheight = mDrawableHeight;

        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
        int vheight = getHeight() - mPaddingTop - mPaddingBottom;

        boolean fits = (dwidth < 0 || vwidth == dwidth) &&
                       (dheight < 0 || vheight == dheight);

        if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
            /* If the drawable has no intrinsic size, or we‘re told to
                scaletofit, then we just fill our entire view.
            */
            mDrawable.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            mDrawable.setBounds(0, 0, dwidth, dheight);

            if (ScaleType.MATRIX == mScaleType) {
                // Use the specified matrix as-is.
                if (mMatrix.isIdentity()) {
                    mDrawMatrix = null;
                } else {
                    mDrawMatrix = mMatrix;
                }
            } else if (fits) {
                // The bitmap fits exactly, no transform needed.
                mDrawMatrix = null;
            } else if (ScaleType.CENTER == mScaleType) {
                // Center bitmap in view, no scaling.
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
                                         (int) ((vheight - dheight) * 0.5f + 0.5f));
            } else if (ScaleType.CENTER_CROP == mScaleType) {
                mDrawMatrix = mMatrix;

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
            } else if (ScaleType.CENTER_INSIDE == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;

                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }

                dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
                dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                mTempSrc.set(0, 0, dwidth, dheight);
                mTempDst.set(0, 0, vwidth, vheight);

                mDrawMatrix = mMatrix;
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
    }

很显然,这个mDrawMatrix会根据mScaleType的值来操作,因为我的程序内mScaleType是ScaleType.FIT_XY,所以执行了这段:

if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {  mDrawable.setBounds(0, 0, vwidth, vheight);
  mDrawMatrix = null;}

这个mDrawable被设置成控件本身的宽高了。

然后我试图查找下当控件被执行动画之后,这个bounds会不会也被设置了,我找到了一个方法:

    /**
     * Return the visible drawing bounds of your view. Fills in the output
     * rectangle with the values from getScrollX(), getScrollY(),
     * getWidth(), and getHeight(). These bounds do not account for any
     * transformation properties currently set on the view, such as
     * {@link #setScaleX(float)} or {@link #setRotation(float)}.
     *
     * @param outRect The (scrolled) drawing bounds of the view.
     */
    public void getDrawingRect(Rect outRect) {
        outRect.left = mScrollX;
        outRect.top = mScrollY;
        outRect.right = mScrollX + (mRight - mLeft);
        outRect.bottom = mScrollY + (mBottom - mTop);
    }

这个方法返回你的视图的绘制区域的边距信息,其中有一句话(These bounds do not account for any * transformation properties currently set on the view, such as * {@link #setScaleX(float)} or {@link #setRotation(float)}.) ,意思应该是这个bounds是不会被动画所影响的。好吧。。。感觉没有头绪了啊。。。

接着我去Google了一下:android ImageView after ScaleAnimation draw not complete

在倒数几条搜索结果中,

我找到了:ImageView scale animation cropping(link:https://code.google.com/p/android/issues/detail?id=20333),内容如下:

Reported by [email protected], Sep 26, 2011

I have a project that requires a fairly simple animation.
There is a ImageView created this way:
        <ImageView android:src="@drawable/letter3" android:clipChildren="false" android:clipToPadding="false" android:cropToPadding="false" android:id="@+id/startmessage" android:adjustViewBounds="true" android:layout_width="wrap_content" android:scaleType="fitCenter" android:layout_centerVertical="true" android:layout_centerHorizontal="true"></ImageView>

As I understand it wrap_content should keep the size of the view big enough to contain the image within.
Then in code I set an image and start an animation that fades out and scales up the image:

final ImageView v = (ImageView)findViewById(R.id.startmessage);
                fadeout.setAnimationListener(null);
                v.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.letter3));
                v.startAnimation(fadeout);

Here is the animation code:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/accelerate_interpolator"
     android:shareInterpolator="true">
    <alpha  android:fromAlpha = "1.0"
            android:toAlpha = "0.0"
            android:duration="1000"
    />
</set>

The problem is that when the scaling animation begins the drawing rect does not seem to change so the image is cropped when it becomes larger. The problem occurs only on android 2.3.3 I believe, on device and on emulator as well. I played around with all the scaleType settings for the imageview but it didn‘t fix the problem.

Sep 26, 2011
#1 [email protected]

Correction - this is how the animation is defined:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/accelerate_interpolator"
     android:shareInterpolator="true">
    <alpha  android:fromAlpha = "1.0"
            android:toAlpha = "0.0"
            android:duration="1000"
    />
    <scale android:fromXScale="1.0"
           android:toXScale="6.0"
           android:fromYScale="1.0"
           android:toYScale="6.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:duration="1000"
    />
</set>

Sep 26, 2011
Project Member #2 [email protected]

The ImageView will be cropped by its parent. You need to disable children clipping on the parent and make the parent big enough.

Status: Declined
Sep 27, 2011
#3 [email protected]

The parent is fullscreen and it also is set to not crop the children, also this behavior is observer only on 2.3.3, on  2.2 and lower everything is working fine.

    <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:clipChildren="false" android:clipToPadding="false" android:id="@+id/startlayout" android:visibility="invisible">
        <ImageView android:layout_height="wrap_content" android:src="@drawable/letter3" android:layout_width="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:scaleType="fitCenter" android:id="@+id/startmessage"></ImageView>
    </RelativeLayout>

意思是你的父容器的clipChildren属性默认为true,导致了这个裁剪现象的发生。现在你只需要将ScrollView和LinearLayout的clipChildren属性设置为true即可。

就目前来看,我的三星i9250是没问题,另外我用Genymotion模拟器模拟4.3的Nexus4也没问题,其他版本的未知。

时间: 2024-12-11 10:50:57

问题追踪:ImageView执行缩放动画ScaleAnimation之后,图像显示不全的问题。的相关文章

UI基础--动画(缩放动画, 渐变动画, 左右振动, 移动动画, 组合动画)(封装好)

创建一个CAAnimation的类别 CAAnimation+HCAnimation .h #import <QuartzCore/QuartzCore.h> #import <UIKit/UIKit.h> typedef NS_ENUM(NSInteger, Axis) { AxisX = 0, ///< x轴 AxisY, ///< y轴 AxisZ ///< z轴 }; typedef NS_ENUM(NSInteger, ShakeDerection) {

android动画的透明度渐变、旋转动画、缩放动画、评议动画

这是我在学习android的时候做的一个小小的东西可以实现图片的旋转.平移.缩放.透明度的渐变 首先我们要创建一个android的项目 在自己的drawable-mdpi中添加自己的图片 然后在res目录中,创建一个名称是anim(动画)的目录,并且在该目录中实现图片的操作 首先是anim_alpha.xml定义一个实现透明渐变的动画该动画实现的是完全不透明-->完全透明---->完全不透明 <pre name="code" class="html"

android缩放动画的两种实现方法

在android开发.我们会常常使用到缩放动画,普通情况下缩放动画有两种实现方式.一种是直接通过java代码去实现,第二种是通过配置文件实现动画,以下是两种动画的基本是用法: Java代码实现: //创建缩放动画对象 Animation animation = new ScaleAnimation(0, 1.0f, 0f, 1.0f); animation.setDuration(1500);//动画时间 animation.setRepeatCount(3);//动画的反复次数 animati

Android缩放动画

Android缩放动画 核心方法 public void startAnimation(Animation animation) 运行动画,參数能够是各种动画的对象,Animation的多态.也能够是组合动画,后面会有. 4个參数构造方法 /** * Constructor to use when building a ScaleAnimation from code * * @param fromX Horizontal scaling factor to apply at the start

Android ImageView手势缩放完整的实现

已经有很多开源的缩放控件了,实际做项目没有必要重复造轮子,但对于学习来说自己亲自实现一个缩放的ImageView是大有益处的.所以这里分享一下自己学习的心得. 1.创建一个类继承ImageView. public class GestureImageView extends ImageView { public GestureImageView(Context context) { super(context); } public GestureImageView(Context context

Silverlight &amp; Blend动画设计系列三:缩放动画(ScaleTransform)

在Silverlight的动画框架中,ScaleTransform类提供了在二维空间中的坐标内进行缩放操作,通过ScaleTransform可以在水平或垂直方向的缩放和拉伸对象,以实现一个简单的缩放动画效果,故此我将其称为缩放动画(ScaleTransform).使用ScaleTransform需要特别关注的有两点:中心点坐标和X.Y轴方向的缩放比例,比例值越小则对象元素就越小(既收缩),比例值越大则对象元素就越大(既呈现为放大效果). Blend对Silverlight里的动画设计支持非常强大

iOS项目开发实战——制作视图的缩放动画

视图的大小应该是随时可控的.今天我们就来实现对一个View的缩放动画.该动画的实现与位移动画,透明度动画稍有不同. 详细实现例如以下: import UIKit class ScaleViewController: UIViewController { @IBOutlet weak var greenSquare: UIView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after

[ jquery 效果 stop(stopAll,goToEnd) ] 此方法用于停止所有在指定元素上正在运行的动画,如果队列中有等待执行的动画(并且clearQueue没有设为true),他们将被马上执行

停止所有在指定元素上正在运行的动画,如果队列中有等待执行的动画(并且clearQueue没有设为true),他们将被马上执行 实例: <!DOCTYPE html> <html lang='zh-cn'> <head> <title>Insert you title</title> <meta http-equiv='description' content=''.animation' is my page'> <meta ht

[WPF] 动画Completed事件里获取执行该动画的UI对象

原文:[WPF] 动画Completed事件里获取执行该动画的UI对象 昨天群里有位童鞋提出如何在动画完成事件Completed里获取到执行该动画的UI对象. WPF里动画的Completed的本身并不会返回执行动画的UI对象,但我们可以利用附加属性Storyboard.TargetProperty来达到我们想要的效果. 步骤: 1 在执行动画前,先附加属性记录对象 DoubleAnimation ani = new DoubleAnimation(); ani.From = start; an