Search code examples
androidbitmapdrawableshadertiling

Android: Drawing tiled bitmaps with bottom or some other alignments similar to css background-position


I want to set a background of a View with a tiled bitmap, but the tiling needs to be anchored to the bottom-left, instead of the top-left corner (the default). For example, if the tiles are the smiley faces below, I want it to be tiled like:

enter image description here

Using xml drawables I could achieve either tiling (using tileMode="repeat") or bottom positioning (using gravity="bottom"), but combining both is not possible, even the documentation says so:

android:tileMode

Keyword. Defines the tile mode. When the tile mode is enabled, the bitmap is repeated. Gravity is ignored when the tile mode is enabled.

Although it's not internally supported, is there any way to achieve this, perhaps using custom views?


Solution

  • Another way would be to extend BitmapDrawable and override the paint() method:

    In this method we avoid creating a new bitmap having the size of the view.

    class MyBitmapDrawable extends BitmapDrawable {
        private Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
        private boolean mRebuildShader = true;
        private Matrix mMatrix = new Matrix();
    
        @Override
        public void draw(Canvas canvas) {
            Bitmap bitmap = getBitmap();
            if (bitmap == null) {
                return;
            }
    
            if (mRebuildShader) {
                mPaint.setShader(new BitmapShader(bitmap, TileMode.REPEAT, TileMode.REPEAT));
                mRebuildShader = false;
            }
    
            // Translate down by the remainder
            mMatrix.setTranslate(0, getBounds().bottom % getIntrinsicHeight());
            canvas.save();
            canvas.setMatrix(mMatrix);
            canvas.drawRect(getBounds(), mPaint);
            canvas.restore();
        }
    }
    

    It can be set to the view like this:

    view.setBackgroundDrawable(new MyBitmapDrawable(getResources().getDrawable(R.drawable.smiley).getBitmap()));