Custom view is losing some transparancy on each redraw - android

Each time my custom view is being redrawn it is losing more and more transparancy.
The code for creating the paint object:
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(Color.argb(100, 255, 71, 126));
It is drawn like this:
canvas.drawPath(myPath, p);
It worsk great the first time it is drawn, however each time it is being redrawn it is losing more and more of its transparancy.. (for example when navigating away then back to the view)
The custom view is infact a ViewGroup with this code set so that it will draw itself
setWillNotDraw(false);
Thanks

Are you clearing your view inbetween draws? Otherwise, you may be drawing on top of your previous result. Drawing a translucent color over another translucent color will result in something less translucent (well, depending on your Porter/Duff mode...).

Related

Clip content of ActivityView

i am implementing a custom launcher in Android, displaying 3rd party apps using ActivityViews.
I want to clip the content of these ActivityViews to a custom shape (other than Circle, Rectangle, RoundedRectangle, Ring...).
I already tried to call clipPath/drawPath on the dispatchDraw canvas of a parent viewgroup element which works fine for all children except the ActivityView. Even the ActivityView itself and its referenced SurfaceView seem to be clipped according to my given path (if i add a solid color for testing). But the rendered content remains unchanged. Manipulating the SurfaceView canvas (which you receive by calling getHolder().lockCanvas()) doesnt have any effect, too.
I think this has something to do with the virtualdisplay and/or various SurfaceControls which are used by the ActivityView, but i dont have any clue how to set clipping areas/paths for those classes.
Does anyone have an idea how to solve this?
Hint: i cannot paint over the ActivityViews content as i want to display the system wallpaper in the transparent areas.
finally setting up the PorterDuffXfermode correctly solved the issue. Just overwrite the dispatchDraw method of the parent viewgroup and erase the required areas using PorterDuff.
Sometimes it looks like the direction does matter how the path for drawPath is created (CW or CCW). So maybe try both.
Unfortunately this approach does not work if the hosted activity uses a SurfaceView on its own.
protected void dispatchDraw(Canvas canvas) {
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(getContext().getColor(android.R.color.white));
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
int save = canvas.save();
super.dispatchDraw(canvas);
canvas.drawPath(path, p);
canvas.restoreToCount(save);
}

Android view clipping/subtracting

Is there any way in Android (from API 15) to clip/subtract views like masking in photoshop?
See the example below:
https://s31.postimg.org/d18lktjq3/index.jpg
The Red view is just a bold funny V shape, while the blue one is something more complex.
Note that in the red view, the striped part is transparent.
The result view i would like to obtain, is something like the blue big view, with the V shape of the second view, and anything above cut away.
Note that, in the final result, the space "inside" the V shape must be transparent.
Currently i achieve this effect using the two views one on top of the other (filling the gap in the V shape view), but this is not optimal because i have to know exactly what the other view is, and the summed up view is bigger than the source.
Thank you
In Android, this is done using Porter-Duff Transfer Modes.
Your best best for this is to have two overlay bitmaps: One that has the red V-shape, and a complementary bitmap that represents everything you want to cut out of the lower layer.
With a custom view, you override onDraw() to do these steps:
Draw the base (blue) bitmap
Draw the red stripe using Porter-Duff mode SRC_OVER
Draw the top V cutout using Porter-Duff mode CLEAR
Code would look something like this (assuming you have created the bitmaps and computed the x,y coordinates where you want to draw them):
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(blue_base, blueX, blueY, paint);
// draw the red v on top of the blue part
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
canvas.drawBitmap(red_v, redX, redY, paint);
// erase the unwanted pixels from the blue part
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawBitmap(cut_out, redX, redY, paint);
Here's an interesting tutorial to get you started: Punch a hole in a bitmap by using Android's porter-duff Xfer - TechRepublic

Fill a canvas with a transparent color in Android

