Android - Moving text issue - android

I'm trying to create moving text.I have crated surface view and thread for looping it.but it not show me a moving motion but draw that text each after like * ** * * in infinite.
But what I need was move that this point to that** -> ** got it?
this is my code
package com.CurvePackage.Curve;
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.Toast;
public class Origin extends SurfaceView implements SurfaceHolder.Callback {
Context context1;
private MainThread thread;
private int x=0;
private int y=0;
public Origin(Context context) {
super(context);
// TODO Auto-generated constructor stub
setWillNotDraw(false);
context1 = context;
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(23);
paint.setFakeBoldText(true);
paint.setColor(Color.YELLOW);
// int score=(10-sprites.size()*100);
x=x+20;
y=y+20;
canvas.drawText("ewqewqe", x, y, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return super.onTouchEvent(event);
// Toast.makeText(getba, "Replay clicked!", Toast.LENGTH_SHORT).show();
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
thread.setRunning(false);
// TODO Auto-generated method stub
// boolean retry = true;
// while (retry) {
// try {
// thread.join();
// retry = false;
// } catch (InterruptedException e) {
// // try again shutting down the thread
// }
// }
}
}
Main Thread
package com.CurvePackage.Curve;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
// flag to hold game state
private boolean running;
private SurfaceHolder surfaceHolder;
private Origin origin;
static final long FPS = 15;
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = origin.getHolder().lockCanvas();
synchronized (origin.getHolder()) {
origin.onDraw(c);
}
} finally {
if (c != null) {
origin.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
public MainThread(SurfaceHolder surfaceHolder, Origin origin) {
super();
this.surfaceHolder = surfaceHolder;
this.origin = origin;
}
}

You need to paint the entire background in your onDraw method, before you paint your text.
Paint p2 = new Paint();
p2.setStyle(Style.FILL);
canvas.drawRect(0, 0, screenWidth, screenHeight, p2);
//draw text here
This will completely paint over the text from the previous time the canvas was drawn, and will remove this dragging effect.

Related

Pause and resume threads in Android

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

How to draw a view with animation in android?

I want to draw view like this image with animation. First i want draw circle then eyes and then mouth(arch like view ) with smooth animation. can we achieve such kind of animation? . Here i am getting problem of positioning the view eye and arc mouth.
Try this please
> AnimView.java
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
public class AnimView extends SurfaceView implements Runnable,
Callback {
Paint paint = new Paint();
Thread thread = null;
SurfaceHolder surfaceHolder;
boolean running=false;
long time=0;
int pos=0;
public AnimView(Context context) {
super(context);
paint.setColor(Color.GREEN);
surfaceHolder = getHolder();
}
public AnimView(Activity context) {
// TODO Auto-generated constructor stub
super(context);
paint.setColor(Color.GREEN);
surfaceHolder = getHolder();
}
public void onResumeMySurfaceView() {
thread = new Thread(AnimView.this);
thread.start();
running=true;
}
public void onPauseMySurfaceView() {
boolean retry = true;
running = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
// #Override
// public void onDraw(Canvas canvas) {
// canvas.drawLine(0, 0, 20, 20, paint);
// canvas.drawLine(20, 0, 0, 20, paint);
// Log.i("onDraw","Draw");
//
// }
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
#Override
public void run() {
// TODO Auto-generated method stub
while(running)
{
if(time==0)
{
time=System.currentTimeMillis();
pos=0;
}
if((System.currentTimeMillis()-time) >3000)
{
pos=1;
}
if((System.currentTimeMillis()-time) >6000)
{
pos=2;
}
if((System.currentTimeMillis()-time) >9000)
{
pos=3;
}
if((System.currentTimeMillis()-time) >12000)
{
pos=0;
time=System.currentTimeMillis();
}
Canvas canvas = surfaceHolder.lockCanvas();
if(canvas!=null)
{
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, this.getWidth(),this.getHeight(), paint);
if(pos>0)
{
paint.setColor(Color.GREEN);
canvas.drawCircle(200, 200, 50, paint);
paint.setColor(Color.WHITE);
canvas.drawCircle(200, 200, 48, paint);
}
if(pos>1)
{
paint.setColor(Color.GREEN);
canvas.drawCircle(175, 185, 5, paint);
canvas.drawCircle(225, 185, 5, paint);
}
if(pos>2)
{
paint.setStrokeWidth(5);
// opacity
//p.setAlpha(0x80); //
RectF rectF = new RectF(160, 160, 240, 240);
canvas.drawArc (rectF, 45, 135, true, paint);
rectF = new RectF(159, 159, 238, 238);
paint.setColor(Color.WHITE);
canvas.drawArc (rectF, 35, 145, true, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
Log.i("onDraw","Draw");
}
}
}
>MainActivity.java
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
AnimView av;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
av=new AnimView(this);
setContentView(av);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
av.onPauseMySurfaceView();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
av.onResumeMySurfaceView();
}
}

SurfaceView drawing failure

I am trying an example having SurfaceView. I have inherited my class from SurfaceView and using as follows:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
Context context;
MySurfaceViewThread mThread;
SurfaceHolder holder;
Paint paint;
int x = 20, y = 20, r = 10;
public void init() {
holder = getHolder();
holder.addCallback(this);
mThread = new MySurfaceViewThread(getHolder(), this);
paint = new Paint();
paint.setStyle(Style.STROKE);
paint.setStrokeCap(Cap.ROUND);
paint.setStrokeWidth(1);
paint.setColor(Color.rgb(255, 255, 255));
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context = context;
init();
}
public MySurfaceView(Context context, AttributeSet attr) {
super(context,attr);
this.context = context;
init();
}
public MySurfaceView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
this.context = context;
init();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mThread.isRunning = false;
while (true) {
try {
mThread.join();
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// canvas.drawColor(0, Mode.CLEAR);
x += 2;
y += 2;
r += 3;
canvas.drawColor(Color.rgb(x%255, y%255, (x+y)%255));
canvas.drawCircle(x, y, r, paint);
canvas.drawText("x:"+x, 100, 100, paint);
Log.d("onDraw","onDraw()"+"x:"+x + ",y:"+y+",r:"+r);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.d("surfaceCreated", "surfaceCreated()");
mThread.isRunning = true;
mThread.start();
}
}
I am updating my Canvas from a Thread which is:
public class MySurfaceViewThread extends Thread {
SurfaceHolder holder;
MySurfaceView surfaceView;
boolean isRunning = false;
public MySurfaceViewThread(SurfaceHolder holder, MySurfaceView surfaceView) {
Log.d("thread","thread constructor");
this.holder = holder;
this.surfaceView = surfaceView;
}
#Override
public void run() {
Log.d("run","run()");
while(isRunning) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
synchronized(holder) {
surfaceView.onDraw(canvas);
}
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
holder.unlockCanvasAndPost(canvas);
Log.d("canvas status", "canvas unlocaked...");
}
}
}
}
When application starts and its onDraw() is called, it draws circle and text as well but on further calls to onDraw() it draws nothing. Means nothing changed on screen after first update. Any idea where I am getting wrong? I am new to android and slow learner as well.
I got the answer. Its very strange. I don't know why this worked.
I commented the following line from my activity and it runs.
surfaceView.setBackgroundColor(Color.rgb(0, 255, 0));
the activity code is:
public class SurfaceViewTutorialActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MySurfaceView surfaceView = new MySurfaceView(this);
// surfaceView.setBackgroundColor(Color.rgb(0, 255, 0));
surfaceView.setBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
setContentView(surfaceView);
}
}
If any one knows about this, kindly guide me to the right direction.

