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);
Related
I asked this question before, but now I've stumbled around and figured out a direction.
Basically, I need to record the user's finger's movements around the screen, and replay an animation of that movement on a view upon pressing a replay button, as well as a reverse animation of it when pressing a reverse button. I'm trying to achieve this by saving the finger's (x,y) coordinates in onTouch(), which I store in an ArrayList for PointF objects, then create a path for the view to animate on based on the coordinates stored in said ArrayList. Then I'll need to animate along that path. However, I am not sure how to create a path based on an arraylist that could be of any length.
Code related to the animation so far:
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import java.util.ArrayList;
/**
* TODO: document your custom view class.
*/
public class MyView extends View {
ArrayList<PointF>theCoords;
ArrayList<Float> xcord;
ArrayList<Float> ycord;
private Paint paint;
//coordinates
private float x;
private float y;
public MyView (Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
xcord = new ArrayList<Float>();
ycord= new ArrayList<Float>();
theCoords=new ArrayList<PointF>();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initPaint();
xcord = new ArrayList<Float>();
ycord= new ArrayList<Float>();
theCoords=new ArrayList<PointF>();
}
public MyView(Context context) {
super(context);
initPaint();
xcord = new ArrayList<Float>();
ycord= new ArrayList<Float>();
theCoords=new ArrayList<PointF>();
}
//initialize paint object
private void initPaint(){
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setTextSize(40);
}
#Override
//drawing on the canvas
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawCircle(x,y,50,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
theCoords.clear();
xcord.clear();
ycord.clear();
x = event.getX();
y = event.getY();
PointF p1 = new PointF(x,y);
theCoords.add(p1);
postInvalidate();
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
x = event.getX();
y = event.getY();
PointF p2 = new PointF(x,y);
theCoords.add(p2);
postInvalidate();
break;
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.R)
public void replayAnim()
{
PointF pcur;
PointF pnext;
//create path
for(int i =0;i<theCoords.size()-1;i++)
{
pcur=new PointF(theCoords.get(i));
pnext=new PointF(theCoords.get(i+1));
//how to form a path with these?
}
//anim along the path
}
public void reverseAnim()
{
//the original code I have, which only
//moves the view to its original position
for (int i = xcord.size() - 1; i >= 0; i--)
{
x = xcord.get(i);
y = ycord.get(i);
Log.d("ReverseAnimation", "x: " + Float.toString(x));
postInvalidate();
}
}
public float getX()
{
return x;
}
public float getY()
{
return y;
}
} ```
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();
}
}
}
So i've started learnin android studio game development from this series: https://www.youtube.com/watch?v=Rliwg0sELJo and i can't seem to find the reason why my draw method isn't working. i triple checked my code and the video and ran some tests to try and find my error but ended up blank.
please keep in mind i'm new to stackoverflow and programming so if you see any ways i can improve on stuff like formatting i'd love to hear it
MainActivity:
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new GamePanel(this));
}
}
GamePanel:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;
private RectPlayer player;
private Point playerPoint;
public GamePanel(Context context){
super(context);
getHolder().addCallback(this);
thread=new MainThread(getHolder(),this);
player = new RectPlayer(new Rect(100,100,200,200), Color.rgb(255,0,0));
playerPoint=new Point(150,150);
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
#Override
public void surfaceCreated(SurfaceHolder holder){
thread = new MainThread(getHolder(),this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while(retry){
try{
thread.setRunning(false);
thread.join();
}catch(Exception e){e.printStackTrace();}
retry=false;
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
playerPoint.set((int)event.getX(),(int)event.getY());
}
return true;
//return super.onTouchEvent(event);
}
public void update(){
player.update(playerPoint);
System.out.println(playerPoint.x);
System.out.println(playerPoint.y);
}
#Override
public void draw(Canvas canvas){
super.draw(canvas);
canvas.drawColor(Color.BLUE);
player.draw(canvas);
}
}
MainThread:
package com.example.student.game_core1;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
public static final int MAX_FPS=30;
private double averageFPS;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
private boolean running;
public static Canvas canvas;
public void setRunning(boolean running){
this.running=running;
}
public MainThread(SurfaceHolder surfaceHolder,GamePanel gamePanel){
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run(){
long startTime;
long timeMillis;
long waitTime;
int frameCount=0;
long totalTime=0;
long targetTime=1000/MAX_FPS;
while (running){
startTime=System.nanoTime();
canvas=null;
try{
canvas=this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
this.gamePanel.update();
this.gamePanel.draw(canvas);
}
}catch(Exception e){
e.printStackTrace();
}finally {
if(canvas!=null){
try{
surfaceHolder.unlockCanvasAndPost(canvas);
}catch(Exception e){e.printStackTrace();}
}
}
timeMillis=(System.nanoTime()-startTime)/1000000;
waitTime=targetTime - timeMillis;
try{
if(waitTime>0)
this.sleep(waitTime);
}catch(Exception e) {e.printStackTrace();}
totalTime+=System.nanoTime()-startTime;
frameCount++;
if(frameCount==MAX_FPS){
averageFPS=1000/(totalTime/frameCount/1000000);
frameCount=0;
totalTime=0;
System.out.println(averageFPS);
}
}
}
}
RectPlayer:
package com.example.student.game_core1;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
public class RectPlayer implements GameObject {
private Rect rectangle;
private int color;
public RectPlayer(Rect rectangle, int color){
this.rectangle=rectangle;
this.color=color;
}
#Override
public void draw(Canvas canvas){
Paint paint=new Paint();
paint.setColor(color);
canvas.drawRect(rectangle,paint);
}
#Override
public void update(){
}
public void update(Point point){
rectangle.set((point.x)-(rectangle.width()/2),(point.y)-(rectangle.height()/2),(point.x)+(rectangle.width()/2),(point.y)+(rectangle.height()/2));
}
public Rect getRectangle() {
return rectangle;
}
}
If im not wrong you are using Canvas, trying to draw your item with draw() method.
It seems that you need to use another method (onDraw(Canvas)):
Draw your graphics in a Canvas object. To use this option, you pass your canvas to the appropriate class' onDraw(Canvas) method. You can also use the drawing methods in Canvas. This option also puts you in control of any animation.
If you need more info about canvas, just go here --> https://developer.android.com/guide/topics/graphics/2d-graphics.html
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()
how do i develop an app that draws a line on screen at fixed coordinates, Setting up a repeating timer of 1 second duration? On every tick of the timer,the line refreshes.
LineRefresh.java:
package LineRefresh.xyz.com;
import java.util.Timer;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
public class LineRefresh extends Activity {
DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
}
}
DrawView.java:
package LineRefresh.xyz.com;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawView extends View {
Paint paint = new Paint();
public DrawView(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLACK);
canvas.drawLine(50, 200, 270, 200, paint);
}
}
Use a Handler and use it's postDelayed() to schedule drawing a line.
After you draw a line also schedule another postDelayed() to continue this process.