How to reduce the lag in my paint application on android - java

I have been making a paint app for android with the ability to choose different colors.
my task is almost complete. yet there is cetain lag in my app. At start it works fine but after some lines it starts giving straight lines instead of curves and lags in usage....
This is the code for my DrawIt:
package app.paintit;
import java.util.ArrayList;
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
public class DrawIt extends View{
float x,y;
Paint paint;
int count1=0,count2=0;
ArrayList<Lines> lines = new ArrayList<Lines>();
public int color= 0xFFFFFF;
Lines l;
Path path;
public DrawIt(Context context) {
super(context);
// TODO Auto-generated constructor stub
x=0;y=0;
paint=new Paint();
path = new Path();
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
l = new Lines();
l.color = color;
l.xCoordinate = new ArrayList<Float>();
l.xCoordinate.add(event.getX());
l.yCoordinate = new ArrayList<Float>();
l.yCoordinate.add(event.getY());
lines.add(l);
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
l.color = color;
l.xCoordinate.add(event.getX());
l.yCoordinate.add(event.getY());
lines.add(l);
}
invalidate();
return true;
}
});
}
#Override
protected void onDraw(final Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
Lines p,q;
float nowX,nowY,prevX=0,prevY=0;
for(int j=0;j<lines.size();j++){
p = lines.get(j);
Path path1=new Path();
paint.setColor(p.color);
path1.moveTo(p.xCoordinate.get(0), p.yCoordinate.get(0));
for(int i=1;i<p.xCoordinate.size()-1;i++){
float midX=(p.xCoordinate.get(i)+p.xCoordinate.get(i-1))/2;
float midY=(p.yCoordinate.get(i)+p.yCoordinate.get(i-1))/2;
path1.quadTo(p.xCoordinate.get(i-1), p.yCoordinate.get(i-1), midX, midY);
canvas.drawPath(path1, paint);
}
}
}
}
The code for Lines.java which holds the lists that help in maintaining different colors is :
package app.paintit;
import java.util.ArrayList;
import java.util.LinkedList;
import android.graphics.Color;
public class Lines {
ArrayList<Float> xCoordinate;
ArrayList<Float> yCoordinate;
int color;
}
Please help me how to reduce the lag and the straight lines happening after some shapes are drawn perfectly.

Related

I am making an app and I require to use the interface Parcelable but facing issues and not sure how to implement it

I am new to coding and to java and android. I am making an app that has multiple canvas views (where a person can draw lines with their finger) in multiple fragments (requested to be like this). I have managed to get the fragments to work and to draw lines on each canvas. Next, I want to be able to save the lines drawn by the user when the user goes to a different fragment or closes the app and when the user comes back to a fragment, the drawing for that fragment will still be there, and can continue editing it by adding more lines or clear it by hitting Clear, the same should happen for other fragments that should have their respective drawings.
I was previously told about the interface Parcelable and have made some steps to implement it but I am finding it hard to understand what I am doing and having trouble reading in an ArrayList. The error is stating that it is expecting ClassLoader but being provided with an ArrayList (I hope in the right place), and that's if I make the getter static but that creates an error: Non-static field 'paths' cannot be referenced from a static context in the getter in the PaintView class (this controls the drawing). I get a similar static context message for the readArrayList method in the FingerPath class. Once this is figured out, I will need to find out how to bring the relevant, saved drawing back to the canvas when the fragment is opened which I am not sure how, I think when the Bundle isn't equal to null but not sure.
I'll show the code below (right now it is on a test app)
FingerPath class
import android.graphics.Path;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
public class FingerPath implements Parcelable {
public int color;
public boolean emboss;
public boolean blur;
public int strokeWidth;
public Path path;
public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path) {
this.color = color;
this.emboss = emboss;
this.blur = blur;
this.strokeWidth = strokeWidth;
this.path = path;
}
protected FingerPath(Parcel in) {
color = in.readInt();
emboss = in.readByte() != 0;
blur = in.readByte() != 0;
strokeWidth = in.readInt();
//line below causing me issues
path = in.readArrayList(PaintView.getPaths());
}
public static final Creator<FingerPath> CREATOR = new Creator<FingerPath>() {
#Override
public FingerPath createFromParcel(Parcel in) {
return new FingerPath(in);
}
#Override
public FingerPath[] newArray(int size) {
return new FingerPath[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(color);
parcel.writeByte((byte) (emboss ? 1 : 0));
parcel.writeByte((byte) (blur ? 1 : 0));
parcel.writeInt(strokeWidth);
//parcel.writeParcelableArray(PaintView.getPaths(), 0);
}
}
PaintView
Controls what happens when the user starts drawing
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class PaintView extends View {
public static int BRUSH_SIZE = 10;
public static final int DEFAULT_COLOR = Color.WHITE;
public static int DEFAULT_BG_COLOR = Color.GRAY;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
//the getter in question
public ArrayList getPaths() {
return paths;
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp: paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchUp() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
touchUp();
invalidate();
break;
}
return true;
}
}
Here's an example of a fragment
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class LineLHwFragment extends Fragment {
private PaintView paintView;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_line_l_hw, container, false);
paintView = v.findViewById(R.id.lineLPaintView);
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
setHasOptionsMenu(true);
return v;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.normal:
paintView.normal();
return true;
case R.id.clear:
paintView.clear();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("line test", paintView.getPaths());
}
}

