这是我称之为的解决方案:
imageView 解决方案
它从 ImageView 扩展而来,并覆盖其 onDraw 方法。它工作正常,但它有一些缺点,如果有人可以改进,我会很高兴:
- 它不对位图进行操作。
- 我不知道如何对我扩展的 imageView 执行特殊操作,例如反射、圆角等...
- 它不遵循我编写的建议 API,以节省内存使用。
代码在这里:
public class MosaicView extends ImageView {
private ArrayList<Bitmap> mImages;
private ArrayList<Rect> mImagesRects;
private final Paint mPaint = new Paint();
private Rect mTopLeftRect, mLeftRect, mWholeRect, mRightRect, mTopRightRect, mBottomLeftRect, mBottomRightRect;
private boolean mIsDirty = false;
private final Rect mCenterCropRect = new Rect();
public MosaicView(final Context context) {
super(context);
}
public MosaicView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public MosaicView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
public void setImages(final ArrayList<Bitmap> images) {
this.mImages = images;
if (mImages == null)
mImagesRects = null;
else {
mImagesRects = new ArrayList<Rect>(images.size());
for (final Bitmap bitmap : images)
mImagesRects.add(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()));
}
mIsDirty = true;
invalidate();
}
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
final int width = getWidth();
final int height = getHeight();
if (mIsDirty) {
mIsDirty = false;
mTopLeftRect = new Rect(0, 0, width / 2, height / 2);
mLeftRect = new Rect(0, 0, width / 2, height);
mWholeRect = new Rect(0, 0, width, height);
mRightRect = new Rect(width / 2, 0, width, height);
mTopRightRect = new Rect(width / 2, 0, width, height / 2);
mBottomLeftRect = new Rect(0, height / 2, width / 2, height);
mBottomRightRect = new Rect(width / 2, height / 2, width, height);
}
if (mImages == null)
return;
Bitmap b;
switch (mImages.size()) {
case 0:
break;
case 1:
b = mImages.get(0);
getCenterCropRect(mImagesRects.get(0), mWholeRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mWholeRect, mPaint);
break;
case 2:
b = mImages.get(0);
getCenterCropRect(mImagesRects.get(0), mLeftRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mLeftRect, mPaint);
b = mImages.get(1);
getCenterCropRect(mImagesRects.get(1), mRightRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mRightRect, mPaint);
break;
case 3:
b = mImages.get(0);
getCenterCropRect(mImagesRects.get(0), mLeftRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mLeftRect, mPaint);
b = mImages.get(1);
getCenterCropRect(mImagesRects.get(1), mTopRightRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mTopRightRect, mPaint);
b = mImages.get(2);
getCenterCropRect(mImagesRects.get(2), mBottomRightRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mBottomRightRect, mPaint);
break;
default:
case 4:
b = mImages.get(0);
getCenterCropRect(mImagesRects.get(0), mTopLeftRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mTopLeftRect, mPaint);
b = mImages.get(1);
getCenterCropRect(mImagesRects.get(1), mTopRightRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mTopRightRect, mPaint);
b = mImages.get(2);
getCenterCropRect(mImagesRects.get(2), mBottomRightRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mBottomRightRect, mPaint);
b = mImages.get(3);
getCenterCropRect(mImagesRects.get(3), mBottomLeftRect, mCenterCropRect);
canvas.drawBitmap(b, mCenterCropRect, mBottomLeftRect, mPaint);
break;
}
}
private void getCenterCropRect(final Rect srcRect, final Rect limitRect, final Rect dstRect) {
final float scaleX = (float) srcRect.width() / limitRect.width();
final float scaleY = (float) srcRect.height() / limitRect.height();
if (scaleX >= scaleY) {
// image will fit in height, and truncate from the width
dstRect.top = srcRect.top;
dstRect.bottom = srcRect.bottom;
final float newWidth = limitRect.width() * scaleY;
dstRect.left = (int) (srcRect.width() / 2 - newWidth / 2);
dstRect.right = (int) (srcRect.width() / 2 + newWidth / 2);
} else {
// image will fit in width, and truncate from the height
dstRect.left = srcRect.left;
dstRect.right = srcRect.right;
final float newHeight = limitRect.height() * scaleX;
dstRect.top = (int) (srcRect.height() / 2 - newHeight / 2);
dstRect.bottom = (int) (srcRect.height() / 2 + newHeight / 2);
}
}
}