Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display 2 views, with a gradient-fade effect on Android?

I want to have 2 views displayed on the screen - one would be a camera preview, on the top, while other one would show an image or a google map - and live on the bottom of the screen.

I want to have a gradient-like transition between them though - so there's no rough edge between them. Is that possible to have such an effect?

Edit: The effect I'd like to achieve should look like this (top part comes from the camera preview, while bottom part should be a map...):

Map blending into camera photo

On the iOS I got similar effect with CameraOverlay showing the map and setting the layer masp to the gradient:

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.map.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite: 1.0 alpha: 0.0] CGColor], (id)[[UIColor colorWithWhite: 1.0 alpha: 1.0] CGColor], nil];
gradient.startPoint = CGPointMake(0.5f, 0.0f);
gradient.endPoint = CGPointMake(0.5f, 0.5f);
self.map.layer.mask = gradient;
like image 649
kender Avatar asked Apr 18 '13 18:04

kender


1 Answers

Unfortunately AFAIK you can't crossfade between a camera preview and a map if both components have to be interactive/live. Like stated before in a previous comment, this is related to the nature of both widgets and the limitations of Android compositing.

Camera preview needs a SurfaceView in order to work properly. From the official docs:

the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.

Google Maps v2 use SurfaceView too (look here), so basically you have two SurfaceView instances one on top of the other, and you simply can't apply a gradient mask in order achieve what you want, because you have no control on how each widget draws itself:

  • Camera preview SurfaceView receive camera buffer and render it natively
  • Maps SurfaceView is rendered in another process.

Furthermore, using two instances of SurfaceView together is highly discouraged like stated here:

The way surface view is implemented is that a separate surface is created and Z-ordered behind its containing window, and transparent pixels drawn into the rectangle where the SurfaceView is so you can see the surface behind. We never intended to allow for multiple surface views.

I think the only option you have is to choose only one of them to be live/interactive and draw the other as a static image gradient on top of it.


EDIT

In order to validate further my previous statements, below a quote from official docs about Camera usage:

Important: Pass a fully initialized SurfaceHolder to setPreviewDisplay(SurfaceHolder). Without a surface, the camera will be unable to start the preview.

So you are forced to use a SurfaceView in order to get the preview from Camera. Always.
And just to repeat myself: you have no control on how those pixels are rendered, because Camera writes directly the framebuffer using the preview SurfaceHolder.

In conclusion you have two fully-opaque SurfaceView instances and you simply can't apply any fancy rendering to their content, so I think such effect is simply impractical in Android.

like image 196
a.bertucci Avatar answered Nov 15 '22 17:11

a.bertucci