I cant draw on my Canvas by onTouch method.Why dont work?

This is my first question here! I hope that you can help me!
I'm explain:
I'm trying to develop an app like a paint in android studio to work with Paint,Canvas,and this class...
I have a class call Lienzo.java; This is the code of my class:
package com.example.pedro.paint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.graphics.Path;
/**
* Created by Pedro on 26/02/2018.
*/
public class Lienzo extends View {
//PATH TO DRAW THE LINES
private Path drawPath;
//PAINT DRAWING AND PAINT CANVAS
private Paint drawPaint,canvasPaint;
//COLOR INITIAL
private int paintColor=0xFFFF0000;
//CANVAS
private Canvas drawCanvas;
//CANVAS TO SAVE
private Bitmap canvasBitmap;
public Lienzo(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
private void setupDrawing(){
//CONFIGURATION AREA TO DRAW
drawPath = new Path();
drawPaint=new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint= new Paint(Paint.DITHER_FLAG);
}
//ASIGN SIZE TO VIEW
#Override
protected void onSizeChanged(int w, int h,int oldw, int oldh){
super.onSizeChanged(w,h,oldw,oldh);
canvasBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
drawCanvas=new Canvas(canvasBitmap);
}
//PAINT THE VIEW.CALL BY ONTHOUCHEVENT
#Override
protected void onDraw(Canvas canvas){
canvas.drawBitmap(canvasBitmap,0,0,canvasPaint);
canvas.drawPath(drawPath,drawPaint);
}
//REGISTER USER TOUCH
public boolean OnTouchEvent(MotionEvent event)
{
float touchX =event.getX();
float touchY=event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX,touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX,touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX,touchY);
drawCanvas.drawPath(drawPath,drawPaint);
drawPath.reset();
break;
default:
return false;
}
//REPAINT
invalidate();
return true;
}
}
I have no error but I try to paint but do nothing.
This is a copy of an example.The original https://www.youtube.com/watch?v=GAr_agEokr8 works but my code,its equal and dont work.
Anybody knows why?
Thanks and regards!
OnTouchEvent change to onTouchEvent and add #Override

Draw a circle in Android Canvas when previous circle was selected at predefined positions

This is my first time using Canvas in Android.
I am creating an app that would display circles at certain positions on the screen one at a time (positions are selected randomly). New circle should be drawn after the previous one was selected/touched, and the previous one should disappear.
I have some ideas about it: to keep an arraylist of Point objects(each object contains x,y coordinate of the centre of the circle) and randomly select one each time the circle is drawn on the screen. So first I am populating an array of points. I also know how to randomly select the element from arraylist.
My biggest confustion is how to connect onDraw and onTouchEvent methods with each other? I know I should check if the circle was selected and only then draw a new circle at the randomly selected position, but I m not sure how to make a call for onDraw() method from the onTouchEvent...
Could you please help with this issue?
My code is below:
package com.example.researcher.heatmap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: document your custom view class.
*/
public class MyView extends View {
Paint paint;
ArrayList<Point> points = new ArrayList<>();
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// Load attributes
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
populateArrayList();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
int i=1; // should be random, will randomize later
for(Point p: points) {
p.x = points.get(i).x;
p.y = points.get(i).y;
canvas.drawCircle(p.x, p.y, 50, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int i=1;
for(Point p: points) {
Canvas canvas = new Canvas();
p.x = points.get(i).x;
p.y = points.get(i).y;
canvas.drawCircle(p.x, p.y, 50, paint);
}
postInvalidate();
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}
public void populateArrayList(){
points.clear();
points.add(new Point(120, 120));
points.add(new Point(150, 320));
points.add(new Point(280, 200));
}
}
Thank you Chris for your help! I really appreciate it.
Here is my solution if someone will need it for reference
package com.example.researcher.heatmap;
import android.content.Context;
import android.content.res.TypedArray;
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.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* TODO: document your custom view class.
*/
public class MyView extends View {
Paint paint;
ArrayList<Point> points = new ArrayList<>();
private int pointsPos = 0; //Which point we will be drawing
public float x;
public float y;
public int radius = 150;
public MyView(Context context) {
super(context);
x = this.getX();
y = this.getY();
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
x = this.getX();
y = this.getY();
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
x = this.getX();
y = this.getY();
init();
}
private void init() {
// Load attributes
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
populateArrayList();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, radius, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
//Check if the point press is within the circle
if(contains(event, points.get(pointsPos))){
Random r = new Random(System.nanoTime());
pointsPos = r.nextInt(points.size());; //between 0 and points.length
postInvalidate();
}
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}
private boolean contains(MotionEvent event, Point point) {
float xTouch = event.getX();
float yTouch = event.getY();
if ((xTouch - point.x) * (xTouch - point.x) + (yTouch - point.y) * (yTouch - point.y) <= radius * radius) {
return true;
}
else {
return false;
}
}
public void populateArrayList(){
points.clear();
points.add(new Point(220, 1020));
points.add(new Point(550, 320));
points.add(new Point(780, 500));
}
}
Class var
private int state = 0 //0 normal, 1 new circle
private int pointPos = 0; //Which point we will be drawing
onDraw was overwriting the x/y of all your other points
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
if(state == 1){
pointPos = random(); //between 0 and points.length
state = 0;
}
canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, 50, paint);
}
onTouchEvent: Drawing should only be done on the ondraw, use flags/states to keep track of what you should be doing on the next draw call
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Though these days this is usually done on the up event
//Check if the point press is within the circle
if(contains(event, points.get(pointPos))){
state = 1;
postInvalidate();
}
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}

