3

Background

I have 2 imageViews, one on top of another, that have an animation together . I need them to blend with each other, using the "Multiply" effect, during this animation.

Something similar to this question which is about colors, yet with images (VectorDrawable in my case, but I can use PNG instead if needed).

Here's a sketch to demonstrate what I'd like to do:

enter image description here

Notice that the part of the images that overlap is darker than the original color of the arrows.

The problem

So far I can't find a way to do it. I know of course how to put a view on top of another, but changing the color of a part of the bitmap, based on the other, is something I can't find.

What I've found

I tried to use :

imageView.getDrawable().setColorFilter(..., PorterDuff.Mode.MULTIPLY)

for both the ImageViews, but it doesn't seem to work. What it does is actually change the entire color of the imageView, merging with the color I provide as the parameter.

It makes sense, because it's just a colorFilter, similar to tint.

I also tried alpha for each of the ImageViews, but this also mean that a part of the ImageViews (the parts that don't overlap) will have a semi-transparent color.

I could theoretically get the bitmap of each of them, and then perform the filter on the result, but this is not practical as I need to show it during animation between the two.

The question

How can I blend the 2 imageViews ?

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • @pskink How should I do it? Also, would extending the ImageView (or its support library view) ruin the support of using VectorDrawable? – android developer Apr 04 '17 at 13:23
  • what about changing color by pixels? – Abid Khan Apr 04 '17 at 13:24
  • @AbidKhan Already wrote about it in the question. It won't work, because I don't want to change entire color of the view, only the overlapping part. – android developer Apr 04 '17 at 13:25
  • May be extend a view and draw both image using canvas? putting an animator isn't difficult once you achieve the desired overlap effect. something like this http://android-er.blogspot.in/2013/08/merge-two-image-overlap-with-alpha.html – Ankit Apr 04 '17 at 13:39
  • @Ankit Example you've shown is with Alpha. I don't want Alpha. I want real colors of the ImageViews to blend with each other. – android developer Apr 04 '17 at 13:50
  • @pskink The sketch is only for demonstration and was created via an image editing app. If the two images are of a light-blue color, for example, the part that overlaps them would be a darker color of blue. I don't want to use alpha for the ImageViews. – android developer Apr 04 '17 at 13:56
  • @pskink The question isn't about an animation (which if you insist wasn't decided yet). The animation is just a part of the things to consider, so that you won't use a bitmap+bitmap algorithm. – android developer Apr 04 '17 at 13:59
  • @pskink A sentence before has " that have an animation together" . They play an animation together. As I wrote, it's not about the animation. It's about the blending. – android developer Apr 04 '17 at 14:05
  • @pskink out of curiosity, how expensive is that operation? If this doesn't work i think GPU is the only option for blend + animation. may be openGL or opencv? never tried one for this effect. – Ankit Apr 05 '17 at 08:43
  • @pskink just speculating that if your solution is to be implemented with a simple transition animation will the animation work smoothly? i am aware that OP doesn't require animation as primary requirement. – Ankit Apr 05 '17 at 09:25
  • @Ankit There might be animation. It depends on a decision we will make. – android developer Apr 05 '17 at 15:08
  • @pskink The exact same code could work on the support library VectorDrawable? – android developer Apr 05 '17 at 15:09
  • @pskink As I remember, the VectorDrawable of the support library has many limitations when used in old Android versions. As an example, it must not be used in a LayerDrawable (will crash). Since you use a LayerDrawable, I think it has a high chance of not working. But even if it works (I can use PNG anyway), how would you use it in 2 ImageViews, each has its own animation? Will you simulate 2 ImageViews inside a single one? – android developer Apr 05 '17 at 17:38
  • @pskink As I wrote, I don't understand your solution of what to do here. My guess is that you want to use a single ImageView with 2 VectorDrawables (of the support library) inside a single LayerDrawable. If so, as I remember, such a thing will crash (on old Android versions). There were even posts about it : https://code.google.com/p/android/issues/detail?id=206112. In addition, this means it's not 2 ImageViews, as I asked about. However, since this might be an interesting thing to try, please post a full solution of what you suggest. – android developer Apr 05 '17 at 18:02
  • @pskink you tried on old Android version? – android developer Apr 05 '17 at 20:11
  • @pskink Can you please share the code? – android developer Apr 05 '17 at 20:42
  • @pskink I just tested your code. As I suspected, it cannot work with VectorDrawable on low Android versions. What you probably did is to forget using the file as VectorDrawable, by not putting the flag to use them ( "vectorDrawables.useSupportLibrary = true" in gradle file), so it used the PNG files automatically generated from them. On new Android versions (like on 7.1.2 in my case), it works fine. BTW, how would you change the code to support as many drawables as needed? – android developer Apr 22 '17 at 07:24
  • @pskink Please show your entire code. For me it shows that it can't load those vectors, as any other vector (on low Android versions). – android developer Apr 22 '17 at 11:40
  • @pskink Using getDrawable. But as I wrote, this is not supported. – android developer Apr 22 '17 at 11:45
  • @pskink I've tested almost all of what you wrote. I didn't use Context#getDrawable because it's not supported on low Android versions, but I didn't know of AppCompatResources class (which now works). Why isn't it used in ResourcesCompat ? Is there any danger in using it, because of what Google warned of using VectorDrawable in other cases that are not setImageResource and app:srcCompat ? – android developer Apr 22 '17 at 11:55
  • @pskink Interesting, but why are there 2 support library class to get resources ( ResourcesCompat, AppCompatResources ) ? I find it weird... – android developer Apr 22 '17 at 12:27
  • @pskink ok thank you. Say, what would you change in the "LD" class to support more than 2 layers? – android developer Apr 22 '17 at 19:59
  • @pskink You called "canvas.saveLayer" and "canvas.restoreToCount". Not just drawing. What are they for? Should you also call them multiple times in the loop? – android developer Apr 22 '17 at 20:33
  • @pskink Should they both be called in the loop? – android developer Apr 23 '17 at 07:05
  • @pskink I meant if both those calls of those functions be called inside the loop – android developer Apr 23 '17 at 07:44
  • @pskink Since the layers need to animate, we are talking about animation within the view/drawable itself, no? Shouldn't it actually be more efficient than multiple views animation? – android developer Apr 26 '17 at 05:16
  • @pskink Can't see an animation effect in what you've put, but how do you set the color of the arrow using the same vector file? I know it's possible (support library does it), but I never thought how. Just set the color of the paint of the vector? Or something else? – android developer Apr 26 '17 at 18:41
  • @pskink Oh you mean animating the paths within the vector. But how do you animate them? – android developer Apr 27 '17 at 09:54
  • @pskink Interesting. Thanks. – android developer Apr 27 '17 at 10:18
  • @pskink And what? This question was asked a long time ago. We moved on, while I asked for more information because I was just curious. – android developer Apr 27 '17 at 22:39
  • @pskink We moved on because of lack of time, by just putting simple animation and that's it. – android developer Apr 28 '17 at 10:09
  • @pskink That's work. Move on when you can't keep up with the schedule. The designed wasn't even sure this is what he wants anyway. – android developer Apr 28 '17 at 19:24
  • @pskink Why would you ignore questions I don't intend to use at the office? Why does it matter what purpose the code is used for? Whether for learning or for actual usage at work? Also, I still don't get why you insist on using the comments instead of writing an answer. – android developer Apr 29 '17 at 06:07
  • @pskink OK, your choice when to help and when not to. – android developer Apr 29 '17 at 10:36

