gpt4 book ai didi

android - 如何将矩阵动画化为 "crop-out"图像?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:58:45 29 4
gpt4 key购买 nike

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

例如在下面的屏幕截图中,用户最初只能看到小狗的部分。但在用户点击图像后,整只小狗就会显示出来。在第一个后面褪色的图像显示了动画的结果。

screenshot

最初,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)。但是,如果我在动画期间线性缩放 Matrix,则 View 在动画期间会被挤压。最终结果看起来不错,但在动画过程中图像看起来很丑。

最佳答案

我知道你(和其他答案)一直在尝试使用矩阵操作来解决这个问题,但我想提出一种与你的问题中概述的视觉效果相同的不同方法。

为什么不使用矩阵来操作图像的可见区域( View ),为什么不根据裁剪定义这个可见区域?这是一个很容易解决的问题:我们需要做的就是定义可见矩形,并简单地忽略落在其边界之外的任何内容。如果我们随后为这些边界设置动画,视觉效果就像裁剪边界按比例放大和缩小一样。

幸运的是,一个Canvas支持通过各种 clip*() 方法进行裁剪来帮助我们解决这个问题。动画裁剪边界很容易,可以用与您自己的代码 fragment 类似的方式完成。

如果你把所有东西放在一个普通 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" />

让您了解视觉转换:

enter image description here

关于android - 如何将矩阵动画化为 "crop-out"图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18305219/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com