Failing to execute code on android game

I am making an android game that should display a message that you have lost a certain point. But however, its failing of some reason that i cant possibly figure out. On checkLivesLeftValue(), it calls onMethod() if the user has used up all of the three lives he got. But then, when i am creating a toast, the application fails, why???
This is my java code:
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleView extends SurfaceView implements SurfaceHolder.Callback
{
class ExampleThread extends Thread
{
private ArrayList<Parachuter> parachuters;
private Bitmap parachuter;
private Paint black;
private boolean running;
private SurfaceHolder mSurfaceHolder;
private Context mContext;
private Handler mHandler;
private GameScreenActivity mActivity;
private long frameRate;
private boolean loading;
public float x;
public float y;
public MediaPlayer mp1;
public int parachuterIndexToResetAndDelete;
public int canvasGetWidth;
public int livesLeftValue;
public ExampleThread(SurfaceHolder sHolder, Context context, Handler handler)
{
mSurfaceHolder = sHolder;
mHandler = handler;
mContext = context;
mActivity = (GameScreenActivity) context;
parachuters = new ArrayList<Parachuter>();
parachuter = BitmapFactory.decodeResource(getResources(), R.drawable.parachuteman);
black = new Paint();
black.setStyle(Paint.Style.FILL);
black.setColor(Color.WHITE);
running = true;
// This equates to 26 frames per second.
frameRate = (long) (1000 / 26);
loading = true;
}
#Override
public void run()
{
while (running)
{
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder)
{
long start = System.currentTimeMillis();
doDraw(c);
long diff = System.currentTimeMillis() - start;
if (diff < frameRate)
Thread.sleep(frameRate - diff);
}
} catch (InterruptedException e)
{
}
finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
protected void doDraw(Canvas canvas)
{
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), black);
canvasGetWidth = canvas.getWidth();
//Draw
for (int i = 0; i < parachuters.size(); i++)
{
canvas.drawBitmap(parachuter, parachuters.get(i).getX(), parachuters.get(i).getY(), null);
parachuters.get(i).tick();
}
//Remove
for (int i = 0; i < parachuters.size(); i++)
{
if (parachuters.get(i).getY() > canvas.getHeight()) {
parachuters.remove(i);
onPlaySound();
onMethod();
checkLivesLeftValue();
}
}
}
public void onPlaySound()
{
try {
mp1 = MediaPlayer.create(getContext(), R.raw.bombsound);
mp1.start();
} catch (Exception e) {
e.printStackTrace();
mp1.release();
}
}
public void onMethod() {
Toast.makeText(getContext(), "You lost!", 15).show();
}
private void checkLivesLeftValue() {
// TODO Auto-generated method stub
if (livesLeftValue == 3) {
//Message to display: "You lost!"
onMethod();
}
else {
livesLeftValue = livesLeftValue + 1;
}
}
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() != MotionEvent.ACTION_DOWN)
return false;
float x1 = event.getX();
float y1 = event.getY();
initiateDrawParachuters();
return true;
}
public void initiateDrawParachuters()
{
drawParachuter1();
}
private void drawParachuter1() {
// TODO Auto-generated method stub
//Parachuter nr. 1
x = 68;
y = 40;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
drawParachuter2();
}
private void drawParachuter2() {
// TODO Auto-generated method stub
//Parachuter nr. 2
x = 100;
y = 80;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
drawParachuter3();
}
private void drawParachuter3() {
// TODO Auto-generated method stub
//Parachuter nr. 3
x = 150;
y = 120;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
drawParachuter4();
}
private void drawParachuter4() {
// TODO Auto-generated method stub
//Parachuter nr. 4
x = 170;
y = 150;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
drawParachuter5();
}
private void drawParachuter5() {
// TODO Auto-generated method stub
//Parachuter nr. 5
x = 180;
y = 170;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
drawParachuter6();
}
private void drawParachuter6() {
// TODO Auto-generated method stub
//Parachuter nr. 6
x = 200;
y = 180;
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
}
public void drawParachuters()
{
Parachuter p = new Parachuter(x, y);
parachuters.add(p);
Toast.makeText(getContext(), "x=" + x + " y=" + y, 15).show();
}
public void setRunning(boolean bRun)
{
running = bRun;
}
public boolean getRunning()
{
return running;
}
}
/** Handle to the application context, used to e.g. fetch Drawables. */
private Context mContext;
/** Pointer to the text view to display "Paused.." etc. */
private TextView mStatusText;
/** The thread that actually draws the animation */
private ExampleThread eThread;
public ExampleView(Context context)
{
super(context);
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// create thread only; it's started in surfaceCreated()
eThread = new ExampleThread(holder, context, new Handler()
{
#Override
public void handleMessage(Message m)
{
// mStatusText.setVisibility(m.getData().getInt("viz"));
// mStatusText.setText(m.getData().getString("text"));
}
});
setFocusable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return eThread.onTouchEvent(event);
}
public ExampleThread getThread()
{
return eThread;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder)
{
if (eThread.getState() == Thread.State.TERMINATED)
{
eThread = new ExampleThread(getHolder(), getContext(), getHandler());
eThread.start();
}
else
{
eThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
eThread.setRunning(false);
while (retry)
{
try
{
eThread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
}
And this is my logcat output:
03-24 16:32:59.442: W/dalvikvm(363): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
03-24 16:32:59.641: E/AndroidRuntime(363): FATAL EXCEPTION: Thread-8
03-24 16:32:59.641: E/AndroidRuntime(363): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
03-24 16:32:59.641: E/AndroidRuntime(363): at android.os.Handler.<init>(Handler.java:121)
03-24 16:32:59.641: E/AndroidRuntime(363): at android.widget.Toast.<init>(Toast.java:68)
03-24 16:32:59.641: E/AndroidRuntime(363): at android.widget.Toast.makeText(Toast.java:231)
03-24 16:32:59.641: E/AndroidRuntime(363): at com.mysoftwaremobileapps.ParachuteHunter.ExampleView$ExampleThread.onMethod(ExampleView.java:135)
03-24 16:32:59.641: E/AndroidRuntime(363): at com.mysoftwaremobileapps.ParachuteHunter.ExampleView$ExampleThread.doDraw(ExampleView.java:116)
03-24 16:32:59.641: E/AndroidRuntime(363): at com.mysoftwaremobileapps.ParachuteHunter.ExampleView$ExampleThread.run(ExampleView.java:79)
03-24 16:33:03.842: I/Process(363): Sending signal. PID: 363 SIG: 9
You are creating a Toast from Thread, which is not having a Looper attached to it. The simplest solution is to create a Toast from UI thread which is having Looper by default.
Also, you already having a Handler, which is created inside a View constructor. You can use this Handler to post some Runnable to UI thread and create Toast there.
public void onMethod() {
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getContext(), "You lost!", 15).show();
}
});
}

Android - How to rotate multiple 2D graphic objects

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()

Categories

Resources