3 Answers3

0

Since you're using VectorDrawable, Have you considered animating the drawable rather than the view?

https://developer.android.com/reference/android/graphics/drawable/AnimatedVectorDrawable.html

ekimai
  • 83
  • 11
  • 1
    This is one option we actually consider (and I wrote about it here: http://stackoverflow.com/q/43200533/878126 ) , but we need to investigate both options. Please avoid writing an answer that says to use a completely different API. – android developer Apr 04 '17 at 13:22
0

try this:

public Bitmap combineImages(Bitmap frame, Bitmap image) {

            Bitmap cs = null;
            Bitmap rs = null;

            rs = Bitmap.createScaledBitmap(frame, image.getWidth(),
                    image.getHeight(), true);

            cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
                    Bitmap.Config.RGB_565);

            Canvas comboImage = new Canvas(cs);

            comboImage.drawBitmap(image, 0, 0, null);
            comboImage.drawBitmap(rs, 0, 0, null);

            if (rs != null) {
                rs.recycle();
                rs = null;
            }
            Runtime.getRuntime().gc();

            return cs;
        }
Saurav Prakash
  • 588
  • 1
  • 5
  • 26
  • As I wrote, I don't want to use a bitmap, because this will require me to do it for every frame of the animation. It will require lot of CPU usage. – android developer Apr 04 '17 at 13:48
0

OK, it seems it's probably not possible using 2 views, because of the way they work on Android, so instead, I want to show how to do it with a LayerDrawable instead:

public class LD extends LayerDrawable {
    private Paint p = new Paint();

    public LD(Drawable[] layers) {
        super(layers);
        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        int count = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);

        for (int i = 0, numberOfLayers = getNumberOfLayers(); i < numberOfLayers; ++i) {
            this.getDrawable(i).draw(canvas);
            canvas.saveLayer(null, p, Canvas.ALL_SAVE_FLAG);
        }
        canvas.restoreToCount(count);

        //original code:
        //int count = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
        //this.getDrawable(0).draw(canvas);
        //canvas.saveLayer(null, p, Canvas.ALL_SAVE_FLAG);
        //this.getDrawable(1).draw(canvas);
        //canvas.restoreToCount(count);
    }
}

Usage:

    ImageView imageView = (ImageView) findViewById(R.id.imageView);
    Drawable drawable1 = AppCompatResources.getDrawable(this, R.drawable....);
    Drawable drawable2 = AppCompatResources.getDrawable(this, R.drawable....);
    Drawable drawable3 = AppCompatResources.getDrawable(this, R.drawable....);

    LD layerDrawable = new LD(new Drawable[]{
            drawable1,
            drawable2,
            drawable3
    });
    imageView.setImageDrawable(layerDrawable);
android developer
  • 114,585
  • 152
  • 739
  • 1,270