Good Morning,
I have an ImageView that I initialized with #99aaaaaa color (it corresponds to 153,170, 170,170). after that I draw some lines with different colors. and Now I want to Fill my Canvas with the original color (#99aaaaaa).
The method myCanvas.drawColor(OriginalColor) fills the canvas with OriginalColor, but the lines still visible
myPaint.setColor(OriginalColor);
myPaint.setStyle(Paint.Style.FILL);
myCanvas.drawRect(0, 0, 170, 170, myPaint); // my ImageView is 170X170
Also let lines visible.
Any help please, Thank You
as the canvas original color is semi transparent, then you draw something on it and draw another layer of semi transparent stuff, then its pretty obvious youll see the level-down-layer through the top transparent layer isnt it? another words, if you place a half transparent glass on your knees, ull still see the knees through it
Set the transfer mode as follows, before calling drawRec():
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
Reset the painter afterwards, for further drawing:
paint.setXfermode(null);
paint.setColor(0xFFFFFFFF);

Creating a "cut out" layout

Right now, I have it so that my layout consists of a Fragment that takes up the entire screen and displays an image. I want to make it so that an additional View exists on top of it, also taking up the entire screen. On that top layer, I want to be able to color it all black initially, and then create certain spots that are transparent (alpha?) and reveal the image displayed on the fragment behind it. So basically the screen will be all black except for a few spots where the image behind is showing through, which I would determine programmatically. I've looked into a bunch of the graphics and views that Android provides, but have no clue where to start. Is this suited for a SurfaceView if I just want it to be all black with some spots of alpha?
Once I select the correct view to use, I'm assuming that I just override the onDraw() method and then do something like canvas.setBody(black) and then add shapes of alpha to it? Will the shapes correctly affect the background color?
For your masking View, you can make a custom view that can keep track of which areas to unmask (as Rects or something similar) and then draw them in onDraw(Canvas) like this:
public class MaskView extends View {
private Set<Rect> mRects = new HashSet<Rect>();
private Paint mUnmaskPaint = new Paint();
{
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
/**
* Add an unmasking rectangle to this view's background.
*
* #param rect
* a rectangle used to unmask the background
*/
public void addUnmaskRect(Rect rect) {
mRects.add(rect);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
for (Rect r : mRects) {
canvas.drawRect(r, mUnmaskPaint);
}
}
}
Your Fragment (or whatever is keeping track of the unmask areas) passes Rects to MaskView via addUnmaskRect(Rect). Whenever the view is redrawn (remember to call invalidate() each time you are done passing Rects) it is first filled with black, and then has any rectangles unmask the black background. The coordinates for your rectangles must be set to the coordinate space of the view, but if the underlying image occupies the exact same area it should be relatively simple (you can also look at the View.getLocationInWindow(int[]) method to help you with this as well).

Gradient appears banded in a SurfaceView, but looks very smooth in a normal View

My problem is that when drawing a simple test image (a rectangle with a gradient fill) within a SurfaceView, the gradient has colour banding. When drawing exactly the same rectangle with the same gradient in a simple extended View, the gradient looks very smooth, and as nice as I would expect for 32-bit colour.
This is occurring side by side using the test SurfaceView placed alongside the test View within the same layout in the same Activity.
For information, in the Activity class I am calling window.setFormat(PixelFormat.RGBA_8888) to switch the Activity to 32-bit colour, as this was the solution in the past to eliminate banding in gradients (however, I believe that this is no longer necessary at a certain Android level, where 32-bit is the default). My minSdkVersion is 8.
The test code that appears in the onDraw() of both the simple extended View and the SurfaceView is:
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(false);
Shader shader = new LinearGradient(
0,
0,
0,
200,
new int[]{0xff150d2f,0xff432b96},
null,
Shader.TileMode.CLAMP
);
paint.setShader(shader);
canvas.drawRect(0,0,getWidth(),getHeight(), paint);
Here is the screenshot showing the SurfaceView above and the normal View beneath. I realise that the banding is very subtle in this example; it's even more apparent when the gradient sweeps over a smaller band of colours.
Any suggestions, please?
Trev
Found the solution myself in the end by adding this into the SurfaceView's constructor:
getHolder().setFormat(PixelFormat.RGBA_8888);

Categories

Resources