如何在不创建新位图的情况下具有圆形,中心裁剪的imageView?

android开发人员

注意:我知道关于此有很多问题和存储库,但似乎没有一个适合我尝试实现的目标。

背景

给定任意长宽比的位图,我希望将其设置为ImageView的内容(仅使用可绘制对象,而不扩展ImageView),以便内容将被中心裁剪,但仍为圆形。

所有这些都以最小的内存使用量完成,因为有时图像可能会很大。我不想为此创建一个全新的位图。内容已经在那里...

问题

我发现的所有解决方案都缺少我写的东西之一:有些不居中裁剪,有些假定图像是方形的,有些从给定的位图创建新的位图...

我尝试过的

除了尝试各种存储库之外,我还尝试了本教程,并尝试针对非正方形长宽比进行修复,但是失败了。

这是其代码,以防网站关闭:

public class RoundImage extends Drawable {
      private final Bitmap mBitmap;
      private final Paint mPaint;
      private final RectF mRectF;
      private final int mBitmapWidth;
      private final int mBitmapHeight;

      public RoundImage(Bitmap bitmap) {
            mBitmap = bitmap;
            mRectF = new RectF();
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint.setShader(shader);

            mBitmapWidth = mBitmap.getWidth();
            mBitmapHeight = mBitmap.getHeight();
      }

      @Override
      public void draw(Canvas canvas) {
            canvas.drawOval(mRectF, mPaint);
      }

      @Override
      protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            mRectF.set(bounds);
      }

      @Override
      public void setAlpha(int alpha) {
            if (mPaint.getAlpha() != alpha) {
                  mPaint.setAlpha(alpha);
                  invalidateSelf();
            }
      }

      @Override
      public void setColorFilter(ColorFilter cf) {
            mPaint.setColorFilter(cf);
      }

      @Override
      public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
      }

      @Override
      public int getIntrinsicWidth() {
            return mBitmapWidth;
      }

      @Override
      public int getIntrinsicHeight() {
            return mBitmapHeight;
      }

      public void setAntiAlias(boolean aa) {
            mPaint.setAntiAlias(aa);
            invalidateSelf();
      }

      @Override
      public void setFilterBitmap(boolean filter) {
            mPaint.setFilterBitmap(filter);
            invalidateSelf();
      }

      @Override
      public void setDither(boolean dither) {
            mPaint.setDither(dither);
            invalidateSelf();
      }

      public Bitmap getBitmap() {
            return mBitmap;
      }

}

我发现(这里)的一个很好的解决方案完全可以满足我的需要,除了它在ImageView本身中全部使用它,而不是创建可绘制对象。这意味着我无法将其设置为例如视图的背景。

问题

我该如何实现?


编辑:这是当前代码,并且我想添加边框,它也有以下代码:

public class SimpleRoundedDrawable extends BitmapDrawable {
    private final Path p = new Path();
    private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public SimpleRoundedDrawable(final Resources res, final Bitmap bitmap) {
        super(res, bitmap);
        mBorderPaint.setStyle(Paint.Style.STROKE);
    }

    public SimpleRoundedDrawable setBorder(float borderWidth, @ColorInt int borderColor) {
        mBorderPaint.setStrokeWidth(borderWidth);
        mBorderPaint.setColor(borderColor);
        invalidateSelf();
        return this;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        p.rewind();
        p.addCircle(bounds.width() / 2,
                bounds.height() / 2,
                Math.min(bounds.width(), bounds.height()) / 2,
                Path.Direction.CW);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.clipPath(p);
        super.draw(canvas);
        final float width = getBounds().width(), height = getBounds().height();
        canvas.drawCircle(width / 2, height / 2, Math.min(width, height) / 2, mBorderPaint);
    }
}

我希望这是应该真正起作用的方式。


编辑:似乎该解决方案仅适用于特定的Android版本,因为它不适用于Android 4.2.2。而是显示方形图像。

