我正在创建一个自定义ImageView,它将我的图像裁剪成六边形并添加边框 . 我想知道我的方法是否正确,或者我是以错误的方式做到这一点 . 有一堆自定义库已经可以做到这一点,但它们都没有开箱即用的形状我正在寻找 . 话虽如此,这是一个关于最佳实践的问题 .
您可以在gist中看到完整的类,但主要问题是这是最好的方法 . 这对我来说感觉不对,部分是因为一些神奇的数字意味着它可能会在某些设备上混乱 .
这是代码的内容:
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null || getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int dimensionPixelSize = getResources().getDimensionPixelSize(R.dimen.width); // (width and height of ImageView)
Bitmap drawnBitmap = drawCanvas(bitmap, dimensionPixelSize);
canvas.drawBitmap(drawnBitmap, 0, 0, null);
}
private Bitmap drawCanvas(Bitmap recycledBitmap, int width) {
final Bitmap bitmap = verifyRecycledBitmap(recycledBitmap, width);
final Bitmap output = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final Rect rect = new Rect(0, 0, width, width);
final int offset = (int) (width / (double) 2 * Math.tan(30 * Math.PI / (double) 180)); // (width / 2) * tan(30deg)
final int length = width - (2 * offset);
final Path path = new Path();
path.moveTo(width / 2, 0); // top
path.lineTo(0, offset); // left top
path.lineTo(0, offset + length); // left bottom
path.lineTo(width / 2, width); // bottom
path.lineTo(width, offset + length); // right bottom
path.lineTo(width, offset); // right top
path.close(); //back to top
Paint paint = new Paint();
paint.setStrokeWidth(4);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint); // draws the bitmap for the image
paint.setColor(Color.parseColor("white"));
paint.setStrokeWidth(4);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setPathEffect(new CornerPathEffect(10));
paint.setAntiAlias(true); // draws the border
canvas.drawPath(path, paint);
return output;
}
我正在查看一些iOS代码,他们能够将实际图像应用为掩码来实现此结果 . 在Android上有没有做类似的事情?
2 回答
我一直在寻找最好的方法 . 您的解决方案非常繁重,并且与动画效果不佳 . clipPath方法不使用抗锯齿,并且在某些版本的Android(4.0和4.1?)上不能与硬件加速一起使用 . 似乎最好的方法(动画友好,抗锯齿,非常干净和硬件加速)是使用Canvas图层:
您可以使用任何类型的蒙版,包括自定义形状和位图 . Carbon使用这种方法来实现小部件的圆角 .
即使它可能有效,但在这个实现上有一些不好的错误:
你在
onDraw
阶段分配了一些非常大的对象,这导致了糟糕的表现 . 最重要的是createBitmap
但你应该在onDraw
期间不惜一切代价避免new
. 在初始化期间预先分配所有必需的对象,并在onDraw
期间重新使用它们 .在
onSizeChanged
期间,您应该只设置一次path
. 避免每个OnDraw
上的所有路径如果您使用
Picasso
从互联网加载图像或者如果您想使用选择器,则依赖于BitmapDrawable
的使用,则此代码将无效 .您不需要分配第二个位图,而是使用
canvas.clipPath
来提高效率 .说所有的绘图效率更高的伪代码应该是: