【问题标题】:Adding borders for image rounded image android为图像圆形图像android添加边框
【发布时间】:2015-01-29 22:00:14
【问题描述】:

我有什么:: 我有一个 Imageview,我正在使用 picassso 将图像制作成一个圆圈

我该怎么做:: 我想使用我当前的实现为圆形图像添加黑色边框,如何在不使用第三方库的情况下实现这一目标

Picasso.with(this)
.load("http://i.imgur.com/DvpvklR.png")
.transform(new RoundedTransformation(50, 4))
.resize(100, 100)
.centerCrop().into(imageView1);

RoundedTransformation.java

// enables hardware accelerated rounded corners
// original idea here : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
public class RoundedTransformation implements com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin;  // dp

    // radius is corner radii in dp
    // margin is the board in dp
    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

    @Override
    public String key() {
        return "rounded";
    }
}

编辑

public class RoundedTransformation implements com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin;  // dp

    // radius is corner radii in dp
    // margin is the board in dp
    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {


        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        Paint paint1 = new Paint();      
        paint1.setColor(Color.RED);
        paint1.setStyle(Style.STROKE);
        paint1.setAntiAlias(true);
        paint1.setStrokeWidth(2);
        canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint1);


        return output;
    }

    @Override
    public String key() {
        return "rounded";
    }
}

【问题讨论】:

  • 我用的是这个版本...red borde 不像图片那么大,把 50 作为第一个参数图片没有四舍五入

标签: android picasso


【解决方案1】:

这是圆形和矩形形状的解决方案。此外,它不仅适用于 Picasso 的使用,而且适用于一般的 android Canvas-tasks。

我已经创建了非常庞大和详细的它们,只是为了让您了解流程,随意缩短。

但我想澄清许多人面临的一个主要问题。 在 android 中没有可能创建内部或外部边框 - 仅居中:

这就是为什么你会收到这样的边框元素被截断的原因:

所以只有一种方法可以重新计算边框的位置:在

  • circle 你必须将圆的半径减小一半的边界宽度
  • 矩形 你必须 1) 将边框线“向内”移动一半的边框宽度; 2) 将拐角半径减小一半边框宽度

这些操作将为您提供预期的结果:

如果您只需要边框代码 - 只选择通讯员 drawBorder() 方法。 这是一个带有两个图像的空片段的示例:

ViewsCroppingAndBorderingTestFragment.kt

class ViewsCroppingAndBorderingTestFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_test_views_cropping_and_bordering, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val urlCircle      = "https://images-na.ssl-images-amazon.com/images/I/71zLQIfmTlL._AC_SX466_.jpg"
        val urlRectRounded = "https://www.gardendesign.com/pictures/images/675x529Max/site_3/helianthus-yellow-flower-pixabay_11863.jpg"

        val ivCircle       = view.findViewById<ImageView>(R.id.ivCircle)
        val ivRectRounded  = view.findViewById<ImageView>(R.id.ivRectRounded)

        val trCircle       = CircleTransformation()
        val trRectRounded  = RectRoundedTransformation()

        Picasso.get().load(urlCircle).transform(trCircle).into(ivCircle)
        Picasso.get().load(urlRectRounded).transform(trRectRounded).into(ivRectRounded)
    }


    class CircleTransformation() : Transformation {

        override fun transform(source: Bitmap): Bitmap {

            val size = Math.min(source.width, source.height)
            val x = (source.width  - size) / 2
            val y = (source.height - size) / 2
            val w = size
            val h = size
            val squaredBitmap = Bitmap.createBitmap(source, x, y, w, h)

            if (squaredBitmap != source) {
                source.recycle()
            }

            val bitmap = Bitmap.createBitmap(w, h, source.config)

            val canvas = Canvas(bitmap)

//          >>  Draw original rectangle image
//            val paint = Paint(Paint.ANTI_ALIAS_FLAG)
//            canvas.drawBitmap(squaredBitmap, 0F, 0F, paint)

            val rImage = w / 2f

            cropWithCircle(squaredBitmap, canvas, rImage)
            squaredBitmap.recycle()


            drawBorder(canvas, rImage)


            return bitmap
        }

        private fun cropWithCircle(bitmapSource: Bitmap, canvas: Canvas, rImage: Float) {

            val shader = BitmapShader(bitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)

            val paint         = Paint(Paint.ANTI_ALIAS_FLAG)
            paint.shader      = shader
            paint.isAntiAlias = true

            val xCenter = rImage
            val yCenter = rImage

            canvas.drawCircle(xCenter, yCenter, rImage, paint)
        }

        private fun drawBorder(canvas: Canvas, rImage: Float) {

            val borderWidth = 30F

            val paintBorder         = Paint()
            paintBorder.strokeWidth = borderWidth
            paintBorder.style       = Paint.Style.STROKE
            paintBorder.color       = Color.GREEN
            paintBorder.isAntiAlias = true


            val cCenter = rImage
            val yCenter = rImage

            // ANDROID'S BORDER IS ALWAYS CENTERED.
            //  So have to reduce radius by half of border's width

            val rBorder = rImage - borderWidth / 2

            canvas.drawCircle(cCenter, yCenter, rBorder, paintBorder)
        }

        override fun key(): String {
            return "circle"
        }
    }

    class RectRoundedTransformation() : Transformation {

        override fun transform(source: Bitmap): Bitmap {

            val x = 0
            val y = 0
            val w = source.width
            val h = source.height
            val squaredBitmap = Bitmap.createBitmap(source, x, y, w, h)

            if (squaredBitmap != source) {
                source.recycle()
            }

            val bitmap = Bitmap.createBitmap(w, h, source.config)

            val canvas = Canvas(bitmap)

//          >>  Draw original rectangle image
//            val paint = Paint(Paint.ANTI_ALIAS_FLAG)
//            canvas.drawBitmap(squaredBitmap, 0F, 0F, paint)

            val rCorner = 80F

            cropCorners(squaredBitmap, canvas, rCorner)
            squaredBitmap.recycle()


            drawBorder(canvas, rCorner)


            return bitmap
        }

        private fun cropCorners(bitmapSource: Bitmap, canvas: Canvas, rCorner: Float) {

            val width  = canvas.width
            val height = canvas.height

            val maskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
            val maskCanvas = Canvas(maskBitmap)
            val maskPaint  = Paint(Paint.ANTI_ALIAS_FLAG)
            val maskRect   = RectF(0F, 0F, width.toFloat(), height.toFloat())

            // 1. draw base rect
            maskCanvas.drawRect(maskRect, maskPaint)

            // 2. cut off inner rounded rect, leave corners
            maskPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
            maskCanvas.drawRoundRect(maskRect, rCorner, rCorner, maskPaint)

            // 3. draw original rectangle image
            val paintSource = Paint(Paint.ANTI_ALIAS_FLAG)

            canvas.drawBitmap(bitmapSource, 0f, 0f, paintSource)

            // 4.cut off corners
            val paintCropped = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
            paintCropped!!.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

            canvas.drawBitmap(maskBitmap!!, 0f, 0f, paintCropped)
        }

        private fun drawBorder(canvas: Canvas, rCorner: Float) {

            val borderWidth  = 30F

            val paintBorder         = Paint()
            paintBorder.strokeWidth = borderWidth
            paintBorder.style       = Paint.Style.STROKE
            paintBorder.color       = Color.RED
            paintBorder.isAntiAlias = true


//            // ANDROID'S BORDER IS ALWAYS CENTERED.
//            //  So have to shift every side by half of border's width

            val rectLeft   = 0 + borderWidth / 2
            val rectTop    = 0 + borderWidth / 2
            val rectRight  = canvas.width.toFloat() - borderWidth / 2
            val rectBottom = canvas.height.toFloat() - borderWidth / 2
            val rectF      = RectF(rectLeft, rectTop, rectRight, rectBottom)

//            //  So have to corner reduce radius by half of border's width
            val rectRCorner = rCorner - borderWidth / 2

            canvas.drawRoundRect(rectF, rectRCorner, rectRCorner, paintBorder)
        }

        override fun key(): String {
            return "rectRounded"
        }
    }
}