编辑:似乎上述解决方案也比使用BitmapShader(链接此处效率低得多知道如何在可绘制区域而不是自定义ImageView中使用它真是太好了

-这是以下解决方案的当前修改版本。我希望对某些人来说会很方便:

public class SimpleRoundedDrawable extends Drawable {
    final Paint mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG), mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Bitmap mBitmap;
    int mSide;
    float mRadius;

    public SimpleRoundedDrawable() {
        this(null);
    }

    public SimpleRoundedDrawable(Bitmap bitmap) {
        this(bitmap, 0, 0);
    }

    public SimpleRoundedDrawable(Bitmap bitmap, float width, @ColorInt int color) {
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBitmap = bitmap;
        mSide = mBitmap == null ? 0 : Math.min(bitmap.getWidth(), bitmap.getHeight());
        mBorderPaint.setStrokeWidth(width);
        mBorderPaint.setColor(color);
    }

    public SimpleRoundedDrawable setBitmap(final Bitmap bitmap) {
        mBitmap = bitmap;
        mSide = Math.min(bitmap.getWidth(), bitmap.getHeight());
        invalidateSelf();
        return this;
    }

    public SimpleRoundedDrawable setBorder(float width, @ColorInt int color) {
        mBorderPaint.setStrokeWidth(width);
        mBorderPaint.setColor(color);
        invalidateSelf();
        return this;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        if (mBitmap == null)
            return;
        Matrix matrix = new Matrix();
        RectF src = new RectF(0, 0, mSide, mSide);
        src.offset((mBitmap.getWidth() - mSide) / 2f, (mBitmap.getHeight() - mSide) / 2f);
        RectF dst = new RectF(bounds);
        final float strokeWidth = mBorderPaint.getStrokeWidth();
        if (strokeWidth > 0)
            dst.inset(strokeWidth, strokeWidth);
        matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
        Shader shader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        shader.setLocalMatrix(matrix);
        mMaskPaint.setShader(shader);
        matrix.mapRect(src);
        mRadius = src.width() / 2f;
    }

    @Override
    public void draw(Canvas canvas) {
        Rect b = getBounds();
        if (mBitmap != null)
            canvas.drawCircle(b.exactCenterX(), b.exactCenterY(), mRadius, mMaskPaint);
        final float strokeWidth = mBorderPaint.getStrokeWidth();
        if (strokeWidth > 0)
            canvas.drawCircle(b.exactCenterX(), b.exactCenterY(), mRadius + strokeWidth / 2, mBorderPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        mMaskPaint.setAlpha(alpha);
        invalidateSelf();
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        mMaskPaint.setColorFilter(cf);
        invalidateSelf();
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}
pskink

尝试此极简主义自定义Drawable并修改它以满足您的需求:

class D extends Drawable {
    Bitmap bitmap;
    Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    int side;
    float radius;

    public D(Bitmap wrappedBitmap) {
        bitmap = wrappedBitmap;
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setStrokeWidth(16);
        borderPaint.setColor(0xcc220088);
        side = Math.min(bitmap.getWidth(), bitmap.getHeight());
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        Matrix matrix = new Matrix();
        RectF src = new RectF(0, 0, side, side);
        src.offset((bitmap.getWidth() - side) / 2f, (bitmap.getHeight() - side) / 2f);
        RectF dst = new RectF(bounds);
        dst.inset(borderPaint.getStrokeWidth(), borderPaint.getStrokeWidth());
        matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);

        Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        shader.setLocalMatrix(matrix);
        maskPaint.setShader(shader);
        matrix.mapRect(src);
        radius = src.width() / 2f;
    }

    @Override
    public void draw(Canvas canvas) {
        Rect b = getBounds();
        canvas.drawCircle(b.exactCenterX(), b.exactCenterY(), radius, maskPaint);
        canvas.drawCircle(b.exactCenterX(), b.exactCenterY(), radius + borderPaint.getStrokeWidth() / 2, borderPaint);
    }

    @Override public void setAlpha(int alpha) {}
    @Override public void setColorFilter(ColorFilter cf) {}
    @Override public int getOpacity() {return PixelFormat.TRANSLUCENT;}
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不创建新对象的情况下返回对象类?

如何在ExoPlayer的PlayerView上(而不是在中心)具有类似的中心裁剪机制?

如何在不创建新数组的情况下减小数组大小?

Java如何在不递归的情况下创建具有相同类型子对象的对象?

如何在不注销Firebase的情况下创建新帐户?在iOS中(Swift)

如何在不创建新对象的情况下更改对象的参数?

如何在不转换为位图的情况下裁剪包含Y'(亮度)的byte []数组

熊猫如何在不创建新列的情况下进行外部联接

如何在不访问数据库的情况下创建具有延迟字段的Django模型实例?

如何在不创建新环境的情况下使用yml文件安装python库列表

如何在不创建新列表的情况下增加列表中的数字?

如何在不创建新的空实例的情况下获取类的实例

自适应卡:如何在不截断文本的情况下创建具有6列的表格?

如何在不创建数组的情况下获取新的String [0] .class?

如何在不添加新任务的情况下创建新的JFrame

如何在不创建新列表对象的情况下获取python列表中的行范围?

如何在不知道XAML尺寸的情况下以圆形方式裁剪图像

如何在不创建新表的情况下遍历MATLAB表

如何在中心裁剪图像

如何在不创建新列表的情况下访问python中的嵌套列表项?

如何在不创建新行的情况下显示 DIV 元素?

如何在不创建新数组的情况下获取 PDF 页面位置

如何在不创建新列表的情况下检索 IEnumerable 的基础列表?

如何在不破坏原始数组的情况下创建新的 JavaScript 数组?

如何在不创建新的小部件树分支的情况下重用相同的布局屏幕

如何在不更改新列表的情况下从现有列表创建列表?

如何在不创建新键的情况下访问 for 循环内的现有字典键?

如何在不创建新列的情况下增加数据框中的值?

如何在不导入每个类的情况下创建具有不同类的 python 包