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);
}
}
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 have the following problem.
I am trying to code a Tetris Game for Android. Therefore I need to put a Grid on the GameView (a self coded class, which extends the SurfaceVieW).
Unfortunately I do not know how to draw the Grid on the GameView.
I already implemented a Grid class, which sets the width and height of the rows and columns.
My Grid Class
package com.example.tetris;
import android.content.Context;
import android.graphics.Paint;
import android.widget.GridView;
public class Grid extends GridView
{
private int rowsWidth;
private int columnsHeight;
private int rowsNum;
private int columnsNum;
private Paint gridcolor;
private GameView gameview;
public Grid(Context context)
{
super(context);
}
public void drawGrid(GameView gameview)
{
this.gameview = gameview;
rowsWidth = gameview.getWidth() / 10;
rowsNum = gameview.getWidth() / rowsWidth;
columnsHeight = gameview.getHeight()/rowsWidth;
columnsNum = gameview.getHeight() / columnsHeight;
setHorizontalSpacing(1);
setColumnWidth(rowsWidth);
setNumColumns(columnsNum);
}
}
My GameView Class
package com.example.tetris;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.GridView;
public class GameView extends SurfaceView {
private SurfaceHolder surfaceHolder;
private Tetriminos[] tetriminos[];
private GridView grid;
public GameView(Context context)
{
super(context);
final GameLoopThread gameloop = new GameLoopThread(this); // warum er final erzwingt, ka
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameloop.setRunning(true);
gameloop.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
gameloop.setRunning(false);
}
});
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
drawBorders(canvas);
// grid.drawGrid(this);
}
public boolean onTouchEvent(MotionEvent event) {
return false;
}
public void drawBorders(Canvas canvas)
{
int borderwidth = 10;
int screenWidth = getWidth();
int screenHeight = getHeight();
Paint bordercolor = new Paint();
bordercolor.setARGB(255, 236, 27, 36);
canvas.drawRect(0, 0, borderwidth, getHeight(), bordercolor);
canvas.drawRect(0, getHeight()-borderwidth, getWidth(), getHeight(), bordercolor);
canvas.drawRect(getWidth()-borderwidth, 0, getWidth(), getHeight(), bordercolor);
canvas.drawRect(0, 0, getWidth(), borderwidth, bordercolor);
}
}
I'm developing in android, and I have to do a Paint for android.
I'm using the code below and, when I execute the code, the draw works, but, it seems that there are 2 surfaces to paint, and when you draw in one, the other one disappears.
I was looking for the exact error, but cannot find it.
Here is the code :
import java.util.Random;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
MySurfaceView mySurfaceView;
Button Cuadrado;
Button Circulo;
Button Color;
Button Linea;
private boolean Bcuadrado,Bcirculo,Bcolor=false;
private boolean Blinea=true;
Canvas canvas = new Canvas();
#TargetApi(11)
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout mainLayout =(RelativeLayout)findViewById(R.id.main_layout_id );
View view =getLayoutInflater().inflate(R.layout.itemlayout, mainLayout,false);
mainLayout.addView(view);
mySurfaceView = new MySurfaceView(this);
Cuadrado=(Button)findViewById(R.id.button1);
Circulo=(Button)findViewById(R.id.button2);
Color=(Button)findViewById(R.id.button3 );
Linea=(Button)findViewById(R.id.button4 );
int w= view.getWidth();
int h= view.getHeight();
float x=view.getX();
float y= view.getY();
mySurfaceView.setY(100);
mainLayout.addView(mySurfaceView);
Cuadrado.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(Bcuadrado==false){
Bcuadrado=true;
Bcirculo=false;
Bcolor=false;
Blinea=false;
}
}
});
Circulo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Bcirculo){
Bcuadrado=false;
Bcirculo=true;
Bcolor=false;
Blinea=false;
}
}
});
Color.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Bcolor){
Bcuadrado=false;
Bcirculo=false;
Bcolor=true;
Blinea=false;
}
}
});
Linea.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(!Blinea){
Bcuadrado=false;
Bcirculo=false;
Bcolor=false;
Blinea=true;
}
}
});
}
class MySurfaceView extends SurfaceView{
Path path;
SurfaceHolder surfaceHolder;
volatile boolean running = false;
private Paint paint = new Paint();
float x0=0;
float x1=0;
float y0=0;
float y1=0;
Random random = new Random();
public MySurfaceView(Context context) {
super(context);
surfaceHolder = getHolder();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(android.graphics.Color.WHITE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(Blinea){
if(event.getAction() == MotionEvent.ACTION_DOWN){
path = new Path();
path.moveTo(event.getX(), event.getY());
}else if(event.getAction() == MotionEvent.ACTION_MOVE){
path.lineTo(event.getX(), event.getY());
}else if(event.getAction() == MotionEvent.ACTION_UP){
path.lineTo(event.getX(), event.getY());
}
if(path != null){
canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcuadrado){
if(event.getAction()==MotionEvent.ACTION_DOWN){
x0=event.getX();
y0=event.getY();
}
else if(event.getAction()==MotionEvent.ACTION_UP){
x1=event.getX();
y1=event.getY();
canvas = surfaceHolder.lockCanvas();
canvas.drawRect(x0, y0, x1, y1, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcirculo){
if(event.getAction()==MotionEvent.ACTION_DOWN){
x0=event.getX();
y0=event.getY();
}
else if(event.getAction()==MotionEvent.ACTION_UP){
x1=event.getX();
canvas=surfaceHolder.lockCanvas();
canvas.drawCircle(x0, y0,(x1-x0), paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}else if(Bcolor){
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
canvas=surfaceHolder.lockCanvas();
paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
surfaceHolder.unlockCanvasAndPost(canvas);
}
return true;
}
}
}
it seems that there are 2 surfaces to paint, and when you draw in one, the other one disappears.
That is exactly how SurfaceView works - it's double buffered. You need to redraw whole frame each time.
From Android's doc: SurfaceHolder
The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written. The only exception to this rule is when a dirty rectangle is specified, in which case, non-dirty pixels will be preserved.
The canvas does not save what you previously wrote to it. Every time you call unlock(), you must redraw everything all over again.
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()
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);
}
}
}
}
}