chồng lên hai hình ảnh trong Android để đặt chế độ xem hình ảnh


100

Tôi đang cố gắng phủ hai hình ảnh trong ứng dụng của mình, nhưng chúng dường như bị lỗi ở canvas.setBitmap()dòng của tôi . Tôi đang làm gì sai?

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

Cũng có thể sử dụng framelayout, như thế này: stackoverflow.com/a/11658554/586484
Lysogen

Câu trả lời:


234

Bạn có thể bỏ qua thao tác Canvas phức tạp và thực hiện việc này hoàn toàn bằng Drawables, bằng cách sử dụng LayerDrawable. Bạn có một trong hai lựa chọn: Bạn có thể xác định nó bằng XML, sau đó chỉ cần đặt hình ảnh hoặc bạn có thể định cấu hình LayerDrawableđộng trong mã.

Giải pháp số 1 (qua XML):

Tạo một tệp XML có thể vẽ mới, hãy gọi nó là 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>

Bây giờ hãy đặt hình ảnh bằng cách sử dụng Drawable đó:

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

Giải pháp # 2 (động):

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

(Tôi chưa kiểm tra mã này nên có thể có sai sót, nhưng phác thảo chung này sẽ hoạt động.)


1
cảm ơn bạn, nó đã hoạt động! tuy nhiên, một lỗi đánh máy, trong trường hợp người khác sử dụng mã: LayerDrawable layer2 = new LayerDrawable (các lớp); chứng thực.setImageDrawable (lớp2);
John

1
Cách tuyệt vời để tiết kiệm không gian và tái sử dụng hình ảnh. Ngoài ra, bạn có thể sử dụng android: left, android: right, android: top và android: down để điều khiển vị trí của một trong các lớp trong tệp .xml.
zabawaba99

Tôi đã sử dụng cái này để vẽ một hình tròn có thể vẽ được đằng sau một hình ảnh, giải pháp rất hay!
Daniel Wilson

1
Có cách nào để ẩn các lớp [1] một mình theo chương trình không? Tôi muốn hiển thị một lớp Hình ảnh với lớp bộ tải ajax ở trên cùng. Sau một thời gian, tôi muốn ẩn bộ tải ajax một mình. Bất kì lời đề nghị nào?
harishannam

1
Hoạt động tốt cho nhu cầu của tôi (tôi đã sử dụng phương pháp mã). Tôi có một số 'ô xếp' mà người dùng chạm vào để điều hướng xung quanh ứng dụng. Sử dụng cách tiếp cận này, tôi đã có thể có một hình nền duy nhất (chung cho tất cả các ô) và nhiều hình ảnh tiền cảnh (với nền trong suốt) mà tôi có thể tải trong thời gian chạy. Sẽ không nhìn vào LayerDrawable nếu không có câu trả lời này :-)
DilbertDave

10

Được thôi để bạn biết có một chương trình được gọi là DroidDraw. Nó có thể giúp bạn vẽ các đối tượng và thử chúng chồng lên nhau. Tôi đã thử giải pháp của bạn nhưng tôi đã có hoạt ảnh dưới hình ảnh nhỏ hơn nên điều đó không hoạt động. Nhưng sau đó tôi đã cố gắng đặt một hình ảnh trong một bố cục tương đối được cho là nằm dưới trước rồi mới lên trên hình đó, tôi đã vẽ một hình ảnh khác được cho là phủ lên và mọi thứ đều hoạt động tốt. Vì vậy, RelativeLayout, DroidDraw và bạn rất tốt để sử dụng :) Đơn giản, không có bất kỳ loại rắc rối nào :) và đây là một chút mã cho bạn:

Logo sẽ nằm trên hình nền 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

Bạn có thể sử dụng đoạn mã dưới đây để giải quyết vấn đề hoặc tải xuống bản demo tại đây

Tạo hai chức năng để xử lý mỗi chức năng.

Đầu tiên, canvas được vẽ và các hình ảnh được vẽ chồng lên nhau từ điểm (0,0)

Khi nhấp vào nút

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

Chức năng tạo lớp phủ.

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

Đọc thêm


2

Câu trả lời hơi muộn, nhưng nó bao gồm việc hợp nhất hình ảnh từ các url bằng Picasso

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

Thí dụ

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

1

đây là giải pháp của tôi:

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

sử dụng :

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

hoặc là

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

và kết quả:

Chế độ lớp phủ: Chế độ lớp phủ

Chế độ màn hình: Chế độ màn hình


Nó tốt. Nhưng nếu muốn hiển thị hai hình ảnh gần thì giải pháp là gì?
maniaq
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.