I have this class that extends View (it's in C# because I use Xamarin)
public class ScannerOverlay : View
{
public ScannerOverlay(Context context) : base(context)
{
//Initializing some values here
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
//Draw some stuff on the canvas
}
}
I create this view using: View v = new ScannerOverlay(context);
Now I want to add a button to this view. How do I do this? The view has no layout whatsoever so AddView() is not going to work. And from what I found it's not possible to draw a button on a canvas.
Fixed it by extending from RelativeLayout instead of View.
If (like in my case) the OnDraw Method is not getting called, set the following in the constructor: this.SetWillNotDraw(false);
Basically, you can't add a View to another View.
Hard Way: You can create a View as if it has many Views inside it, but you should draw them manually using Canvas and Paint, also handle the click based on touch location of that each "fake" View. So it will take you a lot of time. This is called Custom View.
Easy Way: You can add any View to a ViewGroup and any child of ViewGroup like FrameLayout, LinearLayout, and RelativeLayout with ViewGroup.AddView(view) function. This is called Compound View.
ViewGroup extends View so you directly get all features of View event though you extend ViewGroup. In this way you can add new View to CustomView directly.
public class ScannerOverlay : ViewGroup
{
public ScannerOverlay(Context context) : base(context)
{
//Initializing some values here
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
//Draw some stuff on the canvas
}
}
Related
By default, onDraw() isn't called for ViewGroup.
So I have a question: What happen when we set background drawable for the ViewGroup
onDraw() is inherited from View class since ViewGroup is subclass of View. So when you set Background on a ViewGroup, it works the same way as any other view. When you call setBackground on a view, it sets requestLayout flag to true and invalidates the view.
Also, Official documentation for View class states that:
If you set a background drawable for a View, then the View will draw
it before calling back to its onDraw() method.
You can see how it works in the source code of Android's View class
public void setBackgroundDrawable(Drawable d) {
...
{
requestLayout = true;
}
...
computeOpaqueFlags();
if (requestLayout) {
requestLayout();
}
mBackgroundSizeChanged = true;
invalidate(true);
}
If you look at documentation for invalidate(), you will find
public void invalidate () Invalidate the whole view. If the view is
visible, onDraw(android.graphics.Canvas) will be called at some point
in the future.
setBackgroundColor() and setBackgroundResource() use setBackgroundDrawable() internally so they work the same way.
So to sum it up, onDraw is called at some point in future when you do setBackground().
I am drawing different view in a custom view with canvas, and want to add custom animation to on of the view (infinite bounce) not sure how this can be achieved. Would appreciate any suggestions. Here is block of code and I want to add bounce animation to view1
class MainView extends View {
#Override
protected void onDraw(final Canvas canvas) {
canvas.save();
// Draw view 1
canvas.translate(…);
view1.draw(canvas)
// draw other views
canvas.restore();
}
}
class View1 extends View {
..
}
You can add animators directly to Views using either XML or Java. To create the bounce you would extend the interpolator class (or one of the predefined subclasses)
I am new for android. I want to add image button in onDraw. I wonder if I can do like this. I don't have compile error. But simulator says, "Unfortunately MyApp has stopped."
My second question is how can I add button at x, y location in screen?
There is no location parameters in addView.
protected class MyLayout extends LinearLayout {
ImageButton button;
public MyLayout(Context context) {
super(context);
setWillNotDraw(false);
button = new ImageButton(context);
button.setImageBitmap(buttonBitmap); // buttonBitmap is loaded in onCreate
}
public void onDraw(Canvas canvas) {
addView(button);
}
}
I would not be adding a button to a custom linearlayout in the onDraw() override function. onDraw is called periodically (for example when the element is resized). So you will be adding the same button EACH time onDraw() is called. And you will get an error if you add the same item more than once.
What exactly are you trying to do? If you want to just add a button to a linear layout, you can do so without extending a layout.
I want to make a custom View so I extended the View class and override the onDraw(Canvas canvas) method.
The problems is, I found out that the method is never stopped being called.
well it seems that calling View.invalidate on a different View causes this view to redraw to.
I can't post the code in here so I try to describe only the relevant parts.
in the activity I create a FrameLayout m_mainLayout which is the one I finally pass to setContentView() method.
I add different Views and Layouts to m_mainLayout, one of them is GameView m_gameView which extends View and a GameFrameView which extends RelativeLayout and to this layout I add the View in question.
now, I constantly call (every ~100 ms) m_gameView.invalidate().
how does it cause other views to be redrawn ?
what do I need to do to stop this?
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); <-- add this
int width = canvas.getWidth();
int height = canvas.getHeight();
Log.i("AttackDialogView", "onDraw ");
}
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);