Using a rounded corners drawable

2019-01-30 20:37发布

There is a nice post made by the popular Google developer Romain Guy that shows how to use a rounded corners drawable (called "StreamDrawable" in his code ) on a view efficiently.

The sample itself works very well on my Galaxy S3 when in portrait mode, but I have a few issues with it:

  1. if the screen is small (for example on qvga screens), the shown images get cropped.

  2. if I have an input bitmap that is too small than how I wish to show it, the output image has its edges smeared. Even on the Galaxy S3, when you run the sample code and it's on landscape, it looks awful:

    enter image description here

  3. I'm still not sure about it (since I use a workaround of scaling the image for using the sample code), but it think that even this solution is a bit slow when being used in a listView. Maybe there is a renderscript solution for this?

It doesn't matter if I use setImageDrawable or setBackgroundDrawable. It must be something in the drawable itself.

I've tried to play with the variables and the bitmapShader, but nothing worked. Sadly TileMode doesn't have a value for just stretching the image, only tiling it in some way.

As a workaround I can create a new scaled bitmap, but it's just a workaround. Surely there is a better way which will also not use more memory than it should.

How do I fix those issues and use this great code?

3条回答
孤傲高冷的网名
2楼-- · 2019-01-30 20:55

There underlying problem is that the BitmapShader's TileMode doesn't have a scaling option. You'll note in the source that it's been set to Shader.TileMode.CLAMP, and the docs describe that as:

replicate the edge color if the shader draws outside of its original bounds

To work around this, there are three solutions:

  1. Constrain the size of the view in which the drawable is used to the size of the bitmap.
  2. Constrain the drawing region; for instance, change:

    int width = bounds.width() - mMargin;
    int height = bounds.height() - mMargin;
    mRect.set(mMargin, mMargin, width, height);
    

    To:

    int width = Math.min(mBitmap.getWidth(), bounds.width()) - mMargin;
    int height = Math.min(mBitmap.getHeight(), bounds.height()) - mMargin;
    mRect.set(mMargin, mMargin, width, height);
    
  3. Scale the bitmap to the size of the drawable. I've moved creating the shader into onBoundsChange() and have opted to create a new bitmap from here:

    bitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
    mBitmapShader = new BitmapShader(bitmap,
            Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    

    Note that this a potentially slow operation and will be running on the main thread. You might want to carefully consider how you want to implement it before you go for this last solution.

查看更多
老娘就宠你
3楼-- · 2019-01-30 21:02

I think that the solution that is presented on this website works well.

unlike other solutions, it doesn't cause memory leaks, even though it is based on Romain Guy's solution.

EDIT: now on the support library, you can also use RoundedBitmapDrawable (using RoundedBitmapDrawableFactory ) .

查看更多
手持菜刀,她持情操
4楼-- · 2019-01-30 21:11

I had some size issues with this code, and I solved it.

Maybe this will help you, too:

1) in the constructor store the bitmap in a local variable (e.g. private Bitmap bmp;)

2) override two more methods:

@Override
    public int getIntrinsicWidth() {
    return bmp.getWidth();
}

@Override
    public int getIntrinsicHeight() {
    return bmp.getHeight();
}

Best regards, DaRolla

查看更多
登录 后发表回答