I am trying to rotate 2 circles on the screen. On the press of a button, one circles rotates clockwise, and the other circles rotates counterclockwise. Both will rotate by 90 degrees and then stop until the next button click.
Its working but it looks very bad. Instead of rotating at the same time, 1st one circle rotates, and then the 2nd.
I read about animation but all the examples I found showed how to rotate the entire canvas. Possibly I am not looking in the right places and there is a way to assign animation to an object somehow.
I've added my code below. I apologies for it not being a true SSCCE but I got errors when my custom SurfaceView was an internal class under the main activity.
Any advice or lead on how to do this properly is very appreciated.
Activity
package sscce.android.rotation;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
public class SscceRotationActivity extends Activity implements OnClickListener {
private MySurfaceView mySurfaceView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.btnClockwise).setOnClickListener(this);
findViewById(R.id.btnCounterClockwise).setOnClickListener(this);
mySurfaceView = (MySurfaceView) (findViewById(R.id.surfaceView1));
}
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.btnClockwise:
mySurfaceView.rotate(true);
break;
case R.id.btnCounterClockwise:
mySurfaceView.rotate(false);
break;
}
}
}
Custom SurfaceView
package sscce.android.rotation;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private Circle circle1;
private Circle circle2;
private DrawThread drawThread;
public MySurfaceView(Context context) {
super(context);
initialize();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
private void initialize() {
getHolder().addCallback(this);
drawThread = new DrawThread(getHolder(), this);
setFocusable(true);
}
public void surfaceCreated(SurfaceHolder holder) {
circle1 = new Circle(getWidth() / 2, getHeight() / 2, 50);
circle2 = new Circle(getWidth() / 2, getHeight() / 2, 80);
drawThread.setRunning(true);
drawThread.start();
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry = true;
drawThread.setRunning(false);
while (retry) {
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public void onDraw(Canvas canvas) {
circle2.onDraw(canvas);
circle1.onDraw(canvas);
}
public void rotate(boolean clockWise) {
Rotator rotator1 = new Rotator(circle1, clockWise);
Rotator rotator2 = new Rotator(circle2, !clockWise);
rotator1.run();
rotator2.run();
}
private class Circle {
private RectF rectF;
private int rotationAngle = 0;
MyPaint bluePaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
Color.BLUE);
MyPaint redPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
Color.RED);
MyPaint yellowPaint = new MyPaint(1, Paint.Cap.SQUARE,
Paint.Style.FILL, Color.YELLOW);
MyPaint greenPaint = new MyPaint(1, Paint.Cap.SQUARE, Paint.Style.FILL,
Color.GREEN);
MyPaint borderPaint = new MyPaint(3, Paint.Cap.SQUARE,
Paint.Style.STROKE, Color.WHITE);
public Circle(int centerX, int centerY, int radius) {
rectF = new RectF(new Rect(centerX - radius, centerY - radius,
centerX + radius, centerY + radius));
}
public void rotateClockwise() {
for (int i = 0; i < 90; i++) {
rotationAngle++;
if (rotationAngle == 360) {
rotationAngle = 0;
return;
}
try {
Thread.sleep(20, 0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void rotateCounterClockwise() {
for (int i = 0; i < 90; i++) {
rotationAngle--;
if (rotationAngle == 0) {
rotationAngle = 360;
return;
}
try {
Thread.sleep(20, 0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void onDraw(Canvas canvas) {
canvas.drawArc(rectF, (0 + rotationAngle) % 360, 90, true,
bluePaint);
canvas.drawArc(rectF, (90 + rotationAngle) % 360, 90, true,
redPaint);
canvas.drawArc(rectF, (180 + rotationAngle) % 360, 90, true,
yellowPaint);
canvas.drawArc(rectF, (270 + rotationAngle) % 360, 90, true,
greenPaint);
canvas.drawArc(rectF, 0, 360, true, borderPaint);
}
private class MyPaint extends Paint {
public MyPaint(int strokeWidth, Paint.Cap cap, Paint.Style style,
int color) {
setStrokeWidth(strokeWidth);
setAntiAlias(true);
setStrokeCap(cap);
setStyle(style);
setColor(color);
}
}
}
private class Rotator extends Thread {
private Circle circle;
private boolean clockwise;
public Rotator(Circle circle, boolean clockwise) {
this.circle = circle;
this.clockwise = clockwise;
}
#Override
public void run() {
if (clockwise) {
circle.rotateClockwise();
} else {
circle.rotateCounterClockwise();
}
}
}
private class DrawThread extends Thread {
private SurfaceHolder surfaceHolder;
private MySurfaceView surfaceView;
private boolean run = false;
public DrawThread(SurfaceHolder surfaceHolder, MySurfaceView surfaceView) {
this.surfaceHolder = surfaceHolder;
this.surfaceView = surfaceView;
run = false;
}
public void setRunning(boolean run) {
Log.d("setRunning#DrawThread", "Run status is " + run);
this.run = run;
}
#Override
public void run() {
Canvas canvas = null;
while (run) {
try {
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
surfaceView.onDraw(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<sscce.android.rotation.MySurfaceView
android:id="#+id/surfaceView1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<Button
android:id="#+id/btnClockwise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clockwise" />
<Button
android:id="#+id/btnCounterClockwise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Counter Clockwise" />
</LinearLayout>
</LinearLayout>
I would like to advise a different approach to rotation using matrices.The code would look like
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(cwRotation);
//draw first circle here
canvas.restore();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(ccwRotation);
//draw second circle here
canvas.restore();
This approach has the advantage of being very straightforward and requiring no additional classes and APIs and it is similar to what you would do with OpenGL.
You'll have a lot more success if you replace your rotator1/2.run() lines with rotator1/2.start()
Related
In my SurfaceView when I click on the screen it creates black dots after that I connect them and it has a filled with color. After that I am ttrying to draw other bitmap and I want the current state be something like a background and when I touch the screen I want to draw a bitmap on this possition and when I am trying to draw a bitmap on touch location the canvas goes back to the previous state with the draws.
Here is my code:
package com.inveitix.android.clue.ui.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.inveitix.android.clue.R;
import com.inveitix.android.clue.cmn.Door;
import com.inveitix.android.clue.cmn.MapPoint;
import java.util.ArrayList;
import java.util.List;
public class DrawingView extends SurfaceView {
private static final String TAG = "DrawingView";
private static final float DOOR_SIZE = 30;
private Paint paint;
private Canvas canvas;
private int maxHeight;
private int maxWidth;
private SurfaceHolder surfaceHolder;
private List<MapPoint> shape;
private List<Door> doors;
private float ratio;
private boolean isFloorFinished;
private boolean isDoorSelected;
Path path;
public DrawingView(Context context) {
super(context);
init();
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setIsDoorSelected(boolean isDoorSelected) {
this.isDoorSelected = isDoorSelected;
}
public void setIsFloorFinished(boolean isFloorFinished) {
this.isFloorFinished = isFloorFinished;
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
isFloorFinished = false;
surfaceHolder = this.getHolder();
prepareCanvas();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
shape = new ArrayList<>();
doors = new ArrayList<>();
}
private void prepareCanvas() {
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceCreated(SurfaceHolder holder) {
canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
holder.unlockCanvasAndPost(canvas);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int minh = getPaddingBottom() + getPaddingTop() + getSuggestedMinimumHeight();
this.maxWidth = resolveSizeAndState(minw, widthMeasureSpec, 1);
this.maxHeight = resolveSizeAndState(minh, heightMeasureSpec, 1);
if (ratio != 0) {
maxHeight = (int) (maxWidth / ratio);
}
Log.i(TAG, "onMeasure width:" + maxWidth);
Log.i(TAG, "onMeasure height:" + maxHeight);
setMeasuredDimension(maxWidth, maxHeight);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isFloorFinished) {
if (surfaceHolder.getSurface().isValid()) {
shape.add(new MapPoint(event.getX(), event.getY()));
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for (MapPoint point : shape) {
canvas.drawCircle(point.getX(), point.getY(), 10, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
} else if (event.getAction() == MotionEvent.ACTION_DOWN && isDoorSelected) {
if (surfaceHolder.getSurface().isValid()) {
Door door = new Door();
door.setConnectedTo("door1"); //this is for test
door.setX(event.getX());
door.setY(event.getY());
doors.add(door);
canvas = surfaceHolder.lockCanvas();
drawDoors(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
return false;
}
public void drawFloor() {
Bitmap bmpFloorPattern = BitmapFactory.decodeResource(getResources(), R.drawable.floor_pattern6);
BitmapShader patternBMPshader = new BitmapShader(bmpFloorPattern,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
canvas = surfaceHolder.lockCanvas();
path = new Path();
path.reset();
if (shape != null) {
path.moveTo(shape.get(0).getX(), shape.get(0).getY());
alignPoints(path);
canvas.drawColor(Color.WHITE);
for (int i = 0; i < shape.size(); i++) {
path.lineTo(shape.get(i).getX(), shape.get(i).getY());
}
}
paint.setShader(patternBMPshader);
path.close();
canvas.drawPath(path, paint);
paint.setShader(null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
public void drawDoors(Canvas canvas) {
Bitmap bmpDoor = BitmapFactory.decodeResource(getResources(), R.drawable.door32);
paint.setFilterBitmap(true);
if (doors != null && doors.size() > 0) {
for (Door door : doors) {
canvas.drawBitmap(bmpDoor, door.getX() - DOOR_SIZE, door.getY() - DOOR_SIZE, null);
}
}
}
private void alignPoints(Path path) {
MapPoint previousPoint = null;
for (int i = 0; i < shape.size(); i++) {
float x = shape.get(i).getX();
float y = shape.get(i).getY();
if (previousPoint != null) {
float deltaX = Math.abs(x - previousPoint.getX());
float deltaY = Math.abs(y - previousPoint.getY());
if (Math.max(deltaX, deltaY) == deltaX) {
x = previousPoint.getX();
} else {
y = previousPoint.getY();
}
}
path.lineTo(x, y);
previousPoint = shape.get(i);
}
}
public void setWidthToHeightRatio(float ratio) {
this.ratio = ratio;
maxHeight = (int) (maxWidth / ratio);
invalidate();
requestLayout();
}
}
Any ideas how to draw over the drawn background ?
I found it I have to draw doors in the same time with the floor so I did this changes:
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isFloorFinished) {
if (surfaceHolder.getSurface().isValid()) {
shape.add(new MapPoint(event.getX(), event.getY()));
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
for (MapPoint point : shape) {
canvas.drawCircle(point.getX(), point.getY(), 10, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
} else if (event.getAction() == MotionEvent.ACTION_DOWN && isDoorSelected) {
if (surfaceHolder.getSurface().isValid()) {
Door door = new Door();
door.setConnectedTo("door1"); //this is for test
door.setX(event.getX());
door.setY(event.getY());
doors.add(door);
drawFloor();
}
}
return false;
}
public void drawFloor() {
Bitmap bmpFloorPattern = BitmapFactory.decodeResource(getResources(), R.drawable.floor_pattern6);
BitmapShader patternBMPshader = new BitmapShader(bmpFloorPattern,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
canvas = surfaceHolder.lockCanvas();
path = new Path();
path.reset();
if (shape != null) {
path.moveTo(shape.get(0).getX(), shape.get(0).getY());
alignPoints(path);
canvas.drawColor(Color.WHITE);
for (int i = 0; i < shape.size(); i++) {
path.lineTo(shape.get(i).getX(), shape.get(i).getY());
}
}
paint.setShader(patternBMPshader);
path.close();
canvas.drawPath(path, paint);
paint.setShader(null);
if(doors.size() > 0) {
drawDoors();
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
I'm using SurfaceView for driving sprites.
For performance, I only redraw canvas partially, so I lock the Canvas with dirty rect. In general, it works good, but SurfaceView lost initial drawing in surfaceCreated method.
I suppose it's related to SurfaceView internal double buffering.
Any ideas how to correctly initialize SurfaceView?
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class TestView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = TestView.class.getSimpleName();
SurfaceHolder holder;
public TestView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
drawBg();
drawPoint(100, 120);
}
private void drawBg() {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized (holder) {
canvas.drawRGB(255, 128, 128);
Paint paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawCircle(100, 100, 10, paint);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
private void drawPoint(int x, int y) {
int radius = 10;
Rect dirty = new Rect(x - radius, y - radius, x + radius, y + radius);
Canvas canvas = null;
try {
canvas = holder.lockCanvas(dirty);
synchronized (holder) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(x, y, radius, paint);
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
drawPoint((int) event.getX(), (int) event.getY());
}
return super.onTouchEvent(event);
}
}
I am beginner to multithreading in Java and in my Android application, i have that SurfaceView on wich am drawing a circle randomlly but i want to be able to pause that drawing by pressing the screen (ACTION_DOWN) and resume it the next time i press it again :
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView /**/implements SurfaceHolder.Callback {
private float x = 100;
private float y = 100;
private int radius = 20;
private Paint paint;
private SurfaceHolder mSurfaceHolder;
private DrawingThread mThread;
private Context myContext;
public GameView(Context context) {
super(context);
this.myContext = context;
setWillNotDraw(false);
paint = new Paint();
/**/
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setTextAlign(Paint.Align.LEFT);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
//paint.setTextSize(15);
}
public void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
/**/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new DrawingThread(mSurfaceHolder, myContext);
mThread.mRun = true;
mThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
public synchronized boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int)event.getX();
int Y = (int)event.getY();
switch (eventaction ) {
case MotionEvent.ACTION_DOWN:
this.mThread.canPause = !this.mThread.canPause;
synchronized(this.mSurfaceHolder){
if(this.mThread.canPause){
this.mSurfaceHolder.notify();
}
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
public final class DrawingThread extends Thread {
public boolean canPause = false;
boolean mRun;
Canvas mcanvas;
SurfaceHolder surfaceHolder;
Context context;
public DrawingThread(SurfaceHolder sholder, Context ctx)
{
surfaceHolder = sholder;
context = ctx;
mRun = false;
}
void setRunning(boolean bRun)
{
mRun = bRun;
}
boolean keepDrawing = true;
#Override
public void run() {
while (keepDrawing) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
while(canPause){
try {
mSurfaceHolder.wait();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
waitThreaed();
draw(canvas);
}
}
catch(Exception e){
}
finally {
if (canvas != null)
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
public void waitThreaed() {
try {
x = (float) (getWidth()*Math.random());
y = (float) (getHeight()*Math.random());
this.sleep(1000);
postInvalidate();
} catch (InterruptedException e) {
}
}
}
}
In fact with that code the drawing can be paused but can not be resumed
In order to call wait() you must have synchronized on the object you are waiting on.
See this question for a discussion of that: Why must wait() always be in synchronized block
I am trying to draw on a surface view, but I get a black screen. My xml layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<com.example.surfaceview.MySurface android:id="#+id/padview"
android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>
Important parts of my code: MySurface.java
public class MySurface extends SurfaceView implements SurfaceHolder.Callback {
public DrawingThread thread;
public MySurface(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder surfaceholder = getHolder();
surfaceholder.addCallback(this);
thread = new DrawingThread(surfaceholder, context, new Handler() {
#Override
public void handleMessage(Message m) {
// Do some handle thing
}
});
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder tholder, int format, int width, int height) {
thread.setSurfaceSize(width, height);
thread.holder = tholder;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.running = true;
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.running = false;
while(retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public Thread getThread() {
return thread;
}
public class DrawingThread extends Thread {
private SurfaceHolder holder;
private Context context;
private Handler handle;
private Paint background;
private Rect blank;
public boolean running;
public boolean created;
public int canvasheight;
public int canvaswidth;
public PadThread(SurfaceHolder tholder, Context tcontext, Handler thandler) {
holder = tholder;
context = tcontext;
handle = thandler;
// Temporary canvas dimentions
canvaswidth = 1;
canvasheight = 1;
running = false;
created = false;
background = new Paint();
background.setColor(R.color.white);
blank = new Rect(0, 0, canvaswidth, canvasheight);
}
#Override
public void run() {
Log.d("SurfaceView Test", "Drawing thread run");
while(running) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized(holder) {
// update object states
// get user input gestures
drawing(canvas);
}
} finally {
if(canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
}
private void drawing(Canvas canvas) {
// Clear screen
canvas.drawRect(blank, background);
// Draw Things
}
public void setSurfaceSize(int width, int height) {
synchronized(holder) {
canvaswidth = width;
canvasheight = height;
// New background rect
blank.set(0, 0, canvaswidth, canvasheight);
}
}
}
}
The code is based off of Google's Lunar Landar SurfaceView example at http://developer.android.com/resources/samples/LunarLander/index.html
I know that all of the code is being reached through logging.
change drawing function
background.setColor(Color.RED);
canvas.drawRect(new Rect(10, 10, 100, 100), background);
(There are test values for colors and rect)
How can I draw multiple canvases on Live Wallpaper?
I want a live wallpaper having a background image (bitmap), and on the image there would be an object, which follows your finger. But I can't draw more than one canvas.
I've already went through Google, but I didn't find anythink helpful.
Is there any way to produce this?
Here's my (not working) code for this:
package i.need.some.help;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class NewMyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new CubeEngine();
}
class CubeEngine extends Engine {
private final Paint mPaint = new Paint();
private final Paint myPaint = new Paint();
private float mTouchX = 0;
private float mTouchY = 0;
Bitmap movingObject = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
final SurfaceHolder holder = getSurfaceHolder();
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
int width = Resources.getSystem().getDisplayMetrics().widthPixels;
Bitmap backroundIMG = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round);
CubeEngine() {
setBackground();
}
#Override
public void onCreate (SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
// Touch event handle alert
setTouchEventsEnabled(true);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
#Override
public void onTouchEvent (MotionEvent event) {
super.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
mTouchX = event.getX();
mTouchY = event.getY();
} else {
mTouchX = event.getX();
mTouchY = event.getY();
}
drawFrame();
}
void drawFrame() {
Canvas c = null;
try {
c = holder.lockCanvas();
if (c !=null) {
c.save();
c.drawBitmap(movingObject, mTouchX-(movingObject.getWidth()/2), mTouchY-(movingObject.getHeight()/2), mPaint);
c.restore();
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
final void setBackground() {
Canvas ca = null;
try {
ca = holder.lockCanvas();
if (ca !=null) {
ca.save();
ca.drawColor(0xffa8a8a8);
ca.drawBitmap(backroundIMG, height/2, width/2, myPaint);
ca.restore();
}
} finally {
if (ca != null) {
holder.unlockCanvasAndPost(ca);
}
}
}
}
}