Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a rounded corners drawable

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?

like image 532
android developer Avatar asked Jan 01 '13 09:01

android developer


1 Answers

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.

like image 192
Paul Lammertsma Avatar answered Sep 19 '22 11:09

Paul Lammertsma