Bitmap repeat + rounded corners

前端 未结 2 1038
野性不改
野性不改 2020-12-19 06:14

I am trying to create rectangle with rounded corners and background as repeated bitmaps. I am writing like this, but getting bitmaps in the corners.

Could anyone hel

相关标签:
2条回答
  • 2020-12-19 06:53

    As I understand the goal: have a tiled background image with some curved corners. tiled and curved

    It's not quite pixel perfect, but its as close as I can get.

    first, here are some layouts I'm using to draw that button

    the_button.xml

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/wrapper_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@drawable/bg_curved_tiled"
        android:padding="20dp" >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Some Text" />
    
    </FrameLayout>
    

    and thats using this as its background

    bg_curved_tiled.xml

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <item android:id="@id/layer_needs_rounding">
            <bitmap
                android:src="@drawable/patch"
                android:tileMode="repeat" />
        </item>    
        <item>
            <shape
                android:shape="rectangle"
                android:useLevel="false" >
                <stroke
                    android:width="3dp"
                    android:color="#666666" />
    
                <solid android:color="@null" />
    
                <corners
                    android:bottomLeftRadius="@dimen/radius_corner_default"
                    android:bottomRightRadius="@dimen/radius_corner_default"
                    android:radius="@dimen/radius_corner_default"
                    android:topLeftRadius="@dimen/radius_corner_default"
                    android:topRightRadius="@dimen/radius_corner_default" />
            </shape>
        </item>
    
    </layer-list>
    

    At this point, you have an image that looks like this

    enter image description here

    As you can see, the tiled bitmap sticks out at the corners past the curved shape thats overlayed on top of it.

    So now you need a function that rounds the corners of a bitmap...i got this one off somewhere else on stackoverflow

     public static Bitmap createRoundedCornerBitmap(Context context,
             Bitmap input, float roundPx, boolean squareTL, boolean squareTR,
             boolean squareBR, boolean squareBL) {
          if (input == null) {
             return null;
          }
    
          final int w = input.getWidth(), h = input.getHeight();
          Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
          Canvas canvas = new Canvas(output);
    
          final int color = 0xff424242;
          final Paint paint = new Paint();
          final Rect rect = new Rect(0, 0, w, h);
          final RectF rectF = new RectF(rect);                   
    
          paint.setAntiAlias(true);
          canvas.drawARGB(0, 0, 0, 0);
          paint.setColor(color);
          canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
    
          // draw rectangles over the corners we want to be square
          if (squareTL) {
             canvas.drawRect(0, 0, w / 2, h / 2, paint);
          }
          if (squareTR) {
             canvas.drawRect(w / 2, 0, w, h / 2, paint);
          }
          if (squareBL) {
             canvas.drawRect(0, h / 2, w / 2, h, paint);
          }
          if (squareBR) {
             canvas.drawRect(w / 2, h / 2, w, h, paint);
          }
    
          paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
          canvas.drawBitmap(input, 0, 0, paint);
    
          return output;
       }
    

    Almost there! I hate this part - I haven't found any better way to get the Bitmap object that has the actual tiled bitmap in it. For example, BitmapDrawable.getBitmap just gives you the individual patch bitmap, not the tiled repeated patch canvas...bummer. So instead, I'm getting the drawing cache of the view. You need to make sure the view has been fully initialized first (height and width have been figured out and tiled appropriately), so post to the view and do processing there.

    private void shaveOffCorners(final ViewGroup view) {          
          view.post(new Runnable() {
    
             @Override
             public void run() {
                // make all child views invisible before scraping the drawing cache
                SparseIntArray viewStates = new SparseIntArray();
                for(int index = 0; index < view.getChildCount(); ++index) {
                   View child = view.getChildAt(index);
                   viewStates.put(index, child.getVisibility());
                   child.setVisibility(View.INVISIBLE);
                }
    
                view.buildDrawingCache();
                // this is the exact bitmap that is currently rendered to screen.  hence, we wanted to 
                // hide all the children so that they don't permanently become part of the background
                final Bitmap rounded = view.getDrawingCache();
    
                // restore actual visibility states after getting the drawing cache
                for(int index = 0; index < view.getChildCount(); ++index) {
                   View child = view.getChildAt(index);
                   child.setVisibility(viewStates.get(index));
                }
    
                view.setBackgroundDrawable(new BitmapDrawable(
                      getResources(), 
                      MyImageUtil.createRoundedCornerBitmap(
                            view.getContext(), 
                            rounded, 
                            getResources().getDimensionPixelSize(R.dimen.radius_corner_default), 
                            false, true, true, false)));
             }
          });
       }
    

    And that's how I did it, hope that helps!

    If anyone knows a less horrible way to accomplish this, please share. Also if anyone knows how to get the tiled bitmap other than scraping the drawing cache, that'd be helpful too - the whole hiding and restoring child views is a little janky.

    0 讨论(0)
  • 2020-12-19 06:56

    I found this post by Romain Guy that's a much easier way to round corners on a tiled bitmap. Here's the short answer:

    class CurvedAndTiled extends Drawable {
    
        private final float mCornerRadius;
        private final RectF mRect = new RectF();
        private final BitmapShader mBitmapShader;
        private final Paint mTilePaint;        
    
        CurvedAndTiled(
                Bitmap bitmap, 
                float cornerRadius) {
            mCornerRadius = cornerRadius;
    
            mBitmapShader = new BitmapShader(bitmap,
                    Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
    
            mTilePaint = new Paint();
            mTilePaint.setAntiAlias(true);
            mTilePaint.setShader(mBitmapShader);             
        }
    
        @Override
        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            mRect.set(0, 0, bounds.width(), bounds.height());
        }
    
        @Override
        public void draw(Canvas canvas) {
            canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mTilePaint);           
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    
        @Override
        public void setAlpha(int alpha) {
            mTilePaint.setAlpha(alpha);
        }
    
        @Override
        public void setColorFilter(ColorFilter cf) {
            mTilePaint.setColorFilter(cf);
        }       
    }
    

    You just set your view's background drawable to be one of these guys and you're good to go.

    0 讨论(0)
提交回复
热议问题