generating random circles in android

Im trying to make a simple app that draws random circles when one button is pushed, and clears them all from the screen when another is pushed. Currently When i start the app on an emulator for some reason it starts with an automatically generated circle, then If I attempt to push the button to generate another circle the app crashes and I get a NullPointerException at my
c.drawcircle(b.getX(), b.getY(), b.getR(), p)
method.
Heres what I currently have:
Main:
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class Bubbles extends Activity implements OnClickListener
{
Button b1,b2;
drawView dv;
LinearLayout frame;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bubbles);
dv = new drawView(getApplicationContext());
frame = (LinearLayout)findViewById(R.id.LinearLayout2);
b1 = (Button)findViewById(R.id.BubbleButton);
b1.setOnClickListener(this);
b2 = (Button)findViewById(R.id.ClearButton);
b2.setOnClickListener(this);
frame.addView(dv);
}
#Override
public void onClick(View v)
{
if(v==b1)
{
dv.onDraw(null);
}
if(v==b2)
{
dv.clear();
}
v.postInvalidate();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.bubbles, menu);
return true;
}
}
drawView:
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class drawView extends View
{
ArrayList<Bubble> bList = new ArrayList<Bubble>();
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
public drawView(Context con)
{
super(con);
}
public void onDraw(Canvas c)
{
Bubble b = new Bubble();
p.setColor(b.getColor());
p.setStyle(Paint.Style.FILL);
bList.add(b);
c.drawCircle(b.getX(), b.getY(), b.getR(), p);
}
public void clear()
{
bList.clear();
}
}
Im using an arrayList in this class to store all the bubbles I make and then clear the arrayList using the clear button.
Here is the Bubble class I made that goes with it:
Bubble:
import android.graphics.Color;
public class Bubble
{
int color;
int y;
int x;
int r;
public Bubble ()
{
color = Color.rgb(rand(0,255), rand(0,255), rand(0,255));
r = rand(0,255);
x =rand(0,255);
y = rand(0,255);
}
public int getColor() {
return color;
}
public int getY() {
return y;
}
public int getX() {
return x;
}
public int getR() {
return r;
}
/******************************rand()*****************************/
public int rand(int a, int b)
{
return((int)((b-a+1)*Math.random() + a));
}
}
Thanks for any input, This is my first time messing with graphics so Im not 100% sure why this is happening.
you pass null to your method onDraw here:
dv.onDraw(null);
I guess you would want to pass a Canvas there.
In this method then your Canvas will point to null since you passed null as the param:
public void onDraw(Canvas c) {
Bubble b = new Bubble();
p.setColor(b.getColor());
p.setStyle(Paint.Style.FILL);
bList.add(b);
c.drawCircle(b.getX(), b.getY(), b.getR(), p); // c == null here!
}
==> NPE
as for your random method try this
Random rng = new Random();
in your field declarations.
then use. rng.nextInt(255);
color = Color.rgb(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255));
as for your circles: firstly you need an update method(if you want any movement)
secondly you should be using a surfaceView to draw, and thirdly you should use a
copyOnWriteArrayList, because your button may be modifying the list while its iterating over it, and copyonwritearraylist is perfect for that. here: my gift to you.
CLASS 1
import java.util.Random;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
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(){
radius+=4;
tripper+=change;
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);
}
}
CLASS2
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import com.gmaninc.acidrain2.R;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.service.wallpaper.WallpaperService;
import android.service.wallpaper.WallpaperService.Engine;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnTouchListener;
public class LiveWallpaperService extends WallpaperService {
CopyOnWriteArrayList<GrowCircle> gc = new CopyOnWriteArrayList<GrowCircle>();
private final Handler mHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public Engine onCreateEngine() {
return new CubeEngine();
}
class CubeEngine extends Engine {
private final Paint mPaint = new Paint();
private float mOffset;
private float mTouchX = -1;
private float mTouchY = -1;
private long mStartTime;
private float mCenterX;
private float mCenterY;
private final Runnable mDrawCube = new Runnable() {
public void run() {
drawFrame();
}
};
private boolean mVisible;
CubeEngine() {
// Create a Paint to draw the lines for our cube
final Paint paint = mPaint;
paint.setColor(0xffffffff);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
mStartTime = SystemClock.elapsedRealtime();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// By default we don't get touch events, so enable them.
setTouchEventsEnabled(true);
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mDrawCube);
}
#Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
drawFrame();
} else {
mHandler.removeCallbacks(mDrawCube);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
// store the center of the surface, so we can draw the cube in the right spot
mCenterX = width/2.0f;
mCenterY = height/2.0f;
for(GrowCircle circ:gc){
circ.update();
}
drawFrame();
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mDrawCube);
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xStep, float yStep, int xPixels, int yPixels) {
mOffset = xOffset;
drawFrame();
}
/*
* Store the position of the touch event so we can use it for drawing later
*/
#Override
public void onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mTouchX = event.getX();
mTouchY = event.getY();
} else {
mTouchX = -1;
mTouchY = -1;
}
float tx = event.getX();
float ty= event.getY();
gc.add(new GrowCircle(tx,ty));
super.onTouchEvent(event);
}
/*
* Draw one frame of the animation. This method gets called repeatedly
* by posting a delayed Runnable. You can do any drawing you want in
* here. This example draws a wireframe cube.
*/
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// draw something
drawCircs(c);
for(GrowCircle circ:gc){
if(circ.radius>350){
gc.remove(circ);
}
circ.update();
circ.drawThis(c);
}
drawTouchPoint(c);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawCube);
if (mVisible) {
mHandler.postDelayed(mDrawCube, 1000 / 25);
}
}
/*
* Draw a wireframe cube by drawing 12 3 dimensional lines between
* adjacent corners of the cube
*/
void drawCircs(Canvas c) {
c.save();
c.translate(mCenterX, mCenterY);
c.drawColor(0xff000000);
c.restore();
}
/*
* Draw a circle around the current touch point, if any.
*/
void drawTouchPoint(Canvas c) {
if (mTouchX >=0 && mTouchY >= 0) {
c.drawCircle(mTouchX, mTouchY, 80, mPaint);
}
}
}
}
MANIFEST
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gmaninc.acidrain2"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<service
android:name="LiveWallpaperService"
android:enabled="true"
android:label="Acid Rain 2"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" >
</action>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="#xml/mywallpaper" >
</meta-data>
</service>
</application>
</manifest>
this is a livewallpaper that creates circles onTouch... feel free to play around with it, you should find what you need in here....
NOTE: you may need to change the package name in the manifest to get it to run!

Android onTouchEvent in a view class

I've tried debugging with messages and stuff but the only value i get from event.getAction() is 0 ... which i believe is ACTION_DOWN why dont i detect ACTION_MOVE or ACTION_UP??
package com.andrewxd.test01;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
public class Game extends View {
private Bitmap enemy;
private Enemy enemyN;
private Paint paint;
private float x,y;
public Game(Context context) {
super(context);
enemy = BitmapFactory.decodeResource(getResources(), R.drawable.enemy);
enemy = Bitmap.createScaledBitmap(enemy, 300 , 300, false);
enemyN = new Enemy(10, 10, enemy);
paint = new Paint();
x = 0;
y = 0;
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawRect(x, y, 50, 50, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event){
super.onTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_DOWN){
x = event.getX();
y = event.getY();
invalidate();
} else if(event.getAction() == MotionEvent.ACTION_MOVE){
x = event.getX();
y = event.getY();
invalidate();
}
return false;
}
}
Am I doing something wrong? or is this supposed to work like this? And if this is supposed to be like this where do i detect touch movement
It's because you're returning false at the end of the onTouchEvent. When you return false, you are saying that your View can not handle any more touch events so the events will no longer be sent to the View. If you want to receive MOVE and UP events, then you need to return true.

Categories