nałóż dwa obrazy w systemie Android, aby ustawić widok obrazu


100

Próbuję nałożyć dwa obrazy w mojej aplikacji, ale wydaje się, że zawieszają się na mojej canvas.setBitmap()linii. Co ja robię źle?

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

Można również użyć framelayout, na przykład: stackoverflow.com/a/11658554/586484
Lysogen

Odpowiedzi:


234

Możesz pominąć złożoną manipulację Canvas i zrobić to całkowicie za pomocą Drawables, używając LayerDrawable. Masz jedną z dwóch możliwości: możesz zdefiniować go w XML, a następnie po prostu ustawić obraz, lub możesz skonfigurować LayerDrawabledynamicznie w kodzie.

Rozwiązanie nr 1 (przez XML):

Utwórz nowy plik XML do rysowania, nazwijmy go 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>

Teraz ustaw obraz za pomocą tego Drawable:

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

Rozwiązanie nr 2 (dynamiczne):

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

(Nie testowałem tego kodu, więc może wystąpić błąd, ale ten ogólny zarys powinien działać.)


1
dziękuję, zadziałało! jedna literówka, na wypadek gdyby ktoś inny użył kodu: LayerDrawable layer2 = new LayerDrawable (warstwy); testimage.setImageDrawable (layer2);
John

1
Świetny sposób na zaoszczędzenie miejsca i ponowne wykorzystanie obrazów. Możesz także użyć android: left, android: right, android: top i android: down, aby kontrolować położenie jednej z warstw w pliku .xml.
zabawaba99

Użyłem tego do narysowania okrągłego kształtu, który można narysować za obrazem, bardzo ładne rozwiązanie!
Daniel Wilson,

1
Czy istnieje sposób na programowe ukrycie samych warstw [1]? Chcę pokazać warstwę obrazu z warstwą modułu ładującego ajax na górze. Po jakimś czasie chcę sam ukryć ładowarkę Ajax. Jakieś sugestie?
harishannam

1
Działa dobrze na moje potrzeby (użyłem podejścia kodowego). Mam kilka „kafelków”, które użytkownik dotyka, aby poruszać się po aplikacji. Korzystając z tego podejścia, mogłem mieć jeden obraz tła (wspólny dla wszystkich kafelków) i wiele obrazów pierwszego planu (z przezroczystym tłem), które mogę załadować w czasie wykonywania. Nie spojrzałbym na LayerDrawable bez tej odpowiedzi :-)
DilbertDave

10

ok, żeby wiedzieć, że istnieje program o nazwie DroidDraw. Może pomóc w rysowaniu obiektów i wypróbowywaniu ich jeden na drugim. Wypróbowałem twoje rozwiązanie, ale miałem animację pod mniejszym obrazem, więc to nie zadziałało. Ale potem spróbowałem umieścić jeden obraz we względnym układzie, który miał być najpierw pod, a następnie narysowałem drugi obraz, który miał być nałożony i wszystko działało świetnie. A więc RelativeLayout, DroidDraw i jesteś gotowy do pracy :) Proste, nie ma żadnego rodzaju jiggery pockery :) a tutaj jest trochę kodu dla ciebie:

Logo będzie znajdować się nad obrazem tła 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

Możesz użyć poniższego kodu, aby rozwiązać problem lub pobrać demo tutaj

Utwórz dwie funkcje do obsługi każdej z nich.

Najpierw rysowane jest płótno, a obrazy są rysowane jeden na drugim od punktu (0,0)

Po kliknięciu przycisku

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

Funkcja tworzenia nakładki.

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

Czytaj więcej


2

To trochę późna odpowiedź, ale obejmuje łączenie obrazów z adresów URL za pomocą Picassa

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" />

Przykład

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

1

to jest moje rozwiązanie:

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

stosowanie :

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

lub

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

a wyniki:

Tryb nakładki: Tryb nakładania

Tryb ekranowy: Tryb ekranowy


To jest dobre. Ale jeśli chcesz wyświetlić dwa obrazy w pobliżu, jakie jest rozwiązanie?
maniaq
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.