I have an android application showing coverflow animation.I want to use view extending surfaceview inside coverflow.But this code did not show anything.
public class CoverFlowView extends SurfaceView implements Callback {
public CoverFlowView(Context context) {
super(context);
}
public CoverFlowView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CoverFlowView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
MyThread myThread = new MyThread(holder);
myThread.setFlag(true);
myThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint borderPaint = new Paint();
borderPaint.setARGB(255, 255, 128, 0);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(4);
canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, borderPaint);
}
class MyThread extends Thread {
boolean flag;
SurfaceHolder myHolder;
public MyThread(SurfaceHolder holder) {
myHolder = holder;
}
public void setFlag(boolean myFlag) {
flag = myFlag;
}
public void run() {
Canvas canvas = null;
while (flag) {
try {
canvas = myHolder.lockCanvas();
synchronized (myHolder) {
invalidate();
}
} finally {
if (canvas != null) {
myHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}
What is the problem here?I am new with Surfaceview.
Thanks in advance.
Rewrite your code like this , then it will work fine, i have checked it
public class CoverFlowView extends SurfaceView implements SurfaceHolder.Callback {
then change your constructor to
public CoverFlowView(Context context) {
super(context);
getHolder().addCallback(this);
}
Related
I have following TextView
public class Cube extends TextView {
Context mContext;
Drawable background;//Hintergrund des Blocks
char mLetter;//Buchstabe des Blocks
int x, y;//Koordinaten des Blocks
#SuppressWarnings("deprecation")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Cube(Context context, char letter, int _x, int _y) {
super(context);
mContext = context;
mLetter = letter;
background = ContextCompat.getDrawable(getContext(), R.drawable.cube);
x = _x;
y = _y;
this.setText("" + letter);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
this.setBackgroundDrawable(background);
else
this.setBackground(background);
}
public void drawCube(Canvas canvas){//how to draw now!? This is called from a separate thread in SurfaceView
}
}
If I call following in drawCube():
background.setBounds(x, y, x + 20, y + 20);
background.draw(canvas);
it just draws the backgroundDrawable. But how can I draw it with the text/the letter inside? That it looks like this: (The background ist the canvas, the orange and white one is the Background and the "A" is the letter/text)
EDIT: Code at 21.09
This is my (shortened) thread:
public class CanvasThread extends Thread {
private SurfaceHolder mSh;
private ArrayList<Cube> mCubes;
private Canvas mCanvas;
private Context mContext;
private boolean mRun = false;
private boolean mDown = false;
private boolean newCube = false;
public CanvasThread(SurfaceHolder sh, Context context){
mSh = sh;
mCubes = new ArrayList<>();
mContext = context;
}
public void run(){
while(mRun){
mCanvas = null;
try{
mCanvas = mSh.lockCanvas(null);
synchronized (mSh){
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
newCube = true;
for(int i = 0; i < mCubes.size(); i++){
if(mCubes.get(i).getSpeed() > 0)
newCube = false;
if(mDown) {
if (mCubes.get(i).moveDown(feld)) {
mDown = false;
}
}
//mCubes.get(i).invalidate();
//mCubes.get(i).requestLayout();
mCubes.get(i).draw(mCanvas);
}
if(newCube)
addCube();
}
} finally {
if(mCanvas != null){
mSh.unlockCanvasAndPost(mCanvas);
}
}
}
}
public void addCube(){
Random r = new Random();
Cube cube = new Cube(mContext, mBuchstaben[r.nextInt(29)], r.nextInt(10), 0, mCanvas);
mCubes.add(cube);
}
}
This is my (shortened) fragment which uses the canvas/surface view:
public class KlassischFragment extends Fragment implements SurfaceHolder.Callback {
SurfaceHolder sh;
SurfaceView sv;
private CanvasThread thread;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_klassisch, container, false);
sv = (SurfaceView) view.findViewById(R.id.surfaceView);
sh = sv.getHolder();
sh.addCallback(this);
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
return view;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new CanvasThread(sh, getContext());
thread.setRunnable(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
//thread.setRunnable(false);
while(retry){
try{
thread.join();
retry = false;
} catch(InterruptedException ie){
//Immer wieder versuchen
}
break;
}
thread = null;
}
}
Here is an example on how to draw a text on top of a square. Some of the values hardcoded but you should be able to make them dynamic.
public class Cube extends View {
private final static String TEST_STRING = "ABC";
private Paint mBackgroundPaint;
private Paint mTextPaint;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public Cube(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public Cube(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public Cube(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public Cube(Context context) {
this(context, null, -1);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Just for demo purposes this should be calculated properly
int desiredWidth = 100;
int desiredHeight = 100;
setMeasuredDimension(desiredWidth, desiredHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int savedCount = canvas.save();
drawRectangle(canvas);
drawText(canvas);
canvas.restoreToCount(savedCount);
}
private void init() {
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(Color.BLUE);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// This need to be adjusted based on the requirements that you have
mTextPaint.setTextSize(20.0f);
}
private void drawRectangle(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint);
}
private void drawText(Canvas canvas) {
Rect rect = new Rect();
// For simplicity I am using a hardcoded string
mTextPaint.getTextBounds(TEST_STRING, 0, 1, rect);
int w = getWidth(), h = getHeight();
float x = (w - rect.width()) / 2, y = ((h - rect.height()) / 2) + rect.height();
canvas.drawText(TEST_STRING, 0, 1, x, y, mTextPaint);
}
}
I just get green Pixels at the border of my drawn bitmap if I set the alpha of the paint to 200.
The problem does not appear if I set the alpha to 100 or 255.
How can I fix this?
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private DrawThread drawThread;
private boolean surfaceCreated;
Paint paint = new Paint();
private Bitmap bitmap;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.circleyellow);
paint.setAlpha(200);
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bitmap, 200, 200, paint);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
setSurfaceCreated(true);
createDrawThread();
}
#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
setSurfaceCreated(false);
}
public void setSurfaceCreated(boolean surfaceCreated) {
this.surfaceCreated = surfaceCreated;
}
public boolean getSurfaceCreated() {
return surfaceCreated;
}
public void createDrawThread(){
if (drawThread != null) {
drawThread.destroy();
}
drawThread = new DrawThread(getHolder(), this);
drawThread.setRunning(true);
drawThread.start();
}
public DrawThread getDrawThread(){
return drawThread;
}
I think I have solved the problem. A friend has told me this solution:
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
bitmap = BitmapFactory.decodeResource(
getResources(),
R.drawable.circleyellow
);
paint.setAlpha(200);
}
I'm making a simple rotating animation of 2 images, one on top of another (each with a different speed). I know there is already an Animation API, but I need to use this one instead.
It works well, but from time to time, the animations stop for a very short time and then continue, making it "jumpy" (stays on some frames much more than on the others).
Why does it occur? because of GC? What can I do to avoid it? I intend to do some background operations, so it might get even slower.
I know that using sleep() doesn't really mean the thread will wake up right after the given time, but this is too much and it's very noticeable .
Are there any tricks to make it smoother? maybe use a better alternative?
Here's the code (of the view that does it) :
public class AnimView extends SurfaceView implements SurfaceHolder.Callback
{
int _angle;
private final Bitmap _bitmap;
private final Paint _paint =new Paint();
private AnimationThread _animationThread;
private Matrix _matrix;
private int _width;
private int _height;
public AnimView(final Context context)
{
super(context);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context,final AttributeSet attrs)
{
super(context,attrs);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context,final AttributeSet attrs,final int defStyle)
{
super(context,attrs,defStyle);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(final SurfaceHolder holder,final int format,final int width,final int height)
{
_width=width;
_height=height;
}
#Override
public void surfaceCreated(final SurfaceHolder holder)
{
if(isInEditMode())
return;
_matrix=new Matrix();
setWillNotDraw(false);
_animationThread=new AnimationThread();
_animationThread.start();
}
#Override
public void surfaceDestroyed(final SurfaceHolder holder)
{
_animationThread.cancelAnimation();
}
#Override
protected void onDraw(final Canvas canvas)
{
if(isInEditMode())
{
canvas.drawColor(0xffff0000);
return;
}
_paint.setAntiAlias(true);
_matrix.reset();
_matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
_matrix.postRotate(_angle,_width/2,_height/2);
canvas.drawBitmap(_bitmap,_matrix,_paint);
_matrix.reset();
_matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
_matrix.postRotate(_angle*2,_width/2,_height/2);
canvas.drawBitmap(_bitmap,_matrix,_paint);
}
private class AnimationThread extends Thread
{
private boolean _isRunning =true;
public AnimationThread()
{}
public void cancelAnimation()
{
_isRunning=false;
}
#Override
public void run()
{
while(_isRunning)
{
postInvalidate();
refreshDrawableState();
try
{
sleep(5);
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
_angle=(_angle+1)%360;
}
}
}
}
Try something like this
#Override
public void run()
{
long last = System.currentTimeMillis();
long currentTime = last;
long frameTime = 40;
while(_isRunning)
{
currentTime = System.currentTimeMillis();
if(currentTime - last > frameTime){
postInvalidate();
refreshDrawableState();
//I FORGOT THIS
last = currentTime;
}
try
{
sleep(5);
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
_angle=(_angle+1)%360;
}
}
}
This way you refresh your screen every 40ms and update your position every 5ms. Also this is just one part, you can set your matrix update and calculations also out of the drawing part, and this will increase your speed too. The less calculations you do on actuall draw time the faster it will be.
EDIT: Take a look at this
public class AnimView extends SurfaceView implements SurfaceHolder.Callback {
int _angle;
private final Bitmap _bitmap;
private final Paint _paint = new Paint();
private AnimationThread _animationThread;
private Matrix _matrix;
private int _width = 100;
private int _height = 100;
private Bitmap backBitmap;
private Canvas backCanvas;
public AnimView(final Context context) {
super(context);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context, final AttributeSet attrs) {
super(context, attrs);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(final SurfaceHolder holder, final int format,
final int width, final int height) {
_width = width;
_height = height;
createImage();
}
#Override
public void surfaceCreated(final SurfaceHolder holder) {
if (isInEditMode())
return;
_matrix = new Matrix();
setWillNotDraw(false);
_animationThread = new AnimationThread();
_animationThread.start();
}
#Override
public void surfaceDestroyed(final SurfaceHolder holder) {
_animationThread.cancelAnimation();
}
#Override
protected void onDraw(final Canvas canvas) {
if (isInEditMode() || backBitmap == null) {
canvas.drawColor(0xffff0000);
return;
}
canvas.drawBitmap(backBitmap, 0, 0, _paint);
}
private class AnimationThread extends Thread {
private boolean _isRunning = true;
public AnimationThread() {
}
public void cancelAnimation() {
_isRunning = false;
}
#Override
public void run() {
long last = System.currentTimeMillis();
long currentTime = last;
long frameTime = 40;
long updateTime = 20;
boolean updated = false;
while (_isRunning) {
currentTime = System.currentTimeMillis();
if (currentTime - last > frameTime) {
postInvalidate();
refreshDrawableState();
last = currentTime;
updated = false;
}
else if(currentTime - last > updateTime){
if(!updated){
drawImage();
updated = true;
}
}
try {
sleep(5);
} catch (final InterruptedException e) {
e.printStackTrace();
}
_angle = (_angle + 1) % 360;
}
}
}
private void createImage(){
backBitmap = Bitmap.createBitmap(_width, _height, Config.ARGB_8888);
backCanvas = new Canvas();
backCanvas.setBitmap(backBitmap);
}
private void drawImage(){
backCanvas.drawRGB(0, 0, 0);
_paint.setAntiAlias(true);
_matrix.reset();
_matrix.postScale(_width / _bitmap.getWidth(),
_height / _bitmap.getHeight());
_matrix.postRotate(_angle, _width / 2, _height / 2);
backCanvas.drawBitmap(_bitmap, _matrix, _paint);
_matrix.reset();
_matrix.postScale(_width / _bitmap.getWidth(),
_height / _bitmap.getHeight());
_matrix.postRotate(_angle * 2, _width / 2, _height / 2);
backCanvas.drawBitmap(_bitmap, _matrix, _paint);
}
}
Hope this helps and enjoy your work
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.
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)