所以我有一个使用Matrix的ImageView来缩放我正在显示的位图。我可以双击缩放到全尺寸,我的ScaleAnimation处理动画放大,这一切都很好。
现在我想再次双击缩小,但是当我使用ScaleAnimation为其设置动画时,ImageView不会绘制图像的新曝光区域(因为当前视口缩小),而是看到可见部分我已经尝试使用ViewGroup.setClipChildren(false),但是这只留下了前一帧中最后绘制的工件 - 导致了一种幻觉伸缩效果,但不是我所追求的。
我知道有许多与缩放相关的问题,但没有一个涵盖我的情况 - 特别是动画缩小操作。我确实有机制工作 - 即除了缩小动画,双击放大和缩小工作正常。
有什么建议吗?
答案 0 :(得分:5)
最后我决定停止使用Android提供的Animation类,因为ScaleAnimation将一个比例应用到整个ImageView,然后与ImageView的图像Matrix的比例相结合,使其工作变得复杂(一边)从剪辑问题我有)。 因为我真正需要的是为ImageView的Matrix所做的更改设置动画,所以我实现了OnDoubleTapListener(在这篇文章的最后 - 我将它作为“练习给读者”留下来添加缺少的字段和方法 - 我使用了几个PointF和Matrix字段,以避免过多的垃圾创建)。基本上,动画本身是通过使用View.post来发布一个Runnable来实现的,该Runnable会逐步改变ImageView的图像矩阵:
public boolean onDoubleTap(MotionEvent e) {
final float x = e.getX();
final float y = e.getY();
matrix.reset();
matrix.set(imageView.getImageMatrix());
matrix.getValues(matrixValues);
matrix.invert(inverseMatrix);
doubleTapImagePoint[0] = x;
doubleTapImagePoint[1] = y;
inverseMatrix.mapPoints(doubleTapImagePoint);
final float scale = matrixValues[Matrix.MSCALE_X];
final float targetScale = scale < 1.0f ? 1.0f : calculateFitToScreenScale();
final float finalX;
final float finalY;
// assumption: if targetScale is less than 1, we're zooming out to fit the screen
if (targetScale < 1.0f) {
// scaling the image to fit the screen, we want the resulting image to be centred. We need to take
// into account the shift that is applied to zoom on the tapped point, easiest way is to reuse
// the transformation matrix.
RectF imageBounds = new RectF(imageView.getDrawable().getBounds());
// set up matrix for target
matrix.reset();
matrix.postTranslate(-doubleTapImagePoint[0], -doubleTapImagePoint[1]);
matrix.postScale(targetScale, targetScale);
matrix.mapRect(imageBounds);
finalX = ((imageView.getWidth() - imageBounds.width()) / 2.0f) - imageBounds.left;
finalY = ((imageView.getHeight() - imageBounds.height()) / 2.0f) - imageBounds.top;
}
// else zoom around the double-tap point
else {
finalX = x;
finalY = y;
}
final Interpolator interpolator = new AccelerateDecelerateInterpolator();
final long startTime = System.currentTimeMillis();
final long duration = 800;
imageView.post(new Runnable() {
@Override
public void run() {
float t = (float) (System.currentTimeMillis() - startTime) / duration;
t = t > 1.0f ? 1.0f : t;
float interpolatedRatio = interpolator.getInterpolation(t);
float tempScale = scale + interpolatedRatio * (targetScale - scale);
float tempX = x + interpolatedRatio * (finalX - x);
float tempY = y + interpolatedRatio * (finalY - y);
matrix.reset();
// translate initialPoint to 0,0 before applying zoom
matrix.postTranslate(-doubleTapImagePoint[0], -doubleTapImagePoint[1]);
// zoom
matrix.postScale(tempScale, tempScale);
// translate back to equivalent point
matrix.postTranslate(tempX, tempY);
imageView.setImageMatrix(matrix);
if (t < 1f) {
imageView.post(this);
}
}
});
return false;
}