Iam doing my first game for android.
I want to do a very simple thing which is to have a background and a ball that will "spawn" in it.
So I have made my GameView:
package com.example.newarkanoid;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
public class Tela extends View {
Paint paint;
int x,y;
int lastx,lasty;
Bola bola;
public Tela(Context context, Bola BOLA) {
super(context);
paint = new Paint();
x=0;lastx=0;
y=0;lasty=0;
bola = BOLA;
bola.paint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
bola.invalidate();
}
public boolean onTouchEvent(MotionEvent event) {
x = (int)event.getX();
y = (int)event.getY();
if(lastx !=x || lasty !=y){
lastx=x;
lasty=y;
bola.x = x;
bola.y = y;
bola.invalidate();
}
return false;
}
}
Well, above is my MainDisplay, now i need a ball:
package com.example.newarkanoid;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class Bola extends View {
Paint paint;
float x,y,raio;
public Bola(Context context, float x, float y, float raio) {
super(context);
this.x = x;
this.y = y;
this.raio = raio;
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(x, y, raio, paint);
}
}
So, I did like that cause my teacher told me, you dont have to call invalidate for the intire main display, you can call invalidate just for your ball, so i made my ball drawing code, also its properties.
So as you can see in the code, when i click somewhere in the touchscreen my ball x and y will change to the click position, and then call invalidate.
The thing is, the ball does not even appear when i create my mainDisplay, so I was wondering, is there something like a context problem? why my ball isnt drawn?
Also, here is my MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bola bola = new Bola(this,20,20,5);
Tela t = new Tela(this,bola);
setContentView(t);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
bola.invalidate();
}
when bola invalidate, bola will draw with its canvas, different the Tela's canvas. You can create a class, not extends view, with draw method
public void draw(Canvas canvas) {
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(x, y, raio, paint);
}
and call in tela:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
bola.draw(canvas);
}
use bola.draw(canvas); in your onDraw()
Related
I build this class to draw on screen to implement some brushes created via differents Paints and paths.
Currently is drawing a square based on user touch movement, but the draw path is being rotated by the draw direction of the touch. I tried to apply a rect without no luck and I don't found any related info about this phenom
EDIT :
This image is from current result
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class RachetBasic extends androidx.appcompat.widget.AppCompatImageView {
private Canvas canvas;
private Bitmap bitmap;
private Paint bitmapPaint = new Paint(Paint.DITHER_FLAG);
private Path squarePath = new Path();
private Paint squarePaint = new Paint();
public RachetBasic(Context context) {
super(context);
}
public RachetBasic(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RachetBasic(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
super.onSizeChanged(width, height, oldw, oldh);
squarePaint.setAntiAlias(true);
squarePaint.setDither(true);
squarePaint.setStyle(Paint.Style.STROKE);
squarePaint.setStrokeCap(Paint.Cap.SQUARE);
squarePaint.setStrokeWidth(80);
squarePaint.setColor(Color.BLUE);
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
canvas.drawPath(squarePath, squarePaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
squarePath.moveTo(x, y);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
squarePath.lineTo(x, y);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
squarePath.lineTo(x, y);
canvas.drawPath(squarePath, squarePaint);
squarePath.reset();
}
invalidate();
return true;
}
}
public class MainActivity extends androidx.appcompat.app.AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new RachetBasic(MainActivity.this));
}
}
So I just started learn how to create an app with android-studio and I'm trying to make a simple animation. For exemple I thought of a bouncing ball, but for the moment I can't make my ball move. I don't understand perfectly how everything works but I managed to draw a ball in the screen, now I want my ball to move but the problem is that I can't manage to update my screen (which is drawn by the onDraw function) while it is opened, the phone just show the final screen when all the movement is finished. I heard that I had to use invalidate function but I don't know how to use it and I tried to make a move function to use it. I would like to know what would be the simplest change I have to do on my code to see the ball moving on the screen.
package com.example.myfirstapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.util.Random;
public class AnimationActivity extends AppCompatActivity {
public int posX= 300;
public int posY= 300;
public int radius= 50;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
RenderView renderView = new RenderView(this);
setContentView(renderView);
while(posX<2000) {
renderView.move();
setContentView(renderView);
}
}
class RenderView extends View {
public RenderView(Context context){
super(context);
}
public void move(){
posX=posX+1;
//SystemClock.sleep(2);
invalidate();
}
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
canvas.drawRGB(255, 255, 255);
Paint ball = new Paint();
ball.setAntiAlias(true);
ball.setARGB(255,255,0,0);
ball.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(posX,posY,radius,ball);
}
}
}
Try this code
public class MainActivity extends AppCompatActivity {
public int posX = 300;
public int posY = 300;
public int radius = 50;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
RenderView renderView = new RenderView(this);
setContentView(renderView);
/* while (posX < 2000) {
renderView.move();
renderView.invalidate();
}*/
}
class RenderView extends View {
public RenderView(Context context) {
super(context);
}
public void move() {
posX++;
//SystemClock.sleep(2);
}
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
canvas.drawRGB(255, 255, 255);
Paint ball = new Paint();
ball.setAntiAlias(true);
ball.setColor(getResources().getColor(R.color.colorAccent));
ball.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(posX, posY, radius, ball);
if (posX > 350) {
posX = 300;
posY+=10;
}
posX++;
invalidate();
}
}
}
I want the program to draw a circle whenever the screen gets touched and if the screen gets touched on another position I want the program to draw a circle again but without deleting the old one!
Now my problem is that it doesn't just draw a new circle in addition to the old one. It draws a new circle and deletes the old one. I tried to find a solution but nothing worked.
So can anyone please help me?
So it's working now!
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
List<Point> points = new ArrayList<Point>();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
paint.setColor(Color.GREEN);
for(Point p: points){
canvas.drawCircle(p.x, p.y, 20, paint);
}
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Point p = new Point();
p.x = (int)event.getX();
p.y = (int)event.getY();
points.add(p);
invalidate();
case MotionEvent.ACTION_MOVE: // a pointer was moved
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
break;
}
}
invalidate();
return true;
}
}
You can achieve it by maintaining a list of points as a private instance variable:
private List<Point> points = new ArrayList<Point>;
Then you can add new points to this list every time a new touch event occurs:
Point p = new Point();
p.x = event.getX();
p.y = event.getY();
points.add(p);
invalidate();
Now in the onDraw() method you can print all the points in the list:
paint.setColor(Color.GREEN);
for(Point point: points){
canvas.drawCircle(point.x, point.y, 20, paint);
}
invalidate();
Why not make a circle object which stores the coordinates of where to paint the circle, then add these objects to an array. Then in your paint method iterate through the array get the coordinates from each object and paint the circle using the coordinates?
So in your onclick method create a new circle object with the coordinates gained from the touch
one of my changing circle classes:
public class GrowCircle {
float x, y;int radius;
Paint myp = new Paint();
int colr,colg,colb;
int redvar=1;
int bluevar=5;
int greenvar=2;
int tripper=10;
int change=2;
Random rand = new Random();
public GrowCircle(float x, float y){
this.x=x;
this.y=y;
this.radius=2;
this.colr=rand.nextInt(254)+1;
this.colg=rand.nextInt(254)+1;
this.colb=rand.nextInt(254)+1;
}
public void update(){
if(tripper<=1||tripper>=15){
change=-change;
}
Random col = new Random();
myp.setColor(Color.argb(255,colr,colg,colb));
colr+=redvar;
colg+=greenvar;
colb+=bluevar;
if(colr<=5||colr>=250){
redvar=-redvar;
}
if(colg<=5||colg>=250){
greenvar=-greenvar;
}
if(colb<=5||colb>=250){
bluevar=-bluevar;
}
}
public void drawThis(Canvas canvas){
myp.setStrokeWidth(tripper);
myp.setStyle(Style.STROKE);
canvas.drawCircle(x, y, radius, myp);
}
}
so play with that and make it how you want and then do this:
///var declaration
CopyOnWriteArrayList<GrowCircle> gcirc= new CopyOnWriteArrayList<GrowCircle>();
//in update method
for(GrowCircle circ:gcirc){
circ.update();
}
// in draw method
for(GrowCircle circ:gcirc){
circ.drawThis(c);
}
//and in onTouch
float tx =event.getX();
float ty = event.getY();
gcirc.add(new GrowCircle(tx,ty));
I want to draw circle by canvas. Here is my code:
[MyActivity.java]:
public class MyActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
...
setContentView(new View(this,w,h));
}
}
[View.java]:
public class View extends SurfaceView
{
public View(Context context, int w, int h)
{
super(context);
Canvas grid = new Canvas(Bitmap.createBitmap(h,w, Bitmap.Config.ARGB_8888));
grid. drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
grid.drawCircle(w/2, h/2 , w/2, paint);
}
}
So I have just black screen without circle.
Why it does not work? How to fix it?
You can override the onDraw method of your view and draw the circle.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, radius, paint);
}
For a better reference on drawing custom views check out the official Android documentation.
http://developer.android.com/training/custom-views/custom-drawing.html
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
}
public class MyView extends View
{
Paint paint = null;
public MyView(Context context)
{
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
int radius;
radius = 100;
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawCircle(x / 2, y / 2, radius, paint);
}
}
}
Edit
if you want to draw circle at centre. You could also translate your entire canvas to center then draw circle at center.using
canvas.translate(getWidth()/2f,getHeight()/2f);
canvas.drawCircle(0,0, radius, paint);
These two link also help
http://www.compiletimeerror.com/2013/09/introduction-to-2d-drawing-in-android.html#.VIg_A5SSy9o
http://android-coding.blogspot.com/2012/04/draw-circle-on-canvas-canvasdrawcirclet.html
public class CircleView extends View {
private static final String COLOR_HEX = "#E74300";
private final Paint drawPaint;
private float size;
public CircleView(final Context context, final AttributeSet attrs) {
super(context, attrs);
drawPaint = new Paint();
drawPaint.setColor(Color.parseColor(COLOR_HEX));
drawPaint.setAntiAlias(true);
setOnMeasureCallback();
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(size, size, size, drawPaint);
}
private void setOnMeasureCallback() {
ViewTreeObserver vto = getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
removeOnGlobalLayoutListener(this);
size = getMeasuredWidth() / 2;
}
});
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
if (Build.VERSION.SDK_INT < 16) {
getViewTreeObserver().removeGlobalOnLayoutListener(listener);
} else {
getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}
}
Xml example: will produce a circle of 5dp
<com.example.CircleView
android:layout_width="10dp"
android:layout_height="10dp"/>
If you are using your own CustomView extending View class, you need to call canvas.invalidate() method which will internally call onDraw method. You can use default API for canvas to draw a circle. The x, y cordinate define the center of the circle. You can also define color and styling in paint & pass the paint object.
public class CustomView extends View {
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
setupPaint();
}
}
Define default paint settings and canvas (Initialise paint in constructor so that you can reuse the same object everywhere and change only specific settings wherever required)
private Paint drawPaint;
// Setup paint with color and stroke styles
private void setupPaint() {
drawPaint = new Paint();
drawPaint.setColor(Color.BLUE);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(5);
drawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
}
And initialise canvas object
private Canvas canvas;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
canvas.drawCircle(xCordinate, yCordinate, RADIUS, drawPaint);
}
And finally, for every view refresh or new draw on the screen, you need to call invalidate method. Remember your entire view is redrawn, hence this is an expensive call. Make sure you do only the necessary operations in onDraw
canvas.invalidate();
For more details on canvas drawing refer https://medium.com/#mayuri.k18/android-canvas-for-drawing-and-custom-views-e1a3e90d468b
#Override
public void onDraw(Canvas canvas){
canvas.drawCircle(xPos, yPos,radius, paint);
}
Above is the code to render a circle. Tweak the parameters to your suiting.
Try this
The entire code for drawing a circle or download project source code and test it on your android studio. Draw circle on canvas programmatically.
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.widget.ImageView;
public class Shape {
private Bitmap bmp;
private ImageView img;
public Shape(Bitmap bmp, ImageView img) {
this.bmp=bmp;
this.img=img;
onDraw();
}
private void onDraw(){
Canvas canvas=new Canvas();
if (bmp.getWidth() == 0 || bmp.getHeight() == 0) {
return;
}
int w = bmp.getWidth(), h = bmp.getHeight();
Bitmap roundBitmap = getRoundedCroppedBitmap(bmp, w);
img.setImageBitmap(roundBitmap);
}
public static Bitmap getRoundedCroppedBitmap(Bitmap bitmap, int radius) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(finalBitmap.getWidth() / 2 + 0.7f, finalBitmap.getHeight() / 2 + 0.7f, finalBitmap.getWidth() / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
Here is example to draw stroke circle canvas
val paint = Paint().apply {
color = Color.RED
style = Paint.Style.STROKE
strokeWidth = 10f
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawCircle(200f, 100f, 100f, paint)
}
Result
Example to draw solid circle canvas
val paint = Paint().apply {
color = Color.RED
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawCircle(200f, 100f, 100f, paint)
}
Result
Hope it help
private Paint green = new Paint();
private int greenx , greeny;
green.setColor(Color.GREEN);
green.setAntiAlias(false);
canvas.drawCircle(greenx,greeny,20,green);
I got a class CanvasView :
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import java.util.Random;
public class CanvasView extends View {
private Canvas canvas;
private Paint paint;
private int width;
private int height;
Random random = new Random();
public CanvasView(Context context,AttributeSet attrs) {
super(context);
super.onDraw(canvas);
initPaint(); //here i just create my Paint
}
#Override
public void onDraw(Canvas canvas) {
this.canvas = canvas;
}
public void drawRandom() {
canvas.drawCircle(random.nextInt(700), random.nextInt(700), random.nextInt(200), paint);
}
}
Then i try to create CanvasView object in another activity like this:
canvasView = new CanvasView(this,null);
and then i try to call method drawRandom()
canvasView.drawRandom();
then happens error:Attempt to invoke virtual method 'void android.graphics.Canvas.drawCircle(float, float, float, android.graphics.Paint)' on a null object reference
i know that it means that canvas=null at this moment but how to fix it?I tried a lot but still cant do it.
Dont blame me if this question is as stupid,as me, i am beginner,sorry.
public CanvasView(Context context, AttributeSet attrs) {
super(context);
initPaint(); //here i just create my Paint
}
#Override
public void onDraw(Canvas canvas) {
this.canvas = canvas;
canvas.drawCircle(random.nextInt(700), random.nextInt(700), random.nextInt(200), paint);
}
public void drawRandom() {
invalidate();
}
BTW, don't forget to add it to window after New CanvasView().
Like this:
ViewGroup viewGroup =(ViewGroup) ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
viewGroup.addView(canvasView);