【问题标题】:overlay two images in android to set an imageview在android中覆盖两个图像以设置一个imageview
【发布时间】:2011-02-13 23:04:20
【问题描述】:

我试图在我的应用程序中叠加两个图像,但它们似乎在我的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);
}

【问题讨论】:

标签: android image


【解决方案1】:

您可以跳过复杂的 Canvas 操作并完全使用 Drawables 完成此操作,使用 LayerDrawable。您有以下两种选择之一:您可以define it in 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);

(我没有测试过这段代码,所以可能有错误,但这个大致的大纲应该可以。)

【讨论】:

  • 谢谢,成功了!但是有一个错字,以防其他人使用代码:LayerDrawable layers2 = new LayerDrawable(layers); testimage.setImageDrawable(layers2);
  • 节省空间和重复使用图像的好方法。此外,您可以使用 android:left、android:right、android:top 和 android:down 来控制 .xml 文件中某一层的位置。
  • 我用它在图像后面画了一个可绘制的圆形,非常好的解决方案!
  • 有没有办法以编程方式单独隐藏图层[1]?我想在顶部显示一个带有 ajax 加载器层的图像层。一段时间后,我想单独隐藏 ajax 加载器。有什么建议吗?
  • 非常适合我的需求(我使用了代码方法)。我有许多“图块”,用户可以点击这些“图块”在应用程序中导航。使用这种方法,我能够拥有一个背景图像(所有图块通用)和许多前景图像(具有透明背景),我可以在运行时加载它们。如果没有这个答案,就不会查看 LayerDrawable :-)
【解决方案2】:

好的,这样您就知道有一个名为 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>

【讨论】:

    【解决方案3】:

    答案有点晚,但它涵盖了使用 Picasso 合并来自 url 的图像

    合并图像视图

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

    【讨论】:

      【解决方案4】:

      您可以使用下面的代码解决问题或download demo here

      创建两个函数来处理每个函数。

      首先,画布被绘制,图像从点 (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;
      }
      

      Read more

      【讨论】:

        【解决方案5】:

        这是我的解决方案:

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

        结果:

        叠加模式:

        屏幕模式:

        【讨论】:

        • 很好。但是如果想在附近显示两张图片有什么办法呢?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多