The goal is to create a composite shape and add an emboss effect. I can successfully create the shape as illustrated below.
woodPaint = new Paint();
woodPaint.setAntiAlias(true);
woodBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.wood);
woodShader = new BitmapShader(woodBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
woodPaint.setShader(woodShader);
...
#Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(handleX, radius, radius, woodPaint);
canvas.drawRoundRect(baseRectF, 25, 25, woodPaint);
super.onDraw(canvas);
}
Image:
Then I add an EmbossMaskFilter
paintEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.1f, 8f, 5f);
woodPaint.setMaskFilter(paintEmboss);
Image:
As you can see the emboss mask is applied to the two shapes separately. How can I compose the shapes together and apply the emboss to the entire object? I've tried setting the xfer mode to some flavor off porter duff but this doesn't effect the fact that the emboss mask is applied to each shape separately.
Thanks for any help!
Edit:
As illustrated by Orabîg, you must draw one path with the paint that you've set an emboss filter on. NOTE: the method setMaskFilter() is one of the handful of methods that don't work when hardware acceleration is turned on. I resolved an issue I was having with a phone running jelly bean by disabling hardware acceleration for the activity. You can disable hardware acceleration at any level you choose:
ApplicationActivityWindowView
Cheers!
Well, you need only one emboss effect, so you should ony draw one shape.
So you should use the Canvas.drawPath() method.
You'll just have to define a Path object, with the following methods :
Start by defining 3 RectF objects, which will be the bounding boxes of the left-most round (imagine the circle behind it), the right-most one, and the sliding one :
You'll maybe have to do some additional maths to determine the correct angles to use for box2 (they depend on the respective size of the circle and the whole rectangle)
Good luck !
Related
Imagine that I have a rectangle image. How could I create a style like the next one?
I mean, cropping the image into a circle, add the border, the shadow and the gross /shine effect. Until now, I only have tried this snippet code to crop the image: Cropping circular area from bitmap in Android but just that. I have no idea how to do the remaining components in Android.
An easy way to achieve this effect is to use Canvas.drawCircle() and a BitmapShader:
BitmapShader s = new BitmapShader(myPhoto, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint p = new Paint();
p.setShader(s);
myCanvas.drawCircle(centerX, centerY, radius, p);
To do the shadow, simply call Paint.setShadowLayer() on the paint (this will only work if you draw the effect into an offscreen Bitmap or if your View uses a software layer – set by calling View.setLayerType() –).
The border can be drawn by drawing another circle on top, using the Paint.Style.STROKE style (that you can set by calling Paint.setStyle()).
Finally you can draw the gloss by drawing a circle, oval or Path on top of your very first circle. You'll need to use a LinearGradient shader on your paint and you'll also need to clip the gloss. You can do this in two ways:
If you are drawing the entire effect into a Bitmap, which is what I would recommend, simply set the paint's Xfermode to a new PorterDuffXfermode(PorterDuff.Mode.SRC_IN).
If you are drawing the effect directly on screen you can simply use Canvas.clipPath() to set a circular clip. Note that this will work with hardware acceleration only as of Android 4.3.
I want to draw something similar to this shape on android canvas:
I think the best way is to define this shape as the intersection of 2 circles and a line. What's the proper way to create this with android canvas?
UPDATE
I am now using PorterDuff as smith324 suggested:
*Note: code slightly simplified for clarity.
darkPaint = new Paint();
darkPaint.setColor(Color.rgb(50, 50, 50));
lightPaint = new Paint();
lightPaint.setColor(Color.rgb(200, 200, 200));
atopPaint= new Paint(GameDrawingPanel.darkPaint.getColor());
atopPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
atopPaint.setAntiAlias(true);
atopPaint.setStrokeWidth(2);
_boardCanvas.drawCircle(x, y, radius, darkPaint);
_boardCanvas.drawCircle(x, y, radius_small, lightPaint);
_boardCanvas.drawRect(0,0,height,width,atopPaint);
I forget exactly which modes would be of use here (XOR should work), but essentially you need to use a PorterDuff transfer mode to achieve this. Try drawing the concentric circles atop one another, then a dividing rectangle on one side.
http://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
http://www.svgopen.org/2005/papers/abstractsvgopen/
I'm trying to create a 'glow' effect using the Android Path class. However, the gradient is not being warped to fit around the path. Instead, it is simply being display 'above' it and clipped to the path's stroke. Using a square path, the image below shows what I mean:
Instead, that should look more like this:
In other words, the gradient follows the path, and in particular wraps around the corners according to the radius set in the CornerPathEffect.
Here is the relevant part of the code:
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(20);
paint.setAntiAlias(true);
LinearGradient gradient = new LinearGradient(30, 0, 50, 0,
new int[] {0x00000000, 0xFF0000FF, 0x00000000}, null, Shader.TileMode.MIRROR);
paint.setShader(gradient);
PathEffect cornerEffect = new CornerPathEffect(10);
paint.setPathEffect(cornerEffect);
canvas.drawPath(boxPath, paint);
Any ideas?
Another alternative is to get a 'soft-edged brush' effect when defining the stroke width. I've experimented with BlurMaskFilters, but those give a uniform blur rather than a transition from opaque to transparent. Does anyone know if that's possible?
How about drawing with a soft brush bitmap? Make a soft circular brush with opacity decreasing radially outward using image editing software like Photoshop. Save as drawable, load it in a bitmap and draw it evenly spaced along your path. Make the bitmap with white coloured brush. This way you can simply multiply the given colour(Here blue) to your bitmap using PorterDuffColorFilter.
brush1=BitmapFactory.decodeResource(getResources(), R.drawable.brush_custom_one);
//This contains radially decreasing opacity brush
porter_paint.setColorFilter(new PorterDuffColorFilter(paint.getColor(), Mode.MULTIPLY));
for (int i=1;i<matrix.size();i++) {
//matrix contains evenly spaced points along path
Point point = matrix.get(matrix.get(i));
canvas.drawBitmap(brush1, point.x,point.y, porter_paint);}
The brush used is (It's there):
The final result is:
Turns out there was a stupidly obvious way of doing this. Simply re-use the same path, and adjust the stroke width and alpha on each drawing pass. Example code:
float numberOfPasses = 20;
float maxWidth = 15;
for (float i = 0; i <= numberOfPasses; i++){
int alpha = (int) (i / numberOfPasses * 255f);
float width = maxWidth * (1 - i / numberOfPasses);
paint.setARGB(alpha, 0, 0, 255);
paint.setStrokeWidth(width);
canvas.drawPath(path, paint);
}
See below for an example of the result. The left path was drawn using this method, the right path, for comparison, is drawn in a single stroke with maxWidth and 255 alpha.
This mainly works. There are two problems:
The gradient isn't as smooth as it could be. This is because each pass being drawn over the previous one results in the alpha building up too quickly, reaching 255 before the final strokes. Experimenting a bit with the line int alpha = (int) (i / numberOfPasses * 125f); (note the change to 125f rather than 255f) helps.
The path looks like it has been 'cut' on the insides of the corners. Probably some result of the CornerPathEffect applied.
What you're wanting to do, if I understand it right, is to have the gradient effectively form a "brush" for the stroke.
This is exactly what I also was trying to achieve recently, but as far as I can tell the API doesn't provide any straightforward means to do it. I have recently created an SVG to Android Canvas converter class and so I am working a lot in Inkscape lately, too. So, when I was looking into it, I wondered if it's even possible to do it in Inkscape. However, even in Inkscape it's a very non-trivial thing to do. After some searching I eventually came across this image of a gradient being applied along the course of a path, together with a download link for a tutorial beneath:
http://www.flickr.com/photos/35772571#N03/3312087295/
What I was personally trying to do at the time was to create some semi-circles where the path is a kind of neon glow as opposed to a flat colour. Talking in terms of both the Android API and the SVG standard, it seems that the only way to to do this is to create a radial gradient that's centred perfectly on the circle, and position a series of color stops in exactly the right places. Pretty tricky to do, and I certainly don't know how you'd do it to a shape like a square.
Sorry that this is a bit of a 'I couldn't do it either' rather than a useful answer! I'll follow this with interest as I'm eager to know a solution for a kind of 'soft brush' effect too.
Can be very complicated to draw a gradient than follow a path.
So I suggest you to use some library already done than make it for you.
One can be Sc-Gauges.
Have some usefully classe than you can use for your goal.
For first include the library:
dependencies {
...
compile 'com.github.paroca72:sc-gauges:3.0.7'
}
After create an image or what you want with a canvas where draw:
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Now the code:
// Dimensions
int padding = 24;
Rect drawArea = new Rect(padding, padding, 700 - padding, 500 - padding);
// Get the main layout
ImageView imageContainer = (ImageView) this.findViewById(R.id.image);
assert imageContainer != null;
// Create a bitmap and link a canvas
Bitmap bitmap = Bitmap.createBitmap(
drawArea.width() + padding * 2, drawArea.height() + padding * 2,
Bitmap.Config.ARGB_8888
);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.parseColor("#f5f5f5"));
// Create the path building a bezier curve from the left-top to the right-bottom angles of
// the drawing area.
Path path = new Path();
path.moveTo(drawArea.left, drawArea.top);
path.quadTo(drawArea.centerX(), drawArea.top, drawArea.centerX(), drawArea.centerY());
path.quadTo(drawArea.centerX(), drawArea.bottom, drawArea.right, drawArea.bottom);
// Feature
ScCopier copier = new ScCopier();
copier.setPath(path);
copier.setColors(Color.RED, Color.GREEN, Color.BLUE);
copier.setWidths(20);
copier.draw(canvas);
// Add the bitmap to the container
imageContainer.setImageBitmap(bitmap);
And this the result:
The first part of the code is just for create a bitmap where draw.
What you interest is the second part where use ScCopier.
Just give the path, the color and the with.
Note than is you are inside a view you can use onDraw for draw directly on the view canvas.
This library can used to create gauge of every kind.
If you want take a look to this site ScComponents have some free and not gauges components.
What algorithm or technique should I use to make an object follow the path that the user's drawing on the screen?
The below example creates a PATH for displying TEXT on Circle Path:
// create a path
Path circle = new Path();
circle.addCircle(centerX, centerY, radius, Direction.CW);
// set the color and font size
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setTextSize(30);
paint.setAntiAlias(true);
// draw the text along the circle
canvas.drawTextOnPath(QUOTE, circle, 0, 30, paint);
You can refer full Example Here
And For Animation, There are mainly 4 Types of Animations comes up with Android SDK:
AlphaAnimation – transparency changes
RotateAnimation – rotations
ScaleAnimation – growing or shrinking
TranslateAnimation – position changes
For CREATING ANIMATION SEQUENCES, refer Example Here.
For Different Types of Animations Example such as Frame Animation (As in Flash), List Animation,etc. You can refer Animations Types EXample here .
Enjoy!!
I was just working on this in the last couple weeks for a game--how I did it was by getting each point from coordinates given by the touch event (when the user is drawing it to the screen) and then adding that to a list. I turned that list into a path to draw to the screen, and then just had the object update its location based on the list in the onDraw method for each frame.
How do you create an animated dashed or dotted border of an arbitrary shape in Android? In XML (preferred) or programmatically.
See picture below for an example.
Have you seen the PathEffects API demo?
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/PathEffects.html
It produces precisely an animated line and you can just adjust the path to the edge of your view to create a border. For example:
Define a path by your view parameters / arbitrary shape:
Path path = new Path();
path.addRect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), Path.Direction.CW);
Then create a dashed PathEffect with:
PathEffect pe = new DashPathEffect(new float[] {10, 5, 5, 5}, phase);
Then set the associate it with a Paint object and draw:
mPaint.setPathEffect(pe);
canvas.drawPath(path, mPaint);
EDIT: The animated effect comes from continuously changing the phase and redrawing. In the API demo it calls invalidate() in the onDraw() method (which triggers onDraw()...)
XML... I guess not possible. But you can use a custom view or a SurfaceView and handle the drawing by yourself. Have fun with that :)
Could you use some form of two 9patch images as a background frame around the image file you want to present, one in each of two layouts. The images would differ in terms of the placement of the dashed elements. Interchange the views rapidly (might need a delay) and you might get the effect you want. Don't really know how effective that would be though in terms of being able to let the user continue using the app and chewing battery...