Android 在 centerCropped 图像中创建一个圆孔
Posted
技术标签:
【中文标题】Android 在 centerCropped 图像中创建一个圆孔【英文标题】:Android Create a circle hole in a centerCropped image 【发布时间】:2016-05-07 08:06:23 【问题描述】:我又来了一个android大脑的想法!
我想在位图缩放为 centerCrop 的 imageView 中放置一个圆孔。我知道我需要在哪里放置圆孔(从左侧和底部以 dp 为单位)和孔半径。但不知道如何构建它!
我知道我可以使用 Porterduff 打洞,但你建议怎么做?
自定义位图 自定义可绘制/视图 自定义代码谢谢
下面的答案是我的带有孔的 CustomImage:
public class MyImageView extends ImageView
private AttributeSet attrs;
private float y;
private float x;
private float r;
private Paint paint;
private Rect mSrcRect;
private Rect mDestRect;
private Bitmap mBitmap;
private int alreadycalled = 0;
public MyImageView(Context context, AttributeSet attrs)
super(context, attrs);
this.attrs = attrs;
initView();
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this.attrs = attrs;
initView();
public MyImageView(Context context, float x, float y, float radius)
super(context);
this.x = x;
this.y = y;
this.r = radius;
Log.d("parameters", String.format("left:%s , right:%s, radius:%s", String.valueOf(x), String.valueOf(y), String.valueOf(r)));
initView();
private void initView()
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(10);
paint.setColor(0xff000000);
@Override
protected void onDraw(Canvas canvas)
alreadycalled++;
Log.d("alreadycalled", "called " + alreadycalled);
Drawable mDrawable = getDrawable();
if (mDrawable == null)
return; // couldn't resolve the URI
int dWidth = mDrawable.getIntrinsicWidth();
int dHeight = mDrawable.getIntrinsicHeight();
float scale = 1.0f;
scale = Math.max(getWidth() * 1.0f / dWidth, getHeight()
* 1.0f / dHeight);
int nWidth = (int) (dWidth * scale);
int nHeight = (int) (dHeight * scale);
int offsetLeft = (nWidth - getWidth()) / 2;
int offsetTop = (nHeight - getHeight()) / 2;
mBitmap = ((BitmapDrawable) mDrawable).getBitmap();
//custom mSrcRect mDestRect to achieve centerCrop
mSrcRect = new Rect(0, 0, dWidth, dWidth);
mDestRect = new Rect(-offsetLeft, -offsetTop, getWidth() + offsetLeft, getHeight() + offsetTop);
Log.d("src", mSrcRect.toString());
Log.d("dest", mDestRect.toString());
int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
paint.setColor(0xffffffff);
canvas.drawBitmap(mBitmap, mSrcRect, mDestRect, paint);
paint.setColor(0xffff0000);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
Log.d("position", String.format("%s , %s", String.valueOf(x), String.valueOf(y)));
canvas.drawCircle(x, y, r, paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
我用这些行以编程方式调用它:
BitmapDrawable bd=(BitmapDrawable) getResources().getDrawable(R.drawable.triangle_bas_accueil2);
MyImageView customImView = new MyImageView(getApplicationContext(), mX, mY, mRadius);
customImView.setImageDrawable(bd);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.BOTTOM;
customImView.setLayoutParams(params);
down_relative.addView(customImView);
但是onDraw()
方法被调用了两次(也许它需要),但这让我有两个洞,一个我可以更改参数但另一个仍然在同一个地方! MyImageView
的容器是 RelativeLayout
。
如果有人有想法? @小太阳?
【问题讨论】:
我觉得你最好自定义ImageView。 你有一个例子来帮助我开始解决方案吗? 【参考方案1】:这个只是CenterCrop,不能处理scaleType。而且这个代码可能有一些问题,因为我不擅长画布。
public class MyImageView extends ImageView
private final AttributeSet attrs;
private Paint paint;
private Rect mSrcRect;
private Rect mDestRect;
private Bitmap mBitmap;
public MyImageView(Context context, AttributeSet attrs)
super(context, attrs);
this.attrs = attrs;
initView();
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this.attrs = attrs;
initView();
private void initView()
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(10);
paint.setColor(0xff000000);
@Override
protected void onDraw(Canvas canvas)
// super.onDraw(canvas);
//create the drawable.Maybe you can cache it.
Drawable mDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.triangle_bas_accueil2);
if (mDrawable == null)
return; // couldn't resolve the URI
int dWidth = mDrawable.getIntrinsicWidth();
int dHeight = mDrawable.getIntrinsicHeight();
float scale = 1.0f;
scale = Math.max(getWidth() * 1.0f / dWidth, getHeight()
* 1.0f / dHeight);
int nWidth = (int) (dWidth*scale);
int nHeight = (int) (dHeight*scale);
int offsetLeft = (nWidth - getWidth())/2;
int offsetTop = (nHeight - getHeight())/2;
//cache mBitmap
mBitmap = mBitmap == null ? ((BitmapDrawable) mDrawable).getBitmap(): mBitmap;
//custom mSrcRect mDestRect to achieve centerCrop
mSrcRect = new Rect(0, 0, dWidth, dWidth);
mDestRect = new Rect(-offsetLeft, -offsetTop,getWidth()+offsetLeft, getHeight()+offsetTop);
int x = 250;int r = 100;
int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
paint.setColor(0xffffffff);
canvas.drawBitmap(mBitmap,mSrcRect,mDestRect,paint);
paint.setColor(0xff000000);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
canvas.drawCircle(x,x,r,paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
【讨论】:
感谢@tiny-sunlight 您的解决方案有效,但我无法保留我的ImageView
的ScaleType
property :/
我添加了我的代码@tiny-sunlight,因为我有一个自己出现的洞
我编辑了,因为你设置了layoutparams,所以重绘了。
我将此行修改为您的代码:mBitmap = mBitmap == null ? ((BitmapDrawable) mDrawable).getBitmap(): mBitmap;
。但即使我将 x 和 r 设置为 null,也会画一个洞。如何在创建 LayoutParams
的同时创建 ImageView
?
你是如何将 x 和 r 设置为 null 的?【参考方案2】:
自定义代码。循环遍历每个像素并更改 alpha。这是一些伪代码:
for (int y = 0; y < imageHeight; y++)
for (int x = 0; x < imageWidth; x++)
// Check if the current pixel is within the circle
if (dist(x, y, centerX, centerY) <= radius)
// Change the alpha
image.setPixelAlpha(x, y, 0);
【讨论】:
我认为这不是一个好主意,我的可绘制对象非常庞大,因此计算这样的结果可能需要 10 多秒,让 UI 进程完成 oit 太长了以上是关于Android 在 centerCropped 图像中创建一个圆孔的主要内容,如果未能解决你的问题,请参考以下文章
android:scaleType="centerCrop"
(Android - xml) Gridview 和 ImageView 缩放类型 centerCrop