fragment_test_views_cropping_and_bordering.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/temp"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:background="@android:color/darker_gray">


    <ImageView
        android:id="@+id/ivCircle"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_margin="10dp"/>


    <ImageView
        android:id="@+id/ivRectRounded"
        android:layout_width="200dp"
        android:layout_height="160dp"
        android:layout_margin="10dp"/>


</LinearLayout>

【讨论】:

  • 我不确定政治的画面是否适合这里。不能使用 use else 来显示代码的结果吗?
【解决方案2】:

BlackBelt 和 Devrath 的答案很棒。如果你正在寻找这个类的 Kotlin 版本,这里是:

class RoundedBorderTransform(private val radius: Int, private val margin: Int) : com.squareup.picasso.Transformation {

override fun transform(source: Bitmap?): Bitmap {
    val paint = Paint()
    paint.isAntiAlias = true
    paint.shader = BitmapShader(source!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)

    val output = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(output)
    canvas.drawCircle((source.width - margin) / 2f, (source.height - margin) / 2f, radius - 2f, paint)

    if (source != output) {
        source.recycle()
    }

    val borderPaint = Paint()
    borderPaint.color = Color.RED
    borderPaint.style = Paint.Style.STROKE
    borderPaint.isAntiAlias = true
    borderPaint.strokeWidth = 2f
    canvas.drawCircle((source.width - margin) / 2f, (source.height - margin) / 2f, radius - 2f, borderPaint)

    return output
}

override fun key(): String {
    return "roundedBorder"
}

}

【讨论】:

    【解决方案3】:

    最后的转换类,感谢blackbelt

    public class RoundedTransformation implements com.squareup.picasso.Transformation {
        private final int radius;
        private final int margin;  // dp
    
        // radius is corner radii in dp
        // margin is the board in dp
        public RoundedTransformation(final int radius, final int margin) {
            this.radius = radius;
            this.margin = margin;
        }
    
        @Override
        public Bitmap transform(final Bitmap source) {
    
    
            final Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    
            Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
            canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint);
    
            if (source != output) {
                source.recycle();
            }
    
            Paint paint1 = new Paint();      
            paint1.setColor(Color.RED);
            paint1.setStyle(Style.STROKE);
            paint1.setAntiAlias(true);
            paint1.setStrokeWidth(2);
            canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint1);
    
    
            return output;
        }
    
        @Override
        public String key() {
            return "rounded";
        }
    }
    

    【讨论】:

    • 它不适用于矩形图像。你需要先把它们弄成正方形。
    【解决方案4】:

    您可以将drawCircle 与另一个Paint object 一起使用。例如:

    Paint paint = new Paint();      
    paint.setColor(Color.RED);
    paint.setStyle(Style.STROKE);
    paint.setAntiAlias(true);
    paint.setStrokeWidth(2);
    canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint);
    

    另外,您可以使用drawCircle,而不是使用drawRoundRect 来绘制圆圈

    【讨论】:

    • 它几乎是正确的。你必须使用你的 paint1 而不是 paint,它是 radius-2 而不是 margin-2
    • [+1] 但在编辑中看到图像......如果我使用paint1......我的整个图像都消失了,但我可以看到小圆圈但不是在边框上而是在中心
    • 你把margin-2改成radius-2了吗?
    • 几乎完美......但它没有覆盖编辑中看到的顶部的一小部分......它可以完善吗?
    • 这可能是 RoundRect。你可以用 drawCircle 代替它吗?使用半径而不是半径 2。无论如何,现在只是调整的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 2016-05-07
    • 1970-01-01
    • 2015-04-26
    • 1970-01-01
    • 2022-11-23
    • 2023-03-18
    相关资源
    最近更新 更多