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.
Related
I have a custom view extends form TextView,and write some code in onDraw():
#Override
protected void onDraw(Canvas canvas) {
if (mTextShader == null) {
createShader();
}
shaderMatrix.setTranslate(mProgressWidth,0);
mTextShader.setLocalMatrix(shaderMatrix);
Paint paint = new Paint();
paint.setShader(mBgShader);
canvas.drawRect(0,0,mProgressWidth,getBottom(),paint);
getPaint().setShader(mTextShader);
super.onDraw(canvas);
}
It looks like this:
enter image description here
Just set some shader,and draw a rect,it works fine if I don't use
android:gravity="center"
and
android:singleLine="true"
together,(just one of them is pretty good,)
if only use this property,these shaders and rect are gone!
why?
Before you draw in the canvas, translate the scrolled XY distance
canvas.translate(getScrollX(), getScrollY());
canvas.drawRect(0,0, getWidth(), getHeight(), borderPaint);
your super.onDraw(canvas); should be first line otherwise parent will paint on top of your drawing. also call this setWillNotDraw(false) in your constructor.
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 have 3 ImageViews. 1st and 2nd connected with red line. Also I have simple button. Here is a picture:
I want to connect 2nd & 3rd ImageViews with new Path line and change the first line color (for example to Green) when i clicking my button. Here is parts of my code:
public class SkillPath extends View {
Paint paint;
Path path;
... constructors
#Override
protected void onDraw(Canvas canvas) {
addPath (canvas);
}
//Here is my RED line
void addPath (Canvas canvas){
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
path.moveTo(110, 110);
path.lineTo(210, 110);
canvas.drawPath(path, paint);
Log.d ("Page 2","onDraw");
}
I can get all coordinates of all Views, but how can I redraw existing canvas? I suspect, I need to use invalidate(), but I do not know enough to do this. Need help.
The invalidate() method forces the View to be re-drawn.
So just apply the modification you need on your canvas and call invalidate() on the related View after these modifications.
I'm extending LinearLayout:
public class MyLinearLayout extends LinearLayout {
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
}
If the layout has child elements, shouldn't the red line above be drawn on top of them? Considering a layout like:
<MyLinearLayout>
<ImageView />
</MyLinearLayout>
I'd expect to get the red line drawn above the child ImageView. But it gets drawn below it. I was assuming all child drawing would have been completed after the super.onDraw() line is finished.
Is there a way to get to the canvas and draw something on it after all child drawing has been completed?
Thanks
Layouts don't draw unless you call setWillNotDraw(false);. They do that for efficiency reasons.
EDIT:
onDraw() really is meant to just allow you to modify the Canvas before the drawing operation happens. It doesn't actually draw. What you want to do is override draw() like so:
#Override
protected void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
Calling the super will draw all the children in the view. Then it will draw all the lines. I do still believe you need setWillNotDraw(false) to be called though.
I'm rewriting my answer as I hadn't seen your line of code where you were drawing to the canvas.
The canvas like some other graphics environments is inverted. So calling getHeight() is actually drawing the line at the bottom. Instead call
canvas.drawLine( 0, 0, getWidth(), 0, paint);
This means draw the line at the top, across the width of the view.
Also, calling super first paints the children prior to any custom painting so your fine there.
If you have a LinearLayout and you need:
draw all of its children first, like buttons, image views
then, on top of those components, draw something directly on the canvas.
You can try this:
public class YourClass extends LinearLayout
{
#Override
protected void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
// do your custom drawings afterwards
canvas.drawCircle...
canvas.drawLine...
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);