Android - Imageview with multiple bitmaps

2019-04-16 10:10发布

问题:

I am working on a chat application, which does need to show the profile picture of each person whom I'm chatting with. If it is a group conversation I need to design a layout like FB as below

I'm thinking of implementing it using LayerDrawable but not sure how. Also the images need to be loaded from server. I'm using Glide library to load images.

回答1:

Considered 3 layouts side by side and wrap the top layout into circular shape.

<?xml version="1.0" encoding="utf-8"?>
<nz.co.example.components.CircleLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/messaging_profile_pic_size"
android:layout_height="@dimen/messaging_profile_pic_size"
android:orientation="horizontal"
custom:diameter="@dimen/messaging_profile_pic_size"
>
<ImageView
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:id="@+id/iv_left"
    android:scaleType="centerCrop"
    />

<LinearLayout
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:orientation="vertical"
    android:paddingStart="@dimen/line_spacing"
    android:paddingEnd="0dp"
    >
    <ImageView
        android:layout_width="@dimen/messaging_profile_pic_half_size"
        android:layout_height="@dimen/messaging_profile_pic_half_size"
        android:id="@+id/iv_top_right"
        android:scaleType="centerCrop"
        />
    <ImageView
        android:layout_width="@dimen/messaging_profile_pic_half_size"
        android:layout_height="@dimen/messaging_profile_pic_half_size"
        android:id="@+id/iv_bottom_right"
        android:paddingTop="@dimen/line_spacing"
        android:scaleType="centerCrop"
        />
</LinearLayout>

</nz.co.example.components.CircleLinearLayout>

And my Circular linearlayout code goes like this

public class CircleLinearLayout extends LinearLayout {

private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float radius;

public CircleLinearLayout(Context context) {
    super(context);
    init(context, null, 0);
}

public CircleLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs, 0);
}

public CircleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
}

private void init(Context context, AttributeSet attrs, int defStyle) {

    paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    if(attrs != null)
    {
        TypedArray a = context.getTheme().obtainStyledAttributes( attrs,R.styleable.CircleLinearLayout, defStyle , 0);

        try {
            radius = a.getDimension(R.styleable.CircleLinearLayout_diameter, getResources().getDimension(R.dimen.messaging_profile_pic_size)) / 2;
        } finally {
            a.recycle();
        }
    }

    setWillNotDraw(false);
}

@Override
public void draw(Canvas canvas) {
    Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas offscreenCanvas = new Canvas(offscreenBitmap);

    super.draw(offscreenCanvas);

    if (maskBitmap == null) {
        maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
    }

    offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
    canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}

private Bitmap createMask(int width, int height) {
    Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
    Canvas canvas = new Canvas(mask);

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.WHITE);

    canvas.drawRect(0, 0, width, height, paint);

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

    canvas.drawCircle(radius , radius , radius , paint);

    return mask;
   }
 }

Cheers, Sree



回答2:

Yes, you would need to implement LayerDrawable. On StackOverflow there are some examples like this below from overlay two images in android to set an imageview issue

You can skip the complex Canvas manipulation and do this entirely with Drawables, using LayerDrawable. You have one of two choices: You can either define it in XML then simply set the image, or you can configure a LayerDrawable dynamically in code.

Solution #1 (via XML):

Create a new Drawable XML file, let's call it layer.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/t" />
    <item android:drawable="@drawable/tt" />
</layer-list>

Now set the image using that Drawable:

testimage.setImageDrawable(getResources().getDrawable(R.layout.layer));

Solution #2 (dynamic):

Resources r = getResources();
Drawable[] layers = new Drawable[2];
layers[0] = r.getDrawable(R.drawable.t);
layers[1] = r.getDrawable(R.drawable.tt);
LayerDrawable layerDrawable = new LayerDrawable(layers);
testimage.setImageDrawable(layerDrawable);

(I haven't tested this code so there may be a mistake, but this general outline should work.)

Another possible solution might be from unable to set multiple bitmap in one imageview

you can do something like the following :

public Bitmap drawMultipleBitmapsOnImageView(Bitmap b) {
      Bitmap drawnBitmap = null;

      try {
          drawnBitmap = Bitmap.createBitmap(400, 400, Config.ARGB_8888);

          Canvas canvas = new Canvas(drawnBitmap);
                     // JUST CHANGE TO DIFFERENT Bitmaps and coordinates .
          canvas.drawBitmap(b, 100, 100, null);
          canvas.drawBitmap(b, 200, 300, null);
          canvas.drawBitmap(b, 100, 200, null);
          canvas.drawBitmap(b, 300, 350, null);

      } catch (Exception e) {
          e.printStackTrace();
      }
      return drawnBitmap;
  }

you call this method like the following :

ImageView myImageView = (ImageView) findViewById(R.id.myImageView);
      Bitmap bitmap = ((BitmapDrawable) myImageView.getDrawable())
              .getBitmap();
      Bitmap b = drawMultipleBitmapsOnImageView(bitmap);

      myImageView.setImageBitmap(b);

If you still feel not satisfied, take a look at Android : How to Draw multiple images inside the same imageview but shifted in the y coordinate?

use this code for show 2 image in one image:

    ImageView myImageView = (ImageView) findViewById(R.id.img1);
    Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.call);
    Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.available);
    Bitmap combinedBitmap = getCombinedBitmap(pic2, pic1);

    myImageView.setImageBitmap(b);

and this is the getCombinedBitmap() method :

public Bitmap getCombinedBitmap(Bitmap b, Bitmap b2) {
    Bitmap drawnBitmap = null;

    try {
        drawnBitmap = Bitmap.createBitmap(200, 200, Config.ARGB_8888);

        Canvas canvas = new Canvas(drawnBitmap);
        // JUST CHANGE TO DIFFERENT Bitmaps and coordinates .
        canvas.drawBitmap(b, 0, 0, null);
        canvas.drawBitmap(b2, 0, 0, null);
        //for more images :
        // canvas.drawBitmap(b3, 0, 0, null);
        // canvas.drawBitmap(b4, 0, 0, null);

    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return drawnBitmap;
}

You can also visit: Draw multiple bitmaps on Imageview

On Web you would also find some tutorials, but I don't think that presented there solution would be much different from this above.


Finally, once you've done it to make it circle use this library: https://github.com/hdodenhof/CircleImageView

Hope it help