I have developed a custom rounded LinearLayout and I want to add 1px border.
Here my code :
public class MyLinearLayout extends LinearLayout {
private float radius;
private Path path = new Path();
private RectF rect = new RectF();
public MyLinearLayout(Context context)
{
super(context);
radius = 20;
setWillNotDraw(false);
}
#Override
protected void onDraw(Canvas canvas) {
path.reset();
rect.set(0, 0, canvas.getWidth(), canvas.getHeight());
path.addRoundRect(rect, radius, radius, Direction.CCW);
// Add 1px border RED here ?
path.close();
canvas.clipPath(path);
}
}
Thanks for your help.
If you look closely at the rounded corners in your custom LinearLayout, you will probably see that the radius is not smooth. This is because there is a system limitation that does not support anti aliasing on Paths.
Here is a great tutorial from Erik Burke on how to properly create Views with rounded corners. Basically you will create an off-screen Bitmap, draw a RoundRectangle, and use an alpha compositing technique to merge the off-screen Bitmap with the custom LinearLayout Canvas' Bitmap.
As far as a border, you can can draw it by setting Paint.Style.FILL_AND_STROKE to the Paint.
Related
I'm using a simple custom view which draw a path and clip its children.
Code used :
private void config() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setShadowLayer(10.0f, 4.0f, 4.0f, DARK)
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(20);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
circlePath.reset();
circlePath.addCircle(cx, cy, circleRadius, Path.Direction.CW);
canvas.drawPath(circlePath, paint);
canvas.clipPath(circlePath);
super.dispatchDraw(canvas);
canvas.restore();
}
The path is fully transparent with only a white stroke. If there is no child inside this view container everything is fine.
Empty path :
Problem : I have noticed when a child is clipped, it seems that pixels appears around the white stroke, and only inside the path
Path with a black clipped children inside:
I zoomed and resized screenshots to better understand but also in real size pixels are visible.
I tried without shadowLayer but there is still pixels
Could someone tell me what is the problem source and how to fix it ?
I am trying to create a hollow circle and then put image inside it. I have imageview statically in my XML file. But the hollow circle I am creating is dynamically with the use of Paint class.
The issue is I can draw both and are visible but when I put hollow circle over image it overlaps imageview and image is not visible.
Another issue is I do not know how to put both of them in center of layout.
Here is my java code snippet
RelativeLayout rl = (RelativeLayout) findViewById(R.id.panel);
Circle view = new Circle(MyActivity.this);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
rl.addView(view);
Code to draw circle
private class Circle extends View {
public Circle(Context context) {
super(context);
}
#Override
public void draw(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setColor(Color.BLACK);
canvas.drawCircle((int) (500), (int) (430),
320, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawCircle((int) (500), (int) (430),
300, mPaint);
}
}
Can anybody help to define both image inside this circle in Center I know it need to pass x, y coordinates while drawing circle here but how to know center(x,y) - radius coordinate for circle. Thanks
I'm trying to implement a custom drawable which should have the shape of a speechbubble. Therefore I use two paths, one draws the rect and the other should draw the triangle for the bubble.
My class looks like the following:
public class SpeechBubbleView extends Drawable {
private Paint mBubblePaint;
private Paint mBubblePaint2;
private Path mRectPath;
private Path mBubblePath;
public SpeechBubbleView() { }
public void initPaint() {
mBubblePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBubblePaint.setStyle(Paint.Style.FILL);
mBubblePaint.setColor(Color.GREEN);
mBubblePaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
mBubblePaint2.setStyle(Paint.Style.FILL);
mBubblePaint2.setColor(Color.RED);
int width = getBounds().width();
int height = getBounds().height();
mRectPath = new Path();
mRectPath.addRoundRect(new RectF(0, 0, width, height), 8, 8, Path.Direction.CW);
mRectPath.close();
mBubblePath = new Path();
mBubblePath.moveTo(50, height);
mBubblePath.lineTo(100, height + 50);
mBubblePath.lineTo(150, height);
mBubblePath.close();
}
#Override
public void draw(Canvas canvas) {
if(mRectPath == null && mPathValues == null) {
initPaint();
}
canvas.drawPath(mRectPath, mBubblePaint);
canvas.drawPath(mBubblePath, mBubblePaint2);
}
#Override
public void onBoundsChange(Rect bounds) {
Rect customBound = new Rect(0, 0, bounds.width(), bounds.height() + 50);
super.onBoundsChange(customBound);
}
The problem now is, that I take the width and height from the drawable to draw the rect of the speechbubble. The full space of the canvas is taken and there is no more room for the triangle to display below the rect.
My question now is: Is it possible to change the size of canvas or the drawable, so that I am able to display the small triangle below the rect?
I already tried the method onBoundsChange, but it takes no effect. In the draw-method the size is still the same.
If possible, it would be nice to change the size directly in the custom drawable class, shown above, because I do not have the size of the view, when I call it. Also I cannot make the size of the rect smaller, because in the drawable there is content and if the rect is smaller, some of the content will be outside of the drawable. I use a drawable, so that I can simple call setBackgroundDrawable of my layout or TextView and it matches always the content size.
If anyone of you got an idea on how to do the size change, this would be very great. Thank you :D
I'm just getting into basic drawing with Android. I'm starting off with a few simple shapes but I'm having a few issues. I'd like to draw a circle at the center of a canvas. I looked at a few examples but can't seem to make it work. I think it's because I don't really understand what variables go where.
Could someone please explain the proper way to draw my circle at the center of my screen. Here is my code:
public class Circle extends View{
int width = this.getWidth();
int height = this.getHeight();
public Circle(Context context) {
super(context);
setFocusable(true);
}
protected void onDraw(Canvas canvas){
canvas.drawColor(Color.CYAN);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
//canvas.drawCircle(100, 100, 50, paint);
canvas.drawCircle(width/2, height/2, 100, paint);
Display disp = ((WindowManager)this.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
float radius = 0;//Radius caused an error so I initialized this variable
canvas.drawCircle(disp.getWidth()/2, disp.getHeight()/2, radius, paint);
}
}
width and height of the view have not been yet initialized when getWidth() and getHeight() are called, just use getWidth() and getHeight() in onDraw:
canvas.drawCircle(getWidth()/2, getHeight()/2, 100, paint);
You can also override onSizeChanged and get view width and height.
PS: do not create anything in onDraw, create the paint object in the constructor.
public void drawCircle(Graphics2D g, int x, int y, int radius) {
x = x-(radius/2);
y = y-(radius/2);
g.fillOval(x,y,radius,radius);
}
here x,y is the position of canvas where you want to draw circle and you can find it with motion listener if you want to set x,y position dynamically hope this will help you
There are some links which are very useful for us and I hope they will work for you and other.
https://github.com/swapgo20/Android-Hand-Drawing
https://github.com/codepath/android_guides/wiki/Basic-Painting-with-Views
https://github.com/Korilakkuma/CanvasView
I hope above links are very useful to draw shapes on canvas.
I suggest you use third link and use only Path class (http://developer.android.com/reference/android/graphics/Path.html) of android to draw shapes.
I need to make a thumbnail view with rounded corners and inner shadow. Usually I'm making ImageView frames with 9patches, which have served me well so far, but this time the effect I need requires drawing the inner shadow on top of the image (and not just around it). This lead me to extend the ImageView class and override the onDraw() method.
public class ThumbnailImageView extends ImageView {
After many tutorials (thanks StackOverflow!), I ended up with this code for the onDraw() method:
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
int radius = 4;
int padding = 2;
int bleed = 2;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
canvas.drawRoundRect(frame, radius, radius, mPaint);
Shader bitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
mPaint.setMaskFilter(new BlurMaskFilter(bleed, Blur.INNER));
mPaint.setShader(bitmapShader);
canvas.drawRoundRect(frame, radius, radius, mPaint);
}
What I'm basically doing, is drawing a black rounded rectangle first and then drawing a rounded-corners bitmap with fading edges (with the BlurMaskFilter) on top of it. The result is what I want:
The mBitmap value is initialized in the ImageView constructor like this:
mDrawable = getDrawable();
if (mDrawable != null) {
mBitmap = ((BitmapDrawable) mDrawable).getBitmap();
}
The problem is that I am overriding onDraw() completely (no super.onDraw()) is called, so I have to pre-scale all images to the desired thumbnail size (e.g. 96x96) or else only the top-left corner of the image is drawn. What I want to be able to do is take advantage of all the scaling the framework is doing when I assign the following xml values to the ThumbnailImageView:
android:id="#+id/thumb"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
To do this, I thought I should somehow call super.onDraw() while getting the effects I need at the same time. I have managed to get the rounded rectange by adding a clipping path to the canvas, but I can't find a way to add the inner shadow. This is the new onDraw() code:
#Override
protected void onDraw(Canvas canvas) {
int radius = 4;
int padding = 4;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
Path clipPath = new Path();
clipPath.addRoundRect(frame, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
// add inner shadow
}
I can see two alternatives:
1) To properly pre-scale the ImageView's bitmap. But where is the best place to do it? In it's constructor? In the onDraw() method where the framework seems to be doing it? Is the framework even resizing any bitmap or is there another way to draw a scaled image on the canvas without being bad for performance?
2) To add the inner shadow layer on top of what the super.onDraw() is drawing so far, but I'm running out of ideas on how to do this.
Any help would be appreciated.
Thanks!
Take a look at Eric's (from squareup) presentation material from Oreilly's AndoridOpen Conference last year in his lecture titled Beautiful Android
It has a ton of info that should help you out.
I wish they had the video of his presentation somewhere. I could not find it. So sorry.
EDIT : Thanks to #mykola for the yt link