android에서 두 이미지를 오버레이하여 imageview를 설정하십시오.


100

내 앱에서 두 개의 이미지를 오버레이하려고하는데 내 canvas.setBitmap()라인 에서 충돌하는 것 같습니다 . 내가 뭘 잘못하고 있죠?

private void test() {
    Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.t);
    Bitmap mBitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.tt);
    Bitmap bmOverlay = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
    Canvas canvas = new Canvas();
    canvas.setBitmap(bmOverlay);
    canvas.drawBitmap(mBitmap, new Matrix(), null);
    canvas.drawBitmap(mBitmap2, new Matrix(), null);
    testimage.setImageBitmap(bmOverlay);
}

다음과 같이 프레임 레이아웃도 사용할 수 있습니다. stackoverflow.com/a/11658554/586484
Lysogen

답변:


234

복잡한 Canvas 조작을 건너 뛰고 LayerDrawable. 두 가지 선택 사항 중 하나가 있습니다 . XML정의한 다음 단순히 이미지를 설정하거나 LayerDrawable코드 에서 동적으로 구성 할 수 있습니다 .

솔루션 # 1 (XML 사용) :

새로운 Drawable XML 파일을 만들고 이름을 지정합니다 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>

이제 해당 Drawable을 사용하여 이미지를 설정합니다.

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

솔루션 # 2 (동적) :

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);

(이 코드를 테스트하지 않았으므로 실수가있을 수 있지만이 일반적인 개요는 작동합니다.)


1
감사합니다, 작동했습니다! 다른 사람이 코드를 사용하는 경우 오타 한 가지 : LayerDrawable layers2 = new LayerDrawable (layers); testimage.setImageDrawable (layers2);
John

1
공간을 절약하고 이미지를 재사용하는 좋은 방법입니다. 또한 android : left, android : right, android : top 및 android : down을 사용하여 .xml 파일에서 레이어 중 하나의 위치를 ​​제어 할 수 있습니다.
zabawaba99

나는 이것을 사용하여 이미지 뒤에 원형 모양의 드로어 블을 그렸습니다. 아주 좋은 솔루션입니다!
Daniel Wilson

1
프로그래밍 방식으로 레이어 [1] 만 숨기는 방법이 있습니까? 상단에 ajax 로더 레이어가있는 이미지 레이어를 표시하고 싶습니다. 얼마 후 아약스 로더 만 숨기고 싶습니다. 어떠한 제안?
하리 산남

1
내 요구에 잘 맞습니다 (코드 접근 방식을 사용했습니다). 사용자가 앱을 탐색하기 위해 탭하는 여러 '타일'이 있습니다. 이 접근 방식을 사용하여 런타임에로드 할 수있는 단일 배경 이미지 (모든 타일에 공통)와 수많은 전경 이미지 (투명 배경 포함)를 가질 수있었습니다. :-)이 대답없이 LayerDrawable 살펴 보았다하지 않을까요
DilbertDave

10

좋습니다. DroidDraw라는 프로그램이 있다는 것을 알 수 있습니다. 그것은 당신이 개체를 그리고 다른 위에 그것을 시도하는 데 도움이 될 수 있습니다. 솔루션을 시도했지만 작은 이미지 아래에 애니메이션이있어서 작동하지 않았습니다. 하지만 먼저 아래에 있다고 가정하는 상대적인 레이아웃에 하나의 이미지를 배치하고 그 위에 오버레이로 간주되는 다른 이미지를 그렸고 모든 것이 잘 작동했습니다. 그래서 RelativeLayout, DroidDraw 그리고 당신은 갈 수 있습니다 :) 간단하고, 어떤 종류의 흔들림도 없습니다 :) 그리고 여기에 약간의 코드가 있습니다.

로고는 shazam 배경 이미지 위에 표시됩니다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/widget30"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<ImageView
android:id="@+id/widget39"
android:layout_width="219px"
android:layout_height="225px"
android:src="@drawable/shazam_bkgd"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
<ImageView
android:id="@+id/widget37"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/shazam_logo"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
</RelativeLayout>

6

아래 코드를 사용하여 문제를 해결하거나 여기에서 데모를 다운로드 할 수 있습니다.

각각을 처리 할 두 개의 함수를 만듭니다.

먼저 캔버스가 그려지고 이미지가 점 (0,0)에서 서로 위에 그려집니다.

버튼 클릭시

public void buttonMerge(View view) {

        Bitmap bigImage = BitmapFactory.decodeResource(getResources(), R.drawable.img1);
        Bitmap smallImage = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
        Bitmap mergedImages = createSingleImageFromMultipleImages(bigImage, smallImage);

        img.setImageBitmap(mergedImages);
    }

오버레이를 만드는 기능.

private Bitmap createSingleImageFromMultipleImages(Bitmap firstImage, Bitmap secondImage){

    Bitmap result = Bitmap.createBitmap(firstImage.getWidth(), firstImage.getHeight(), firstImage.getConfig());
    Canvas canvas = new Canvas(result);
    canvas.drawBitmap(firstImage, 0f, 0f, null);
    canvas.drawBitmap(secondImage, 10, 10, null);
    return result;
}

더 읽어보기


2

약간 늦은 답변이지만 Picasso를 사용하여 URL에서 이미지 병합을 다룹니다.

MergeImageView

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;

import java.io.IOException;
import java.util.List;

public class MergeImageView extends ImageView {

    private SparseArray<Bitmap> bitmaps = new SparseArray<>();
    private Picasso picasso;
    private final int DEFAULT_IMAGE_SIZE = 50;
    private int MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE;
    private int MAX_WIDTH = DEFAULT_IMAGE_SIZE * 2, MAX_HEIGHT = DEFAULT_IMAGE_SIZE * 2;
    private String picassoRequestTag = null;

