I am using the onDispatchDraw(Canvas canvas) method to draw lines in my view. When I call canvas.drawLine() it always draws the line on top of all my views. Is there any way to draw the line under a button but on top of another view in my layout using canvas.drawLine()?
I have tried the following but it still draws the line over the button.
Button b;
RelativeLayout r;
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
Paint p = new Paint();
p.setColor(Color.Black);
canvas.drawLine(0,0,100,100,p);
r.removeView(b);
r.addView(b);
}
You're trying to reinvent the wheel. Z-ordering is already implemented in the window management subsystem and you can use it.
Create a custom view you want to draw on.
Make it non-clickable using android:clickable="false" or setClickable(false).
Make its background transparent and implement dispatchDraw().
Put all the views you don't want to draw on above this view in the view hierarchy.
Call super.dispatchDraw() after drawing the line. The dispatchDraw is called by viewgroup for drawing its children, so in your case, calling super.dispatchDraw() will draw the button first then you are drawing the line over it. Do dispatchDraw this way :
Updated code
class myListViewWithLine extends ListView {
....
#Override
protected void dispatchDraw(Canvas canvas) {
Paint p = new Paint();
p.setColor(Color.Black);
canvas.drawLine(0,0,100,100,p);
super.dispatchDraw(canvas);
}
....
}
Another method will be to just add a view with 1 dip as height and background color whatever you like under the button. It should look like like a line.
View v = new View(this);
ViewGroup.LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT,1);
v.setLayoutParams(lp);
v.setBackgroundColor(Color.WHITE);
addView(v,INDEX NUMBER AFTER THE BUTTON);
Related
I have custom ViewGroup with 2 child views, matched to parent, and one on another, one is front and one is behind. I wanted to cut out circle in front view so behind view would be visible in that circle.
I did it with dispatchDrawfunction, code is following:
protected void dispatchDraw(Canvas canvas) {
System.out.println("dispatchDraw");
views.get(1).setVisibility(GONE); //views variable is list of child views
super.dispatchDraw(canvas);
Path pathHole = new Path();
pathHole.addCircle(touchPos[0], touchPos[1], 100, Path.Direction.CW);
canvas.clipPath(pathHole, Region.Op.DIFFERENCE);
views.get(1).setVisibility(VISIBLE);
super.dispatchDraw(canvas);
}
Basically what I did is hide front view and draw the ViewGroup (it drew only behind view),then I cut a circle path, set Visibility of front view and redraw again.
Here is the result:
Problem is dispatchDraw function goes on the loop because .setVisibility() calls this dispatchDraw again.
How to fix this problem or what would be the better approach of this result?
I managed same result with view.draw(canvas); function. Instead of adding views on ViewGroup I saved them in ListArray. then in dispatchDraw did following:
protected void dispatchDraw(Canvas canvas) {
System.out.println("dispatchDraw");
views.get(0).measure(canvas.getClipBounds().width(), canvas.getClipBounds().height());
views.get(0).layout(0, 0, canvas.getClipBounds().width(), canvas.getClipBounds().height());
views.get(0).draw(canvas);
Path pathHole = new Path();
pathHole.addCircle(touchPos[0], touchPos[1], 100, Path.Direction.CW);
canvas.clipPath(pathHole, Region.Op.DIFFERENCE);
views.get(1).measure(canvas.getClipBounds().width(), canvas.getClipBounds().height());
views.get(1).layout(0, 0, canvas.getClipBounds().width(), canvas.getClipBounds().height());
views.get(1).draw(canvas);
}
I tried this before, but I did not know that .draw(canvas) does not work without .measure() and .layout() functions, if it has not parent and is not visible already.
I made a code where a circle moves around, but whenever it moves in front of a textview, the textview gets in front of him and I want him to be in front of the textview.
I tried drawing the circle after making the textview but it doesn't fix it.
Example:
public MainView(Context context) {
super(context);
}
public void onDraw(Canvas canvas){
((ViewGroup) text.getParent()).removeView(text);//the text was already added to the activity
Paint paint=new Paint();
paint.setColor(Color.WHITE);
canvas.drawCircle(0.0,0.0,500.0, paint);
main.addContentView(text, parameters);//adding a textview named text in the activity
invalidate();
}
Don't create Views inside onDraw, it's called so many times and you will have a lot of TextViews but you only need one, normally created on activity onCreate.
The TextView seems in front due the children is clipped when drawing, try setting clipChildren to false in the ViewGroup container
I have a ViewGroup that consists on a header and a circle of menu items. Basically I have a closing/opening animation where my item views go behind the header view. Since all views have transparencies, when the item views go behind the header view, they are still visible and end up appearing behind the header view through the transparencies.
What I wanted to do is to intersect the item views with the hweader view, erasing the intersection. What I came up with was to override dispatchDraw and do something like PorterDuff.Mode.CLEAR
But I can only do this to all views at once, in the sense. Using the code below, it'll erase everything that's been drawn in the view in that specific area, thus the header as well.
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
//do stuff here
}
Is there any way i can draw the view again, or even select which views I want to erase?
Just for future reference, this is what I did. Override dispatch draw, erase the given area and draw the child again with child.draw(canvas)
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
Paint p = new Paint();
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawCircle((float) center.x, (float) center.y, headerSize / 2, p);
canvas.save();
canvas.translate(padding, padding);
getChildAt(0).draw(canvas);
canvas.restore();
}
I have a frame layout (full screen) that acts as a container for another frame layout which shows the camera preview. Now I want to show on top of the camera preview a circle of a given radius. The radius shall change as a function of some properties of the current preview image.
I know that I can add some (semi-transparent) layouts "on top" of the frame layout I use for the camera preview, but I am not sure how to best show this "overlay" circle. The circle shall be centered, have a solid line but not be filled, i.e. be transparent and also its background shall be transparent.
You can make your own View class inside your existing Activity class. Here is my class.
class CanvasView extends View {
private Paint paint;
public CanvasView(Context context){
super(context);
//Customize your own properties
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10f);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
paint.setColor(Color.RED);
canvas.drawCircle(enter coords and radius here);
}
}
You can call the onDraw method from within that class by calling the invalidate() method..
Here is how you can add it to your layout..
Assuming you declared a CanvasView class, called drawable, and have your Framelayout, called main_layout, you add it to your existing framelayout by doing...
CanvasView drawable = new CanvasView(getApplicationContext());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
main_layout.addView(drawable, params);
Hope this works!
I'm trying to draw a line over an ImageView but whenever I try it using Canvas, I have to reload the Bitmap, which is not my intention.
Is there a way to simply draw a line on an uploaded ImageView using Canvas without having to refresh the Image? Or another way to draw lines over Android ImageView?
Or, if you want to be able to draw any lines (rects, ovals, etc), subclass ImageView into your own ImageView and do the drawing yourself.
public class MyImageView extends ImageView {
Paint linePaint = new Paint();
#Override
protected void onDraw(Canvas canvas) {
super.onDraw();
// And draw your line.
// (Be sure to have set the values/fields in linePaint earlier so that you draw the correct line/type/size/etc).
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, linePaint);
}
}
And in your layout xml, don't specify <ImageView .../>, but specify <com.mycompany.project.widget.MyImageView ... /> instead.
The way that I draw lines in Android is by creating a View with height or width of 1dp. Then set the other value to whatever you want and set the color.