i need to by clicking on the button redraw the picture, but after method invalidate onDraw method is not called. But the call onDraw only happens after running the application.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Draw draw = new Draw(this);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
draw.setA(40);
draw.setB(300);
draw.invalidate();
}
});
}
}
Here is the code Draw.java
public class Draw extends View {
private Paint mPaint;
private int a;
private int b;
public Draw(Context context) {
super(context);
init();
}
public Draw(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Draw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(5);
setWillNotDraw(false);
a = 0;
b = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.WHITE);
canvas.drawPaint(mPaint);
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true);
canvas.drawLine(80, 50, 80, 500, mPaint);
canvas.drawLine(80, 50, 70, 85, mPaint);
canvas.drawLine(80, 50, 90, 85, mPaint);
canvas.drawLine(80, 500, 500, 500, mPaint);
canvas.drawLine(500, 500, 465, 510, mPaint);
canvas.drawLine(500, 500, 465, 490, mPaint);
mPaint.setTextSize(35);
mPaint.setStrokeWidth(2);
canvas.drawText("X", 480, 540, mPaint);
canvas.drawText("Y", 45, 80, mPaint);
canvas.drawText("0", 70, 540, mPaint);
drawFunction(canvas, a, b);
}
public void drawFunction(Canvas canvas, int a, int b) {
mPaint.setColor(Color.BLACK);
mPaint.setAntiAlias(true);
canvas.drawLine(80, 500, a, b, mPaint);
}
public void setA(int a) {
this.a = a;
}
public void setB(int b) {
this.b = b;
}
}
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<labs.example.function.Draw
android:layout_width="match_parent"
android:layout_height="wrap_content">
</labs.example.function.Draw>
</RelativeLayout>
Thanks in advance.
Add an id
<labs.example.function.Draw
android:id="#id/draw"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</labs.example.function.Draw>
Replace
final Draw draw = new Draw(this);
by
final Draw draw = (Draw) findViewById(R.id.draw); // need to refer to the view in xml.
If you use final Draw draw = new Draw(this); you need to add that view to your view hierachy.
Did you try to call setWillNotDraw(false). In this post you can see that by default all ViewGroup sub-classes do not call their onDraw method.
Related
In this example code I give a nice square in the form I want. canvas.drawRect (100, 300, 600, 800, paint); values work. But what I want is to call these values from the Activity class. So I want to send these values to the Draw class in the activity class. How can I do that ? For example, I want to send an activity class as drawRect (100,100,100,100, Color.BLUE). I do not want to write these values in the Draw class.
Draw.java
public class Draw extends View {
Paint paint;
Path path;
public Draw(Context context) {
super(context);
init();
}
public Draw(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Draw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void init(){
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawRect(100, 300, 600, 800, paint);
}
}
Activity.java
constraintLayout=findViewById(R.id.constraint);
Draw draw = new Draw(this);
constraintLayout.addView(draw);
You need to make method and pass value from activity to draw class:-
Draw draw = new Draw(this,100, 300, 600, 800);
constraintLayout.addView(draw);
Draw class
public class Draw extends View {
Paint paint;
Path path;
float left;
float top;
float right;
float bottom;
public Draw(Context context,float left, float top, float right, float bottom) {
super(context);
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
init();
}
public Draw(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Draw(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void init(){
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawRect(left, top, right, bottom, paint);
}
}
You can create local variables for the bounds and set them using setters or init function before adding that view to a viewgroup.( constraintLayout.addView(draw) in your case
Can you Give me any advice how to draw a list of rectangles?
I have a Rectangle class :
public final class Rectangle extends View {
private Rect rectangle;
private Paint paint;
public Rectangle(Context context) {
super(context);
int x = 50;
int y = 50;
int sideLength = 200;
// create a rectangle that we'll draw later
rectangle = new Rect(x, y, sideLength, sideLength);
// create the Paint and set its color
paint = new Paint();
paint.setColor(Color.GRAY);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(Color.BLUE);
canvas.drawRect(rectangle, paint);
}
}
and a Rectangle instance on activity
setContentView(new Rectangle(this));
Here you have some example three rectangles side by side
public class Rectangles extends View {
private Paint paintBlack;
public Rectangles(Context context) {
super(context);
init();
}
public Rectangles(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Rectangles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paintBlack = new Paint();
paintBlack.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, 100, 100, paintBlack);
canvas.drawRect(105, 0, 205, 100, paintBlack);
canvas.drawRect(210, 0, 310, 100, paintBlack);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(500, 500);
}
}
I want to redraw a view from another method (say setProgress) in a class extending View. How can I do this.
My view class is
public class SpinView extends View {
private Paint paint;
private Context context;
private Canvas canvas;
private RectF arcOval;
public SpinView(Context context) {
super(context);
this.context = context;
}
public SpinView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
this.context = context;
}
public SpinView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
Display d = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = d.getWidth();
int height = d.getHeight();
arcOval = new RectF((width/2-50), (height/2-50), (width/2+50), (height/2+50));
// RectF arcOval = new RectF(200, 200, 300, 300);
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arcOval, 270f, 360, false, paint);
}
protected void setProgress(float angle){
paint = new Paint();
paint.setColor(Color.YELLOW);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(arcOval, 270f, angle, false, paint);
}
}
All I want is to draw a circular arc of yellow color over the initially created arc of Blue color. Any help?
You can use invalidate() method to call ondraw again
its my first time to ask a question here. I have this problem with my android app.
I would like to create different draw methods inside my custom view class. There are three buttons corresponding to 3 different shapes. When a button is pressed it will draw its shape. But the app crashes when I try to call the custom draw from the MainActivity for me to test it.
MainActivity
import com.example.shapes.view.ShapesView;
public class MainActivity extends Activity {
ShapesView shapesview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shapesview = (ShapesView) findViewById(R.id.ShapesViewID);
shapesview.DrawRectangle();
}
ShapesView
public class ShapesView extends View{
Canvas canvas;
public ShapesView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
this.canvas = canvas;
}
public void DrawRectangle() {
Paint mypaint = new Paint();
mypaint.setColor(Color.BLUE);
canvas.drawRect(30, 30, 200, 200, mypaint);
}
}
My XML layout file
<com.example.shapes.view.ShapesView
android:id="#+id/ShapesViewID"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />`
Please do help! Thank you very much!
If I understand your question you need a custom view (a button) which will draw itself differently based on some event. If that is the case then you need to respect the android's guidelines about the view drawing take a look here.
Now one possible solution for your case is to set some kind of flag about the state of your view and then use that flag when you are ready to draw. For example you can do this:
public class ShapesView extends View{
public int state = 0;
public ShapesView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (state == 1) {
Paint mypaint = new Paint();
mypaint.setColor(Color.BLUE);
canvas.drawRect(30, 30, 200, 200, mypaint);
}
}
and then whenever you need to draw your view from an activity you can use the following:
myview.state = 1;
myview.invalidate();
In your code what you are doing is that you call a views function during the onCreate of your activity which in turn tries to use a null canvas because the onDraw method of your view has not be called during that time. Furthermore as others have pointed out you must not use a canvas object outside the onDraw method.
Hope this helps...
I changed your code with following.
public class ShapesView extends View {
Paint mypaint;
public ShapesView(Context context, AttributeSet attrs) {
super(context, attrs);
mypaint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mypaint.setColor(Color.BLUE);
canvas.drawRect(30, 30, 200, 200, mypaint);
}
}
When you want to draw, call shapesview.invalidate();
Look at method's name its onDraw() and not getCanvas(). The documentation also doesn't makes any claims about the Canvas provided.
After onDraw() is done, that canvas may be disposed, its bitmap/buffer may be re-cycled, who knows.
So, it is not safe to use the Canvas outside of this method. Draw what you want, but only inside onDraw() method.
If you want to trigger the View to re-draw, at some other time, call invalidate().
Example:
View class to render any shape:
public class ShapeView extends View {
private Paint mPaint;
private ShapeRenderer mRenderer;
public ShapeView(Context context) {
super(context);
init();
}
public ShapeView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ShapeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
mPaint = new Paint();
}
public void setPaintColor(int color){
mPaint.setColor(color);
}
public void setPaintStrokeWidth(float width){
mPaint.setStrokeWidth(width);
}
public void setRenderer(ShapeRenderer renderer) {
mRenderer = renderer;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mRenderer != null){
mRenderer.drawShape(canvas,mPaint);
}
}
public static interface ShapeRenderer{
public void drawShape(Canvas canvas, Paint paint);
}
}
A Class that draws a rectangle:
public class RectRenderer implements ShapeView.ShapeRenderer {
#Override
public void drawShape(Canvas canvas, Paint paint) {
canvas.drawRect(0,0,100,100,paint);
}
}
Draw a shape at runtime:
myShapeView.setPaintColor(Color.GREEN);
myShapeView.setPaintStroke(5f);
myShapeView.setRenderer(new RectRenderer());
myShapeView.invalidate();
I think you must redesign your component, so it can draw itself in onDraw method. If you need some class that must contain Canvas, you can try to do something like this.
class Drawer {
private Canvas canvas;
public Drawer(Canvas canvas) {
this.canvas = canvas;
}
public void DrawRectangle() {
Paint mypaint = new Paint();
mypaint.setColor(Color.BLUE);
canvas.drawRect(30, 30, 200, 200, mypaint);
}
}
On yours custom view you can do something like this.
public class ShapesView extends View{
public ShapesView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Drawer drawer = new Drawer(canvas);
drawer.DrawRectangle();
}
public void DrawRectangle() {
Paint mypaint = new Paint();
mypaint.setColor(Color.BLUE);
canvas.drawRect(30, 30, 200, 200, mypaint);
}
}
Hi i draw a canvas for my application
here is the code my canvas
public class Canvas1 extends View{
int i;
int k;
float l,m;
public Canvas1(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public Canvas1 (Context context, AttributeSet attrs) {
super(context, attrs);
}
public Canvas1 (Context context, AttributeSet ats, int ds) {
super(context, ats, ds);
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
Paint paint1=new Paint(Color.BLACK);
Paint paint=new Paint(200);
paint.setStrokeWidth((float)0.5);
canvas.drawLine(0,0,0,getMeasuredHeight(), paint1);
canvas.drawLine(0,0, getMeasuredWidth(), 0, paint1);
canvas.drawLine(0,getMeasuredHeight(), getMeasuredWidth(),getMeasuredHeight(), paint1);
canvas.drawLine(getMeasuredWidth(),getMeasuredHeight(), getMeasuredWidth(), 0, paint1);
//canvas.drawLine(0, 0, ((float)getMeasuredWidth()), ((float)getMeasuredHeight()), paint);
if(l!=0||m!=0)
{
canvas.drawLine(getMeasuredWidth()/2,getMeasuredHeight()/2,getMeasuredWidth()/2,getMeasuredHeight(),paint);
canvas.drawLine(0,0,getMeasuredWidth()/2,getMeasuredHeight()/2,paint);
}
for(int i=1;i<5;i++)
canvas.drawLine(((float)getMeasuredWidth())/5*i, 0, ((float)getMeasuredWidth()/5*i),getMeasuredHeight(), paint);
for(int i=0;i<5;i++)
canvas.drawLine(0, getMeasuredHeight()/5*i, getMeasuredWidth(), getMeasuredHeight()/5*i, paint);
canvas.save();
}
public Boolean setline(float d,float e){
l=d;
m=e;
Log.i("Hello Canvas",l+" "+m+" ");
return true;
}
}
now i am trying to call the function setline() from my main activity in this activity there is an array of canvas . here is the code of my activity
public class HelloCanvasActivity extends Activity {
/** Called when the activity is first created. */
Integer[] in={R.id.can1,R.id.can2,R.id.can3,R.id.can4,R.id.can5,R.id.can6,R.id.can7,R.id.can8};
float x,y;
int j=0;
Canvas1[] can=new Canvas1[8];
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
for(int i=0;i<8;i++)
{
can[i]=(Canvas1)findViewById(in[i]);
}
can[0].setline((float)0.5,(float) 0.5);
new Thread(new Runnable(){
public void run(){
for(int i=0;i<8;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
can[i].setline((float)0.5,(float)0.5);
}
}
}).start();
}
}
when i omit Thread.sleep(1000) from my code lines are drawing but when i put Thread.sleep(1000) setline is calling after 1 second i am getting log in my log table of Hello World,but no line is drawing on canvas please help me in finding where i am wrong.
In your setline method, call invalidate()