0

I only have a RemoteViews object that contains my individual views. I have the following layout for this RemoteViews object:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center">

<LinearLayout
        android:layout_width="50dp"
        android:layout_height="52dp"
        android:layout_marginLeft="10dp"
        android:gravity="center">
<ImageView
        android:contentDescription="icon"
        android:id="@+id/icon"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/dog"
        />
</LinearLayout>
<TextView
        android:id="@+id/description"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white"
        android:layout_marginLeft="10dp"/>
</LinearLayout>

I am trying to draw a circle around the icon with some space in between; I don't want to trace the circle around the icon, I want there to be some whitespace in between(like a target sign).

I thought by specifying a radius larger than the imageview dimensions I could accomplish this, but the outer circle gets cut off at some parts; here "views" is the RemoteViews object:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),    
                R.drawable.dog);
Bitmap workingBitmap = Bitmap.createBitmap(bitmap);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, 
                       true);
Canvas canvas = new Canvas(mutableBitmap);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(6);

int centerCoordinate = mutableBitmap.getWidth()/2;
canvas.drawCircle(centerCoordinate, centerCoordinate, 
centerCoordinate+15, paint);

// equivalent to imageView.setImageBitmap
views.setImageViewBitmap(R.id.icon, mutableBitmap);
MarcusH
  • 1,693
  • 2
  • 15
  • 20

1 Answers1

1

Please try this modified code. I've tried explaining the changes in the comments. Sorry if they are insufficient:

        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),    
                R.drawable.dog);
        //
        // vvvv Commented out vvvv
        /*
         * Reason: The new Bitmap must be larger than the bitmap around
         * which the circle must be drawn. 
         */
//        Bitmap workingBitmap = Bitmap.createBitmap(bitmap);
//        Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, 
//                true);
//        Canvas canvas = new Canvas(mutableBitmap);
        // ^^^^ Commented out ^^^^
        //
        // vvvv Added vvvv
        // This is the total (Right + left) extra space on the sides;
        int padding = 30;
        // Since the Paint is going to draw a noticeably thick line, the thickness must be included in the calculations
        int strokeWidth = 6;
        /*
         * Calculating single dimension since the bitmap must have a square shape for the circle to fit.
         * Also account for the padding and the stroke width;
         */
        int bitmapSize = Math.max(bitmap.getWidth(), bitmap.getHeight()) + padding + strokeWidth;
        Bitmap workingBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(workingBitmap);
        // ^^^^ Added ^^^^
        //
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        //
        // paint.setStrokeWidth(6);
        paint.setStrokeWidth(strokeWidth);
        //
        // canvas.drawCircle(centerCoordinate, centerCoordinate, 
        //         centerCoordinate+15, paint);
        /*
         * Calculate exact top left position in the result Bitmap to draw the original Bitmap
         */
        canvas.drawBitmap(bitmap, (bitmapSize - bitmap.getWidth()) / 2.0f,
                (bitmapSize - bitmap.getHeight()) / 2.0f, paint);
        //
        // int centerCoordinate = mutableBitmap.getWidth()/2;
        int centerCoordinate = bitmapSize / 2;
        //
        //canvas.drawCircle(centerCoordinate, centerCoordinate, 
        // centerCoordinate+15, paint);
        /*
         * Draw the circle but account for the stroke width of the paint or else the circle will flatten on the edges of the Bitmap.
         */
        canvas.drawCircle(centerCoordinate, centerCoordinate,
                centerCoordinate - (strokeWidth/2.0f), paint);
        // equivalent to imageView.setImageBitmap
        // views.setImageViewBitmap(R.id.icon, mutableBitmap);
        views.setImageViewBitmap(R.id.icon, workingBitmap);

Also in the layout for the ImageView add:

android:scaleType="fitXY"

Edit: To keep the inner bitmap size fixed and only vary the circle size, first, the ImageView and its LinearLayout container cannot have a fixed size. Change all of those layout width and height values in the layout to "wrap_content".

Secondly since the image resource for "bitmap" is of an unknown size, bitmap will have to be loaded with a scaled down version of the resource that fits the maximum allowable dimension for the bitmap only, which in your case is 30px. This can be done by replacing:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),    
                    R.drawable.dog);

With the following code:

//
// Value to hold the required image dimension;
int requiredImageDimension = 30;
// Decode the Bitmap resource with the set options.
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(),
        R.drawable.dog);
// Scaled bitmap reference;
Bitmap bitmap = null;
// Check if the largest dimension is the width;
if (originalBitmap.getWidth() > originalBitmap.getHeight()) {
    // Force the width to the maximum allowable size and calculate
    // the scaled height of the Bitmap;
    bitmap = Bitmap.createScaledBitmap(originalBitmap,
            requiredImageDimension,
            originalBitmap.getHeight() * requiredImageDimension
                    / originalBitmap.getWidth(), true);
}
// If the width and height are equal;
else if(originalBitmap.getWidth() == originalBitmap.getHeight()){
    // Force the width and height to the maximum allowable size;
    bitmap = Bitmap.createScaledBitmap(originalBitmap,
            requiredImageDimension,
            requiredImageDimension, true);
}
// If the largest dimension is the height;
else {
    // Force the height to the maximum allowable size and calculate
    // the scaled width of the Bitmap;
    bitmap = Bitmap.createScaledBitmap(originalBitmap,
            originalBitmap.getWidth() * requiredImageDimension
                    / originalBitmap.getHeight(),
            requiredImageDimension, true);
}

So now you get a scaled down version of the original bitmap resource which will be pasted on the larger workingBitmap and loaded into the ImageView which will resize itself to accommodate the bitmap without scaling.

electrocrat
  • 446
  • 3
  • 8
  • Thanks, the circle no longer gets cut off but the padding is very minimal. Increasing it has no effect. In the xml above I had to set specific dimensions for the bitmap since it was too big. How do I increase the padding around my icon? – MarcusH Mar 27 '15 at 19:39
  • In this code if you increase "`padding`" (I tried doubling it), the `Bitmap` object size (dimension) **will** increase but your icon in the `ImageView` will look smaller. That is because the large image is forced to the `ImageView`s size. If you want your **icon** to have the same (physical) size while **increasing** the size of the **circle**, then you are going to have to allow the `ImageView` to scale itself based on the `Bitmap` size, **i.e.** it **cannot** have a fixed width. Do you want **that**?... – electrocrat Mar 28 '15 at 03:59
  • Thanks. Yes, I want the icon to stay 30x32 and increase the radius of my circle without having it cut off. – MarcusH Mar 29 '15 at 05:01