I am drawing custom ovals using canvas in Android as follows. In fact, each shape is a view and created with the help of RecyclerView. When I click any shape, I draw another oval with stroke attribute(white one).
What I want to do here is to remove previous border oval whenever I touch another shape and draw a border for it. Do you have any idea? Thanks.
Code for drawing a shape:
override fun drawOval(canvas: Canvas) {
canvas.drawOval(shapeRectF, shapePaint)
}
I suppose you have a list of models. In each model, you need to have filed isSelected: Boolean. When you need to draw stroke you set isSelected = true to the item you need and isSelected = false to the item you want to remove the previous border. Then set new data to the adapter.
In you ViewHolder draw stroke if isSelected == true
Related
I'm using a custom View to draw rectangles(which will have text inside them at a certain point) and I want to highlight each rectangle when selected, which will happen every few seconds when user selects a rectangle. Should I implement highlighted rectangle in onDraw or is there a way just to redraw each rectangle without redrawing the whole View? I was thinking of using "invalidate(rect)" but it's been deprecated.
I'm trying to be considerate of the cost of invalidating the whole View compared to just redrawing a rectangle.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(CellCoordinates cellCoordinate : mCoordinateCells) {
canvas.drawText(" ", cellCoordinate.getRect().exactCenterX(), cellCoordinate.getRect().exactCenterY(), cellPaint);
}
}
Using invalidate() and onDraw() is fine. Dirty rect is not really have effect on API21+
... In API 21 the given rectangle is ignored entirely in favor of an internally-calculated area instead. ...
Dirty rect is deprecated because of different drawing model in hardware accelerated views. Checkout this link for more information
Also, it seems your rectangles can be implemented as custom Drawables with states (selected and normal). It will not give you extra performance, but might help to divide and structure code for drawing. This might help
I am drawing a rectangle in the canvas on the first attempt and again I am attempting to draw one more rectangle at a different position. When I finally add them to LinearLayout I see the only 2nd rectangle, the first rectangle is lost.
Bitmap place = Bitmap.createBitmap(400,800,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(place);
DrawRect dr = new DrawRect();
dr.setLocation(10,10);
dr.draw(canvas);
dr.setLocation(10,80);
dr.draw(canvas);
ll.removeAllViews();
ll.addView(dr);
How do I make both the rectangles to be visible?
removeAllViews() will remove all view of LinearLayout.
You are adding view after removeAllViews() thats why you see 2nd rectangle only.
So remove thisll.removeAllViews(); line and run again.
I found the problem in the code, i should not use the same DrawRect object for drawing one more item, instead use the same but different DrawRect object does the magic.
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...).
I have a custom view. I create a fullscreen transparent overlay using full screen rectangle by calling this method in onDraw:
private void drawOverlay(Canvas canvas) {
canvas.drawRect(0, 0, this.getWidth(), this.getMeasuredHeight(), backgroundPaint);
}
My screen is now overlayed with transparent background I defined earlier.
Now, I want to draw a Drawable on the screen. A drawable can be have a transparent parts on it. It can be, for example a shape , defined like this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/transparent"></solid>
<stroke android:width="10dp" android:color="#ffff0716"/>
</shape>
Now I want to draw that drawable on the screen. I draw it using this method:
private void drawDrawableOverTargetView(Canvas canvas) {
Rect rect = new Rect(200, 200, 450, 400); //TODO
Drawable drawable = tutorial.getHighlightDrawable();
drawable.setBounds(rect);
drawable.draw(canvas);
}
The inner part of my oval is defined transparent in xml. When displayed, the inner part of the oval will be the overlay color, because the overlay rectangle is below it.
The question is: Is it possible to define that drawable should override the color of background rectangle, meaning that the inner part of it becomes transparent ? Is it possible to remove the part of overlay rectangle which is below my drawable?
I tried using
drawable.setColorFilter(Color.Transparent, PorterDuff.Mode.Clear);
But it doesn't seem to work :/
You're making it way harder than you need to. Canvases maintain what is on them in pixels not objects. When a part of that canvas is invalidated it calls all the draw code relevant there and asks for the new pixels. Just code it up so that it draws the way you'd like it to, and invalidate the area. It'll call up the draw routine again and put them in whatever order you draw them in.
The canvas doesn't recall the background color under objects because there's just pixels not objects. The only sense wherein there are objects is where you draw objections, which causes a rendering of that on the canvas. But you can't remove it. You can however declare the area where that object was drawn to be invalid and upon refresh have it not draw that object the next time draw gets called.
Just make sure you call up the stuff in the order you'd like, as what you'd like changes, have the code draw it in that order.
You can't change the stuff already on the screen after the fact except by one of the blending operations, the Porter-Duff operations simply deal with all the logical ways you can manipulate pixels on a screen. CLEAR for example will restore that area to pure transparent. Which is basically just clearing that section of the screen. There's no circle on the screen. You are writing transparent pixels to a set of pixels that looks like a circle. Don't do that. When you don't want that circle thing, declare the picture invalid and when it calls the draw routine again, do not draw that circle.
After they are drawn, you're modifying pixels not things.
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).