下面列出了android.graphics.Matrix#setTranslate ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Creates a View using the bitmap copy of <code>view</code>. If <code>view</code> is large,
* the copy will use a scaled bitmap of the given view.
*
* @param sceneRoot The ViewGroup in which the view copy will be displayed.
* @param view The view to create a copy of.
* @param parent The parent of view.
*/
public static View copyViewImage(ViewGroup sceneRoot, View view, View parent) {
Matrix matrix = new Matrix();
matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY());
view.transformMatrixToGlobal(matrix);
sceneRoot.transformMatrixToLocal(matrix);
RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight());
matrix.mapRect(bounds);
int left = Math.round(bounds.left);
int top = Math.round(bounds.top);
int right = Math.round(bounds.right);
int bottom = Math.round(bounds.bottom);
ImageView copy = new ImageView(view.getContext());
copy.setScaleType(ImageView.ScaleType.CENTER_CROP);
Bitmap bitmap = createViewBitmap(view, matrix, bounds, sceneRoot);
if (bitmap != null) {
copy.setImageBitmap(bitmap);
}
int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY);
copy.measure(widthSpec, heightSpec);
copy.layout(left, top, right, bottom);
return copy;
}
/**
* Tests that the {@link CutCornerTreatment} doesn't have rounding error which can lead to
* incorrectly calculating that the path is not convex.
*/
@Test
public void hasNoMatrixTransformationRoundingError() {
ShapePath cornerPath = new ShapePath();
cutCornerTreatment.getCornerPath(90, 1, cornerPath);
Matrix edgeTransform = new Matrix();
edgeTransform.setTranslate(DEFAULT_ANGLE, cornerPath.endY);
path.moveTo(WIDTH, 0);
path.lineTo(WIDTH, HEIGHT);
path.lineTo(0, DEFAULT_ANGLE);
cornerPath.applyToPath(new Matrix(), path);
shapePath.reset(0, 0);
shapePath.lineTo(WIDTH - DEFAULT_ANGLE, 0);
shapePath.applyToPath(edgeTransform, path);
assertTrue(path.isConvex());
}
/**
* Creates a View using the bitmap copy of <code>view</code>. If <code>view</code> is large,
* the copy will use a scaled bitmap of the given view.
*
* @param sceneRoot The ViewGroup in which the view copy will be displayed.
* @param view The view to create a copy of.
* @param parent The parent of view
*/
@NonNull
public static View copyViewImage(@NonNull ViewGroup sceneRoot, @NonNull View view, @NonNull View parent) {
Matrix matrix = new Matrix();
matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY());
ViewUtils.transformMatrixToGlobal(view, matrix);
ViewUtils.transformMatrixToLocal(sceneRoot, matrix);
RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight());
matrix.mapRect(bounds);
int left = Math.round(bounds.left);
int top = Math.round(bounds.top);
int right = Math.round(bounds.right);
int bottom = Math.round(bounds.bottom);
ImageView copy = new ImageView(view.getContext());
copy.setScaleType(ImageView.ScaleType.CENTER_CROP);
Bitmap bitmap = createViewBitmap(view, matrix, bounds);
if (bitmap != null) {
copy.setImageBitmap(bitmap);
}
int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY);
copy.measure(widthSpec, heightSpec);
copy.layout(left, top, right, bottom);
return copy;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mScaledBitmap = Bitmap.createScaledBitmap(mOriBitmap, w, h, true);
mRippleScaledBitmap = Bitmap.createScaledBitmap(mOriBitmap,
(int) (w * RIPPLE_SCALE_FACTOR), (int) (h * RIPPLE_SCALE_FACTOR), true);
int width1 = mScaledBitmap.getWidth();
int height1 = mScaledBitmap.getHeight();
int width2 = mRippleScaledBitmap.getWidth();
int height2 = mRippleScaledBitmap.getHeight();
mDisW = Math.abs(width1 - width2) / 2;
mDisH = Math.abs(height1 - height2) / 2;//算出两图中点相聚的距离,就是放大后需要矫正的位移距离
mOriBitmap.recycle();
mOriBitmap = null;
//这里的模式无所谓,因为在屏幕外看不到
mBitmapShader = new BitmapShader(mRippleScaledBitmap,
Shader.TileMode.MIRROR,//这里的模式无所谓,因为在屏幕外看不到
Shader.TileMode.MIRROR);
Matrix matrix = new Matrix();
matrix.setTranslate(-mDisW, -mDisH);
mBitmapShader.setLocalMatrix(matrix);
}
/**
* Return the round bitmap.
*
* @param src The source of bitmap.
* @param recycle True to recycle the source of bitmap, false otherwise.
* @param borderSize The size of border.
* @param borderColor The color of border.
* @return the round bitmap
*/
public static Bitmap toRound(final Bitmap src,
@IntRange(from = 0) int borderSize,
@ColorInt int borderColor,
final boolean recycle) {
if (isEmptyBitmap(src)) return null;
int width = src.getWidth();
int height = src.getHeight();
int size = Math.min(width, height);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig());
float center = size / 2f;
RectF rectF = new RectF(0, 0, width, height);
rectF.inset((width - size) / 2f, (height - size) / 2f);
Matrix matrix = new Matrix();
matrix.setTranslate(rectF.left, rectF.top);
if (width != height) {
matrix.preScale((float) size / width, (float) size / height);
}
BitmapShader shader = new BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
shader.setLocalMatrix(matrix);
paint.setShader(shader);
Canvas canvas = new Canvas(ret);
canvas.drawRoundRect(rectF, center, center, paint);
if (borderSize > 0) {
paint.setShader(null);
paint.setColor(borderColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(borderSize);
float radius = center - borderSize / 2f;
canvas.drawCircle(width / 2f, height / 2f, radius, paint);
}
if (recycle && !src.isRecycled() && ret != src) src.recycle();
return ret;
}
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
int topCenterView = mHeightCenter - mChildrenHeightMiddle;
int childTop = Math.max(0,child.getTop());
float offset = (-childTop + topCenterView)/ (float) mSpaceBetweenViews;
final Matrix matrix = t.getMatrix();
if (offset != 0) {
float absOffset = Math.abs(offset);
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
float px = child.getLeft() + (child.getWidth()) / 2;
float py = child.getTop() + (child.getHeight()) / 2;
if (mTranslatateEnbabled){
matrix.setTranslate(mTranslate * absOffset, 0);
}
if (offset > 0) {
matrix.preTranslate(-px,0);
matrix.postTranslate(px,0);
} else {
matrix.preTranslate(-px, -py);
matrix.postTranslate(px, py);
}
}
return true;
}
/**
* Calculate the effective crop rectangle for this preview viewport;
* assumes the preview is centered to the sensor and scaled to fit across one of the dimensions
* without skewing.
*
* <p>The preview size must be a subset of the active array size; the resulting
* rectangle will also be a subset of the active array rectangle.</p>
*
* <p>The unzoomed crop rectangle is calculated only.</p>
*
* @param activeArray active array dimensions, in sensor space
* @param previewSize size of the preview buffer render target, in pixels (not in sensor space)
* @return a rectangle which serves as the preview stream's effective crop region (unzoomed),
* in sensor space
*
* @throws NullPointerException
* if any of the args were {@code null}
* @throws IllegalArgumentException
* if {@code previewSize} is wider or taller than {@code activeArray}
*/
private static Rect getPreviewCropRectangleUnzoomed(Rect activeArray, Size previewSize) {
if (previewSize.getWidth() > activeArray.width()) {
throw new IllegalArgumentException("previewSize must not be wider than activeArray");
} else if (previewSize.getHeight() > activeArray.height()) {
throw new IllegalArgumentException("previewSize must not be taller than activeArray");
}
float aspectRatioArray = activeArray.width() * 1.0f / activeArray.height();
float aspectRatioPreview = previewSize.getWidth() * 1.0f / previewSize.getHeight();
float cropH, cropW;
if (Math.abs(aspectRatioPreview - aspectRatioArray) < ASPECT_RATIO_TOLERANCE) {
cropH = activeArray.height();
cropW = activeArray.width();
} else if (aspectRatioPreview < aspectRatioArray) {
// The new width must be smaller than the height, so scale the width by AR
cropH = activeArray.height();
cropW = cropH * aspectRatioPreview;
} else {
// The new height must be smaller (or equal) than the width, so scale the height by AR
cropW = activeArray.width();
cropH = cropW / aspectRatioPreview;
}
Matrix translateMatrix = new Matrix();
RectF cropRect = new RectF(/*left*/0, /*top*/0, cropW, cropH);
// Now center the crop rectangle so its center is in the center of the active array
translateMatrix.setTranslate(activeArray.exactCenterX(), activeArray.exactCenterY());
translateMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY());
translateMatrix.mapRect(/*inout*/cropRect);
// Round the rect corners towards the nearest integer values
return ParamsUtils.createRect(cropRect);
}
@Override
public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
Bitmap source = resource.get();
int size = Math.min(source.getWidth(), source.getHeight());
int width = (source.getWidth() - size) / 2;
int height = (source.getHeight() - size) / 2;
Bitmap bitmap = mBitmapPool.get(size, size, Bitmap.Config.ARGB_8888);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader =
new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
Matrix matrix = new Matrix();
matrix.setTranslate(-width, -height);
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return BitmapResource.obtain(bitmap, mBitmapPool);
}
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int width = (source.getWidth() - size) / 2;
int height = (source.getHeight() - size) / 2;
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader =
new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
Matrix matrix = new Matrix();
matrix.setTranslate(-width, -height);
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
source.recycle();
return bitmap;
}
private void setupScaleMatrix(int width, int height) {
if (!mHasFrame) {
// we have to ensure that we already have frame
// called and have width and height
return;
}
final Drawable drawable = getDrawable();
if (drawable == null) {
// we have to check if drawable is null because
// when not initialized at startup drawable we can
// rise NullPointerException
return;
}
Matrix matrix = mMatrix;
final int intrinsicWidth = drawable.getIntrinsicWidth();
final int intrinsicHeight = drawable.getIntrinsicHeight();
float factorWidth = width/(float) intrinsicWidth;
float factorHeight = height/(float) intrinsicHeight;
float factor = Math.max(factorHeight, factorWidth);
// there magic happen and can be adjusted to current
// needs
matrix.setTranslate(-intrinsicWidth/2.0f, 0);
matrix.postScale(factor, factor, 0, 0);
matrix.postTranslate(width/2.0f, 0);
setImageMatrix(matrix);
}
/**
* 图片圆形处理
* @param bitmap 待操作源图片
* @param borderSize 边框尺寸
* @param borderColor 边框颜色
* @return 圆形处理后的图片
*/
public static Bitmap round(final Bitmap bitmap, @IntRange(from = 0) final int borderSize, @ColorInt final int borderColor) {
if (isEmpty(bitmap)) return null;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int size = Math.min(width, height);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
float center = size / 2f;
RectF rectF = new RectF(0, 0, width, height);
rectF.inset((width - size) / 2f, (height - size) / 2f);
Matrix matrix = new Matrix();
matrix.setTranslate(rectF.left, rectF.top);
if (width != height) {
matrix.preScale((float) size / width, (float) size / height);
}
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
shader.setLocalMatrix(matrix);
paint.setShader(shader);
Bitmap newBitmap = Bitmap.createBitmap(width, height, bitmap.getConfig());
Canvas canvas = new Canvas(newBitmap);
canvas.drawRoundRect(rectF, center, center, paint);
if (borderSize > 0) {
paint.setShader(null);
paint.setColor(borderColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(borderSize);
float radius = center - borderSize / 2f;
canvas.drawCircle(width / 2f, height / 2f, radius, paint);
}
return newBitmap;
}
/**
* Used to fit a Bitmap nicely inside a View
*
* @param view
* @param bitmap
*/
@SuppressWarnings("deprecation")
public static void setBackground(View view, Bitmap bitmap) {
if (bitmap == null) {
view.setBackgroundResource(0);
return;
}
int vwidth = view.getWidth();
int vheight = view.getHeight();
int bwidth = bitmap.getWidth();
int bheight = bitmap.getHeight();
float scalex = (float)vwidth / bwidth;
float scaley = (float)vheight / bheight;
float scale = Math.max(scalex, scaley) * 1.0f;
Bitmap.Config config = Bitmap.Config.ARGB_8888;
Bitmap background = Bitmap.createBitmap(vwidth, vheight, config);
Canvas canvas = new Canvas(background);
Matrix matrix = new Matrix();
matrix.setTranslate(-bwidth / 2, -bheight / 2);
matrix.postScale(scale, scale);
matrix.postTranslate(vwidth / 2, vheight / 2);
canvas.drawBitmap(bitmap, matrix, null);
view.setBackgroundDrawable(new BitmapDrawable(view.getResources(), background));
}
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int width = (source.getWidth() - size) / 2;
int height = (source.getHeight() - size) / 2;
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader =
new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
Matrix matrix = new Matrix();
matrix.setTranslate(-width, -height);
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
source.recycle();
return bitmap;
}
/**
* 处理图片绘制位置,在width和height中显示居中
* @param width
* @param height
* @param matrix
*/
public static void setBitmapPosition(Bitmap bitmap, int width, int height, Matrix matrix) {
float left = (width - bitmap.getWidth()) / 2;
float top = (height - bitmap.getHeight()) / 2;
//缩放后
if (bitmap.getWidth() < width && bitmap.getHeight() < height) {
matrix.setTranslate(left, top);
}
else if (bitmap.getWidth() < width) {
matrix.setTranslate(left, 0);
}
else if (bitmap.getHeight() < height) {
matrix.setTranslate(0, top);
}
}
private void drawJet(Canvas canvas) {
Matrix matrix = mMatrix;
matrix.reset();
float dragPercent = mPercent;
float rotateAngle = 0;
// Check overdrag
if (dragPercent > 1.0f && !mEndOfRefreshing) {
rotateAngle = (dragPercent % 1) * 10;
dragPercent = 1.0f;
}
float offsetX = ((mScreenWidth * dragPercent) / 2) - mJetWidthCenter;
float offsetY = mJetTopOffset
+ (mParent.getTotalDragDistance() / 2)
* (1.0f - dragPercent)
- mJetHeightCenter;
if (isRefreshing) {
if (checkCurrentAnimationPart(AnimationPart.FIRST)) {
offsetY -= getAnimationPartValue(AnimationPart.FIRST);
} else if (checkCurrentAnimationPart(AnimationPart.SECOND)) {
offsetY -= getAnimationPartValue(AnimationPart.SECOND);
} else if (checkCurrentAnimationPart(AnimationPart.THIRD)) {
offsetY += getAnimationPartValue(AnimationPart.THIRD);
} else if (checkCurrentAnimationPart(AnimationPart.FOURTH)) {
offsetY += getAnimationPartValue(AnimationPart.FOURTH);
}
}
matrix.setTranslate(offsetX, offsetY);
if (dragPercent == 1.0f) {
matrix.preRotate(rotateAngle, mJetWidthCenter, mJetHeightCenter);
}
canvas.drawBitmap(mJet, matrix, null);
}
/**
* Calculate the actual/effective/reported normalized rectangle data from a metering
* rectangle.
*
* <p>If any of the rectangles are out-of-range of their intended bounding box,
* the {@link #RECTANGLE_EMPTY empty rectangle} is substituted instead
* (with a weight of {@code 0}).</p>
*
* <p>The metering rectangle is bound by the crop region (effective/reported respectively).
* The metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}.</p>
*
* <p>No parameters are mutated; returns the new metering data.</p>
*
* @param activeArraySize active array size of the sensor (e.g. max jpeg size)
* @param meteringRect the user-specified metering rectangle
* @param zoomData the calculated zoom data corresponding to this request
*
* @return the metering area, the reported/effective metering rectangles
*/
public static MeteringData convertMeteringRectangleToLegacy(
Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) {
Rect previewCrop = zoomData.previewCrop;
float scaleW = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
previewCrop.width();
float scaleH = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
previewCrop.height();
Matrix transform = new Matrix();
// Move the preview crop so that top,left is at (0,0), otherwise after scaling
// the corner bounds will be outside of [-1000, 1000]
transform.setTranslate(-previewCrop.left, -previewCrop.top);
// Scale into [0, 2000] range about the center of the preview
transform.postScale(scaleW, scaleH);
// Move so that top left of a typical rect is at [-1000, -1000]
transform.postTranslate(/*dx*/NORMALIZED_RECTANGLE_MIN, /*dy*/NORMALIZED_RECTANGLE_MIN);
/*
* Calculate the preview metering region (effective), and the camera1 api
* normalized metering region.
*/
Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect());
/*
* Try to intersect normalized area with [-1000, 1000] rectangle; otherwise
* it's completely out of range
*/
Rect normalizedIntersected = new Rect(normalizedRegionUnbounded);
Camera.Area meteringArea;
if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) {
Log.w(TAG,
"convertMeteringRectangleToLegacy - metering rectangle too small, " +
"no metering will be done");
normalizedIntersected.set(RECTANGLE_EMPTY);
meteringArea = new Camera.Area(RECTANGLE_EMPTY,
MeteringRectangle.METERING_WEIGHT_DONT_CARE);
} else {
meteringArea = new Camera.Area(normalizedIntersected,
meteringRect.getMeteringWeight());
}
/*
* Calculate effective preview metering region
*/
Rect previewMetering = meteringRect.getRect();
if (!previewMetering.intersect(previewCrop)) {
previewMetering.set(RECTANGLE_EMPTY);
}
/*
* Calculate effective reported metering region
* - Transform the calculated metering area back into active array space
* - Clip it to be a subset of the reported crop region
*/
Rect reportedMetering;
{
Camera.Area normalizedAreaUnbounded = new Camera.Area(
normalizedRegionUnbounded, meteringRect.getMeteringWeight());
WeightedRectangle reportedMeteringRect = convertCameraAreaToActiveArrayRectangle(
activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/false);
reportedMetering = reportedMeteringRect.rect;
}
if (DEBUG) {
Log.v(TAG, String.format(
"convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " +
"previewCrop = %s, meteringArea = %s, previewMetering = %s, " +
"reportedMetering = %s, normalizedRegionUnbounded = %s",
activeArray, meteringRect,
previewCrop, stringFromArea(meteringArea), previewMetering,
reportedMetering, normalizedRegionUnbounded));
}
return new MeteringData(meteringArea, previewMetering, reportedMetering);
}
private static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) {
Rect previewCrop = zoomData.previewCrop;
Rect reportedCrop = zoomData.reportedCrop;
float scaleW = previewCrop.width() * 1.0f /
(NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
float scaleH = previewCrop.height() * 1.0f /
(NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
/*
* Calculate the reported metering region from the non-intersected normalized region
* by scaling and translating back into active array-relative coordinates.
*/
Matrix transform = new Matrix();
// Move top left from (-1000, -1000) to (0, 0)
transform.setTranslate(/*dx*/NORMALIZED_RECTANGLE_MAX, /*dy*/NORMALIZED_RECTANGLE_MAX);
// Scale from [0, 2000] back into the preview rectangle
transform.postScale(scaleW, scaleH);
// Move the rect so that the [-1000,-1000] point ends up at the preview [left, top]
transform.postTranslate(previewCrop.left, previewCrop.top);
Rect cropToIntersectAgainst = usePreviewCrop ? previewCrop : reportedCrop;
// Now apply the transformation backwards to get the reported metering region
Rect reportedMetering = ParamsUtils.mapRect(transform, area.rect);
// Intersect it with the crop region, to avoid reporting out-of-bounds
// metering regions
if (!reportedMetering.intersect(cropToIntersectAgainst)) {
reportedMetering.set(RECTANGLE_EMPTY);
}
int weight = area.weight;
if (weight < MeteringRectangle.METERING_WEIGHT_MIN) {
Log.w(TAG,
"convertCameraAreaToMeteringRectangle - rectangle "
+ stringFromArea(area) + " has too small weight, clip to 0");
weight = 0;
}
return new WeightedRectangle(reportedMetering, area.weight);
}
protected void setMinWidth(RectF rect, Matrix matrix) {
// don't try to store the drawable dimensions by overriding
// setImageDrawable() since it is called in the ImageView's
// constructor and no referenced member of this object will
// have been initialized yet. So it's best to simply request
// the dimensions when they are required only.
RectF srcRect = new RectF(getDrawableRect());
if (rect == null || matrix == null) {
return;
}
float dw = srcRect.width();
float dh = srcRect.height();
float rw = rect.width();
float rh = rect.height();
if (dw < 1 || dh < 1 || rw < 1 || rh < 1) {
return;
}
RectF dstRect = new RectF();
matrix.setTranslate(dw * -.5f, dh * -.5f);
matrix.postRotate(rotation);
matrix.mapRect(dstRect, srcRect);
float xr = rw / dstRect.width();
float yr = rh / dstRect.height();
float scale;
if (scaleType == ImageView.ScaleType.CENTER) {
scale = 1f;
} else if (scaleType == ImageView.ScaleType.CENTER_INSIDE) {
scale = Math.min(xr, yr);
} else if (scaleType == ImageView.ScaleType.CENTER_CROP) {
scale = Math.max(xr, yr);
} else {
throw new UnsupportedOperationException();
}
matrix.postScale(scale, scale);
matrix.postTranslate(
Math.round(rect.left + rw * .5f),
Math.round(rect.top + rh * .5f));
matrix.mapRect(dstRect, srcRect);
minWidth = dstRect.width();
}
/**
* Sets the best movement type and scale.
*
* @return image scale.
*/
private float calculateTypeAndScale() {
movementType = MovingViewAnimator.AUTO_MOVE;
float scale = 1f;
float scaleByImage = Math.max(imageWidth / canvasWidth, imageHeight / canvasHeight);
Matrix m = new Matrix();
//Image is too small to performs any animation, needs a scale
if (offsetWidth == 0 && offsetHeight == 0) {
float sW = canvasWidth / imageWidth;
float sH = canvasHeight / imageHeight;
if (sW > sH) {
scale = Math.min(sW, maxRelativeSize);
m.setTranslate((canvasWidth - imageWidth * scale) / 2f, 0);
movementType = MovingViewAnimator.VERTICAL_MOVE;
} else if (sW < sH) {
scale = Math.min(sH, maxRelativeSize);
m.setTranslate(0, (canvasHeight - imageHeight * scale) / 2f);
movementType = MovingViewAnimator.HORIZONTAL_MOVE;
} else {
scale = Math.max(sW, maxRelativeSize);
movementType = (scale == sW) ? MovingViewAnimator.NONE_MOVE :
MovingViewAnimator.DIAGONAL_MOVE;
}
//Width too small to perform any horizontal animation, scale to width
} else if (offsetWidth == 0) {
scale = canvasWidth / imageWidth;
movementType = MovingViewAnimator.VERTICAL_MOVE;
//Height too small to perform any vertical animation, scale to height
} else if (offsetHeight == 0) {
scale = canvasHeight / imageHeight;
movementType = MovingViewAnimator.HORIZONTAL_MOVE;
//Enough size but too big, resize down
} else if (scaleByImage > maxRelativeSize) {
scale = maxRelativeSize / scaleByImage;
if(imageWidth * scale < canvasWidth || imageHeight * scale < canvasHeight) {
scale = Math.max(canvasWidth / imageWidth, canvasHeight / imageHeight);
}
}
m.preScale(scale, scale);
setImageMatrix(m);
return scale;
}
protected void setFocusToDrawingArea(Canvas canvas){
Matrix m = new Matrix();
m.setTranslate(drawableArea.left, drawableArea.top);
canvas.setMatrix(m);
}