android – 如何动画矩阵以“裁剪”图像?

我正在尝试做一个图像查看器,当用户点击图像时,图像被“裁剪掉”并显示完整的图像.

例如,在下面的屏幕截图中,用户最初只能看到小狗的一部分.但是在用户点击图像后,整个小狗都被揭露了.在第一个后面褪色的图像显示了动画的结果.

最初,ImageView在X和Y中缩放到50%.当用户点击图像时,ImageView将缩放回100%,并重新计算ImageView矩阵.

我尝试了各种方法来计算矩阵.但我似乎无法找到适用于所有类型的作物和图像的景观:裁剪景观到纵向,裁剪景观到景观,裁剪纵向到纵向和裁剪纵向到景观.这有可能吗?

这是我现在的代码.我正在尝试找到setimageCrop()中的内容.

public class MainActivity extends Activity {

private ImageView img;
private float translateCropX;
private float translateCropY;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    img = (ImageView) findViewById(R.id.img);
    Drawable drawable = img.getDrawable();

    translateCropX = -drawable.getIntrinsicWidth() / 2F;
    translateCropY = -drawable.getIntrinsicHeight() / 2F;

    img.setScaleX(0.5F);
    img.setScaleY(0.5F);
    img.setScaleType(ScaleType.MATRIX);

    Matrix matrix = new Matrix();
    matrix.postScale(2F,2F); //zoom in 2X
    matrix.postTranslate(translateCropX,translateCropY); //translate to the center of the image
    img.setimageMatrix(matrix);

    img.setonClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            final PropertyValuesHolder animscaleX = PropertyValuesHolder.ofFloat(View.SCALE_X,1F);
            final PropertyValuesHolder animscaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y,1F);

            final ObjectAnimator objectAnim = ObjectAnimator.ofPropertyValuesHolder(img,animscaleX,animscaleY);

            final PropertyValuesHolder animMatrixCrop = PropertyValuesHolder.ofFloat("imageCrop",0F,1F);

            final ObjectAnimator cropAnim = ObjectAnimator.ofPropertyValuesHolder(MainActivity.this,animMatrixCrop);

            final AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.play(objectAnim).with(cropAnim);

            animatorSet.start();

        }
    });
}

public void setimageCrop(float value) {
    // No idea how to calculate the matrix depending on the scale

    Matrix matrix = new Matrix();
    matrix.postScale(2F,2F);
    matrix.postTranslate(translateCropX,translateCropY);
    img.setimageMatrix(matrix);
}

}

编辑:值得一提的是,线性缩放矩阵是行不通的. ImageView按比例线性缩放(0.5到1).但是如果我在动画期间线性缩放矩阵,则在动画期间视图会变窄.最终结果看起来很好,但在动画期间图像看起来很丑.

解决方法

我意识到你(以及其他答案)一直试图使用矩阵操作来解决这个问题,但是我想提出一种不同的方法,它具有你问题中提到的相同的视觉效果.

而不是使用矩阵来操纵图像的可见区域(视图),为什么不在剪切方面定义这个可见区域?这是一个相当简单的问题需要解决:我们需要做的就是定义可见的矩形,并忽略任何超出其边界的内容.如果我们然后为这些边界设置动画,则视觉效果就像裁剪边界向上和向下缩放一样.

幸运的是,Canvas支持剪切各种clip *()方法来帮助我们在这里.动画剪辑边界很简单,可以使用与您自己的代码片段类似的方式完成.

如果你把所有东西放在一个简单的常规ImageView扩展中(为了封装),你会得到一些看起来像这样的东西:

public class ClippingImageView extends ImageView {

    private final Rect mClipRect = new Rect();

    public ClippingImageView(Context context,AttributeSet attrs,int defStyle) {
        super(context,attrs,defStyle);
        initClip();
    }

    public ClippingImageView(Context context,AttributeSet attrs) {
        super(context,attrs);
        initClip();
    }

    public ClippingImageView(Context context) {
        super(context);
        initClip();
    }

    private void initClip() {
        // post to message queue,so it gets run after measuring & layout
        // sets initial crop area to half of the view's width & height
        post(new Runnable() {
            @Override public void run() {
                setimageCrop(0.5f);
            }
        });
    }

    @Override protected void onDraw(Canvas canvas) {
        // clip if needed and let super take care of the drawing
        if (clip()) canvas.clipRect(mClipRect);
        super.onDraw(canvas);
    }

    private boolean clip() {
        // true if clip bounds have been set aren't equal to the view's bounds
        return !mClipRect.isEmpty() && !clipEqualsBounds();
    }

    private boolean clipEqualsBounds() {
        final int width = getWidth();
        final int height = getHeight();
        // whether the clip bounds are identical to this view's bounds (which effectively means no clip)
        return mClipRect.width() == width && mClipRect.height() == height;
    }

    public void toggle() {
        // toggle between [0...0.5] and [0.5...0]
        final float[] values = clipEqualsBounds() ? new float[] { 0f,0.5f } : new float[] { 0.5f,0f };
        ObjectAnimator.ofFloat(this,"imageCrop",values).start();
    }

    public void setimageCrop(float value) {
        // nothing to do if there's no drawable set
        final Drawable drawable = getDrawable();
        if (drawable == null) return;

        // nothing to do if no dimensions are kNown yet
        final int width = getWidth();
        final int height = getHeight();
        if (width <= 0 || height <= 0) return;

        // construct the clip bounds based on the supplied 'value' (which is assumed to be within the range [0...1])
        final int clipwidth = (int) (value * width);
        final int clipHeight = (int) (value * height);
        final int left = clipwidth / 2;
        final int top = clipHeight / 2;
        final int right = width - left;
        final int bottom = height - top;

        // set clipping bounds
        mClipRect.set(left,top,right,bottom);
        // schedule a draw pass for the new clipping bounds to take effect visually
        invalidate();
    }

}

真正的“魔法”是重写的onDraw()方法的附加行,其中给定的Canvas被剪切为由mClipRect定义的矩形区域.所有其他代码方法主要用于帮助计算剪辑边界,确定裁剪是否合理以及动画.

从Activity中使用它现在减少到以下内容

public class MainActivity extends Activity {

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.image_activity);

        final ClippingImageView img = (ClippingImageView) findViewById(R.id.img);
        img.setonClickListener(new OnClickListener() {
            @Override public void onClick(View v) {
                img.toggle();
            }
        });
    }
}

布局文件将指向我们的自定义ClippingImageView,如下所示:

<mh.so.img.ClippingImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/dog" />

为了让您了解视觉过渡:

相关文章

这篇“android轻量级无侵入式管理数据库自动升级组件怎么实现...
今天小编给大家分享一下Android实现自定义圆形进度条的常用方...
这篇文章主要讲解了“Android如何解决字符对齐问题”,文中的...
这篇文章主要介绍“Android岛屿数量算法怎么使用”的相关知识...
本篇内容主要讲解“Android如何开发MQTT协议的模型及通信”,...
本文小编为大家详细介绍“Android数据压缩的方法是什么”,内...