将自定义遮罩应用于 ImageView
Apply custom mask to an ImageView
我想像这样调整我的 ImageView:
我尝试了不同的方法,例如通过 xml 使用形状或使用 OutlineProvider
。对于这种情况,两者都没有真正起作用。
现在我写了一个 CustomImageView,它画了一个像这样的圆:
class HeaderImageView : AppCompatImageView {
@SuppressLint("CanvasSize")
override fun onDraw(canvas: Canvas) {
val halfWidth = (canvas.width / 2).toFloat()
val radius = height.toFloat()
val path = Path().apply {
addCircle(halfWidth, 0f, radius, Path.Direction.CCW)
}
canvas.clipPath(path)
super.onDraw(canvas)
}
}
如何操作路径以获得我想要的结果?
谢谢!
编辑:
需要说明的是,我有一张图片我想要 "manipulate",而不是颜色。
已添加 xml:
<.HeaderImageView
android:layout_width="match_parent"
android:layout_height="230dp"
android:fitsSystemWindows="false"
android:scaleType="centerCrop"
android:src="@drawable/bg"
app:layout_collapseMode="parallax" />
我正在使用路径绘制圆形。
并使用某种机制使图像适合圆形部分。
我用Path做了。检查一下。
public class RoundedView extends AppCompatImageView {
private Bitmap mBitmap;
Path mPath;
float width, height, offset;
float percent = 0.37f;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public RoundedView(Context context) {
super(context);
}
public RoundedView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RoundedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.RoundedView);
percent = arr.getFloat(R.styleable.RoundedView_roundPercent, 0.37f);
arr.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
if (mPath != null) {
canvas.drawPath(mPath, mPaint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
offset = w / 2f;
change();
}
private void change() {
float roundness = percent * height;
Drawable d = getDrawable();
if (d != null) {
mBitmap = drawableToBitmap(d);
mBitmap = Bitmap.createScaledBitmap(mBitmap, (int) width, (int) height, false);
final Shader shader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mPath = new Path();
mPath.moveTo(0, 0);
mPath.lineTo(width, 0);
mPath.lineTo(width, height - roundness);
mPath.quadTo(offset, height + roundness, 0, height - roundness);
mPath.close();
}
}
@Override
public void setImageDrawable(@Nullable Drawable drawable) {
super.setImageDrawable(drawable);
change();
}
public Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = null;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
感谢您的回答,这一定会对其他用户有所帮助。
不幸的是,我不得不帮助自己获得想要的结果。
这是我的最终解决方案,它将四边形贝塞尔曲线应用于 ImageView。
class HeaderImageView : AppCompatImageView {
constructor(context: Context?) : super(context) {
init()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
lateinit var paint: Paint
private fun init() {
paint = Paint()
paint.color = Color.WHITE
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)
paint.style = Paint.Style.FILL
}
@SuppressLint("CanvasSize")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val fHeight = canvas.height.toFloat()
val startEndHeight = canvas.height / 1.18f
val fWidth = canvas.width.toFloat()
val halfWidth = (fWidth / 2)
val path = Path()
//X = Left side, Y = close to bottom
val ptStart = PointF(0f, startEndHeight)
//X = Middle, Y = Bottom
val ptMiddle = PointF(halfWidth, fHeight + 95)
// X = Right Side, Y = close to bottom
val ptEnd = PointF(fWidth, startEndHeight)
path.moveTo(ptStart.x, ptStart.y)
path.quadTo(ptMiddle.x, ptMiddle.y, ptEnd.x, ptEnd.y)
path.lineTo(fWidth, fHeight)
path.lineTo(0f, fHeight)
path.close()
canvas.drawPath(path, paint)
}
}
我想像这样调整我的 ImageView:
我尝试了不同的方法,例如通过 xml 使用形状或使用 OutlineProvider
。对于这种情况,两者都没有真正起作用。
现在我写了一个 CustomImageView,它画了一个像这样的圆:
class HeaderImageView : AppCompatImageView {
@SuppressLint("CanvasSize")
override fun onDraw(canvas: Canvas) {
val halfWidth = (canvas.width / 2).toFloat()
val radius = height.toFloat()
val path = Path().apply {
addCircle(halfWidth, 0f, radius, Path.Direction.CCW)
}
canvas.clipPath(path)
super.onDraw(canvas)
}
}
如何操作路径以获得我想要的结果?
谢谢!
编辑:
需要说明的是,我有一张图片我想要 "manipulate",而不是颜色。
已添加 xml:
<.HeaderImageView
android:layout_width="match_parent"
android:layout_height="230dp"
android:fitsSystemWindows="false"
android:scaleType="centerCrop"
android:src="@drawable/bg"
app:layout_collapseMode="parallax" />
我正在使用路径绘制圆形。 并使用某种机制使图像适合圆形部分。
我用Path做了。检查一下。
public class RoundedView extends AppCompatImageView {
private Bitmap mBitmap;
Path mPath;
float width, height, offset;
float percent = 0.37f;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public RoundedView(Context context) {
super(context);
}
public RoundedView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RoundedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.RoundedView);
percent = arr.getFloat(R.styleable.RoundedView_roundPercent, 0.37f);
arr.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
if (mPath != null) {
canvas.drawPath(mPath, mPaint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
offset = w / 2f;
change();
}
private void change() {
float roundness = percent * height;
Drawable d = getDrawable();
if (d != null) {
mBitmap = drawableToBitmap(d);
mBitmap = Bitmap.createScaledBitmap(mBitmap, (int) width, (int) height, false);
final Shader shader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mPath = new Path();
mPath.moveTo(0, 0);
mPath.lineTo(width, 0);
mPath.lineTo(width, height - roundness);
mPath.quadTo(offset, height + roundness, 0, height - roundness);
mPath.close();
}
}
@Override
public void setImageDrawable(@Nullable Drawable drawable) {
super.setImageDrawable(drawable);
change();
}
public Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = null;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
感谢您的回答,这一定会对其他用户有所帮助。 不幸的是,我不得不帮助自己获得想要的结果。
这是我的最终解决方案,它将四边形贝塞尔曲线应用于 ImageView。
class HeaderImageView : AppCompatImageView {
constructor(context: Context?) : super(context) {
init()
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
lateinit var paint: Paint
private fun init() {
paint = Paint()
paint.color = Color.WHITE
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)
paint.style = Paint.Style.FILL
}
@SuppressLint("CanvasSize")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val fHeight = canvas.height.toFloat()
val startEndHeight = canvas.height / 1.18f
val fWidth = canvas.width.toFloat()
val halfWidth = (fWidth / 2)
val path = Path()
//X = Left side, Y = close to bottom
val ptStart = PointF(0f, startEndHeight)
//X = Middle, Y = Bottom
val ptMiddle = PointF(halfWidth, fHeight + 95)
// X = Right Side, Y = close to bottom
val ptEnd = PointF(fWidth, startEndHeight)
path.moveTo(ptStart.x, ptStart.y)
path.quadTo(ptMiddle.x, ptMiddle.y, ptEnd.x, ptEnd.y)
path.lineTo(fWidth, fHeight)
path.lineTo(0f, fHeight)
path.close()
canvas.drawPath(path, paint)
}
}