    public MergeImageView(Context context) {
        super(context);
    }

    public MergeImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MergeImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean isInEditMode() {
        return true;
    }

    public void clearResources() {
        if (bitmaps != null) {
            for (int i = 0; i < bitmaps.size(); i++)
                bitmaps.get(i).recycle();
            bitmaps.clear();
        }
        // cancel picasso requests
        if (picasso != null && AppUtils.ifNotNullEmpty(picassoRequestTag))
            picasso.cancelTag(picassoRequestTag);
        picasso = null;
        bitmaps = null;
    }

    public void createMergedBitmap(Context context, List<String> imageUrls, String picassoTag) {
        picasso = Picasso.with(context);
        int count = imageUrls.size();
        picassoRequestTag = picassoTag;

        boolean isEven = count % 2 == 0;
        // if url size are not even make MIN_IMAGE_SIZE even
        MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE + (isEven ? count / 2 : (count / 2) + 1);
        // set MAX_WIDTH and MAX_HEIGHT to twice of MIN_IMAGE_SIZE
        MAX_WIDTH = MAX_HEIGHT = MIN_IMAGE_SIZE * 2;
        // in case of odd urls increase MAX_HEIGHT
        if (!isEven) MAX_HEIGHT = MAX_WIDTH + MIN_IMAGE_SIZE;

        // create default bitmap
        Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_wallpaper),
                MIN_IMAGE_SIZE, MIN_IMAGE_SIZE, false);

        // change default height (wrap_content) to MAX_HEIGHT
        int height = Math.round(AppUtils.convertDpToPixel(MAX_HEIGHT, context));
        setMinimumHeight(height * 2);

        // start AsyncTask
        for (int index = 0; index < count; index++) {
            // put default bitmap as a place holder
            bitmaps.put(index, bitmap);
            new PicassoLoadImage(index, imageUrls.get(index)).execute();
            // if you want parallel execution use
            // new PicassoLoadImage(index, imageUrls.get(index)).(AsyncTask.THREAD_POOL_EXECUTOR);
        }
    }

    private class PicassoLoadImage extends AsyncTask<String, Void, Bitmap> {

        private int index = 0;
        private String url;

        PicassoLoadImage(int index, String url) {
            this.index = index;
            this.url = url;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                // synchronous picasso call
                return picasso.load(url).resize(MIN_IMAGE_SIZE, MIN_IMAGE_SIZE).tag(picassoRequestTag).get();
            } catch (IOException e) {
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap output) {
            super.onPostExecute(output);
            if (output != null)
                bitmaps.put(index, output);

            // create canvas
            Bitmap.Config conf = Bitmap.Config.RGB_565;
            Bitmap canvasBitmap = Bitmap.createBitmap(MAX_WIDTH, MAX_HEIGHT, conf);
            Canvas canvas = new Canvas(canvasBitmap);
            canvas.drawColor(Color.WHITE);

            // if height and width are equal we have even images
            boolean isEven = MAX_HEIGHT == MAX_WIDTH;
            int imageSize = bitmaps.size();
            int count = imageSize;

            // we have odd images
            if (!isEven) count = imageSize - 1;
            for (int i = 0; i < count; i++) {
                Bitmap bitmap = bitmaps.get(i);
                canvas.drawBitmap(bitmap, bitmap.getWidth() * (i % 2), bitmap.getHeight() * (i / 2), null);
            }
            // if images are not even set last image width to MAX_WIDTH
            if (!isEven) {
                Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmaps.get(count), MAX_WIDTH, MIN_IMAGE_SIZE, false);
                canvas.drawBitmap(scaledBitmap, scaledBitmap.getWidth() * (count % 2), scaledBitmap.getHeight() * (count / 2), null);
            }
            // set bitmap
            setImageBitmap(canvasBitmap);
        }
    }
}

xml

<com.example.MergeImageView
    android:id="@+id/iv_thumb"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

List<String> urls = new ArrayList<>();
String picassoTag = null;
// add your urls
((MergeImageView)findViewById(R.id.iv_thumb)).
        createMergedBitmap(MainActivity.this, urls,picassoTag);

1

이것은 내 해결책입니다.

    public Bitmap Blend(Bitmap topImage1, Bitmap bottomImage1, PorterDuff.Mode Type) {

        Bitmap workingBitmap = Bitmap.createBitmap(topImage1);
        Bitmap topImage = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);

        Bitmap workingBitmap2 = Bitmap.createBitmap(bottomImage1);
        Bitmap bottomImage = workingBitmap2.copy(Bitmap.Config.ARGB_8888, true);

        Rect dest = new Rect(0, 0, bottomImage.getWidth(), bottomImage.getHeight());
        new BitmapFactory.Options().inPreferredConfig = Bitmap.Config.ARGB_8888;
        bottomImage.setHasAlpha(true);
        Canvas canvas = new Canvas(bottomImage);
        Paint paint = new Paint();

        paint.setXfermode(new PorterDuffXfermode(Type));

        paint.setFilterBitmap(true);
        canvas.drawBitmap(topImage, null, dest, paint);
        return bottomImage;
    }

사용법 :

imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.SCREEN));

또는

imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.OVERLAY));

결과 :

오버레이 모드 : 오버레이 모드

스크린 모드: 스크린 모드


좋아요. 그러나 두 개의 이미지를 근처에 표시하려면 솔루션은 무엇입니까?
maniaq
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.