I have an activity class, which I want to show a small dynamic content with translucent background on top of a main content, that is something like a moving overlay. I use a SurfaceView descendant for this purpose. For the simplicity I'm trying to code a POC, so I draw an arc in the surface view and rotate it, and move slightly on timer events. The problem is that the code works ok, only if rotation is involved. When I add a shift by (x, y) to change the surface view position, it begins to draw with black opaque rectangle as background. The code is presented below:
public class AndroidActivity extends Activity
{
private RelativeLayout layout;
private OverlayView mOverlay;
private Handler mHandler = new Handler();
private Timer timer = new Timer();
private SurfaceHolder surfaceHolder;
private int degrees = 0;
private int x = 100;
private int y = 200;
#Override
protected void onCreate(Bundle b)
{
super.onCreate(b);
setContentView(R.layout.main_view); // inflate main view
layout = (RelativeLayout) findViewById(R.id.mainview); // get parent layout
mOverlay = new OverlayView(this); // create the surface view descendant
// prepare layout parameters for the surface view
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(50, 50);
params.leftMargin = x;
params.topMargin = y;
mOverlay.setLayoutParams(params); // apply parameters
// next 2 lines ensure transparent background mode
mOverlay.setZOrderOnTop(true);
mOverlay.getHolder().setFormat(PixelFormat.TRANSLUCENT);
// add the surface view into the parent layout
layout.addView(mOverlay);
// lets start dynamic motion
timer.schedule(new DebugTimerTask(), 500, 500);
}
private class OverlayView extends SurfaceView implements SurfaceHolder.Callback
{
private Paint mPaint = new Paint();
public OverlayView(Context context)
{
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
}
protected void doDraw(Canvas canvas)
{
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeWidth(1);
// will draw semitransparent yellow arc
mPaint.setColor(Color.YELLOW);
mPaint.setAlpha(128);
RectF oval = new RectF(0, 0, +50, +50);
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
canvas.drawArc(oval, degrees, 90, true, mPaint);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
setZOrderOnTop(true);
holder.setFormat(PixelFormat.TRANSLUCENT);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
}
}
private class DebugTimerTask extends TimerTask
{
public void run()
{
mHandler.post(new Runnable()
{
#Override
public void run()
{
degrees += 10; // rotate a bit
x += 1; // move a bit
y += 2;
Canvas canvas = null;
// if next lines are commented, code works almost perfectly:
// rotation of semitransparent arc over content beneath,
// but I need to move the overlay, so
// if they are not commented, the overlay's background becomes black
// variant A: doesn't work
//RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(50, 50);
//params.leftMargin = x;
//params.topMargin = y;
//mOverlay.setLayoutParams(params);
// variant B: doesn't work
//mOverlay.layout(x, y, x + 50, y + 50);
try
{
synchronized(surfaceHolder)
{
canvas = surfaceHolder.lockCanvas(null);
if(canvas != null)
{
mOverlay.doDraw(canvas);
}
}
}
finally
{
if(canvas != null)
{
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
});
}
}
}
What is a proper way to move a surface view with transparent background?
Related
I'm trying to draw on surfaceview using onTouch listener, but i'm getting weird drawings (the edge of the line moves on it's own) as you can see in the GIF bellow:
Here's my code:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Canvas canvas;
private Path path;
Paint mPaint = new Paint();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
surfaceView = (SurfaceView) findViewById( R.id.surfaceView );
surfaceHolder = surfaceView.getHolder();
surfaceView.getHolder().addCallback( this );
canvas = surfaceView.getHolder().lockCanvas();
mPaint = new Paint();
mPaint.setAntiAlias( true );
mPaint.setDither( true );
// mPaint.setColor(0xff000000);
mPaint.setStyle( Paint.Style.STROKE );
mPaint.setStrokeJoin( Paint.Join.ROUND);
mPaint.setStrokeCap( Paint.Cap.ROUND);
mPaint.setStrokeWidth( 50);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d( "surfaceCreated", "surfaceCreated " );
path = new Path();
surfaceHolder = holder;
surfaceView.setOnTouchListener( new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float X = event.getX();
float Y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
Log.d( "surfaceCreated", "action down x="+X );
// canvas = surfaceHolder.lockCanvas();
path.moveTo(X,Y);
// mv.touch_start(X,Y);
// canvas = surfaceHolder.lockCanvas();
break;
case MotionEvent.ACTION_MOVE:
Log.d( "surfaceCreated", "action move x="+X );
path.lineTo(X,Y);
break;
case MotionEvent.ACTION_UP:
Log.d( "surfaceCreated", "action up x="+X );
path.lineTo(event.getX(),event.getY());
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset();
surfaceHolder.unlockCanvasAndPost(canvas);
// mCanvas.drawLine( downx, downy, upx, upy, mPaint );
break;
}
if(path != null){
Log.d( "surfaceCreated", "path is not null"+path );
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
return true;
}
});
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
How i can solve the issue? and how i can make the surfaceview white, as you can see it's black at the beginning. Thank you!
Try the following:
1) Background Problem:
According to:
https://developer.android.com/reference/android/view/SurfaceView
The surface is Z ordered so that it is behind the window holding its
SurfaceView; the SurfaceView punches a hole in its window to allow its
surface to be displayed. The view hierarchy will take care of
correctly compositing with the Surface any siblings of the SurfaceView
that would normally appear on top of it. This can be used to place
overlays such as buttons on top of the Surface, though note however
that it can have an impact on performance since a full alpha-blended
composite will be performed each time the Surface changes.
and based on xav's answer: Set the Background Image of a SurfaceView
In order to change your surface background color, you can place a view (overlapping the surface view) on top of the surfaceView with a surfaceHolder pixel format of transparent.
2) Weird Drawing Problem: "the edge of the line moves on it's own"
You already got your answer: Thanks to Guillaume Adam
3) Example:
MainActivity.class
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;
private View surfaceBackground;
private Button b_change_surface_background_color;
private Button b_clear;
private Path path;
private Paint mPaint = new Paint();
private int[] colors = new int[]{Color.WHITE, Color.GREEN, Color.MAGENTA, Color.BLUE};
private int currentSurfaceBackgroundColor = Color.WHITE;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b_change_surface_background_color = (Button) findViewById(R.id.b_change_surface_background_color);
b_change_surface_background_color.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int colorIndex = new Random().nextInt(colors.length);
currentSurfaceBackgroundColor = colors[colorIndex];
changeSurfaceBackgroundColor(currentSurfaceBackgroundColor);
}
});
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceView.setZOrderOnTop(true);
surfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
surfaceView.getHolder().addCallback(this);
surfaceBackground = (View) findViewById(R.id.surfaceBackground);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(50);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void surfaceCreated(SurfaceHolder holder) {
path = new Path();
surfaceView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float X = event.getX();
float Y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
path.reset();
path.moveTo(X, Y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(X, Y);
break;
case MotionEvent.ACTION_UP:
path.lineTo(event.getX(),event.getY());
Canvas canvas1 = surfaceView.getHolder().lockCanvas();
canvas1.drawPath(path, mPaint);
surfaceView.getHolder().unlockCanvasAndPost(canvas1);
break;
}
if(path != null){
Canvas canvas = surfaceView.getHolder().lockCanvas();
canvas.drawPath(path, mPaint);
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
return true;
}
});
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
private void changeSurfaceBackgroundColor(#ColorInt int color) {
if (surfaceBackground != null) {
surfaceBackground.setBackgroundColor(color);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Change Surface Background Color"
android:textAllCaps="false"
android:layout_alignParentTop="true"
android:id="#+id/b_change_surface_background_color">
</Button>
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/b_change_surface_background_color"
android:id="#+id/surfaceView">
</SurfaceView>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/surfaceBackground"
android:layout_below="#id/b_change_surface_background_color"
android:background="#android:color/white">
</View>
</RelativeLayout>
4) Output
It may be because you reset the path before you synced the canvas with the surface view.
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset(); // move this line out
surfaceHolder.unlockCanvasAndPost(canvas);
Try to move path.reset() just before path.moveTo(X,Y).
path.reset(); // add just above moveTo
path.moveTo(X,Y);
Surface view is actually behind your window. It punches a hole in the window for you to see it. So you can put things on top of it in your window, but nothing in your window can appear behind it. So background color won't work. But you get canvas with surface view so you can provide your own color to draw on canvas.
private void setRefreshColor(){
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
surfaceHolder.unlockCanvasAndPost(canvas);
}
Call this function from onSurfaceCreated(). Also every time you refresh canvas you need to draw REFRESH_COLOR.
I have a view and I want to draw a shape on it (circle for example) after click.
I've tried to do this but there are two problems -
onDraw is never called.
Not sure the setLayoutParams(v.getLayoutParams) will give me the result I want.
#Override
public void onClick(View v) {
CircleView circle = new CircleView(GameXoActivity.this, v.getWidth(), v.getHeight());
circle.setLayoutParams(v.getLayoutParams());
circle.startDrawing();
}
CircleView:
public CircleView(Context context, int width, int height) {
super(context);
this.width = width;
this.height = height;
}
protected void startDrawing() {
this.postInvalidate();
}
#Override
protected void onDraw(Canvas canvas) {
Log.d("TAG", "onDraw");
// draw circle
}
}
}
UPDATE:
The shape is not an image and I want to draw it with animation (I didn't write the entire code).
Also, the shape is not always a circle, so using a drawable-state is not an option.
Because there is not just one view, but 9, I don't think the making 9 more on top of them would be right.
As I'm sure you'll need to customize this quite a bit, I've left things rather generic. The following example will animate a blue circle being drawn clockwise, starting from the east (0 degrees), on top of the View's content when the View is clicked.
public class CircleView extends View
{
private static final int MARGIN = 50;
Handler handler = new Handler();
Paint paint = new Paint();
RectF rect = new RectF();
boolean drawing = false;
float sweep = 0;
public CircleView(Context context)
{
this(context, null);
}
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(15);
paint.setColor(Color.BLUE);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawArc(rect, 0, sweep, false, paint);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
rect.set(MARGIN, MARGIN, w - MARGIN, h - MARGIN);
}
public void startAnimation()
{
drawing = true;
handler.post(runnable);
}
Runnable runnable = new Runnable()
{
#Override
public void run()
{
sweep += 10;
if (!(sweep > 360))
{
invalidate();
handler.postDelayed(this, 20);
}
else
{
drawing = false;
sweep = 0;
}
}
};
}
In this Activity example, I used an image that most developers would already have in their project, but it can obviously be changed to your custom image. Also, for the sake of simplicity and brevity, the CircleView is set as the entire content of the Activity, but it can easily be listed in an xml layout, as well.
public class MainActivity extends Activity
{
CircleView circle;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
circle = new CircleView(this);
circle.setBackgroundResource(R.drawable.ic_launcher);
circle.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
circle.startAnimation();
}
}
);
setContentView(circle);
}
}
I suggest, create two imageView with same dimensions, set the image you want to display on image view and then make the second image invisible .
For example :
circleimage.setVisibility(View.INVISIBLE);//now its hidden(do it OnCreate)
and then show 2ndimage when 1stimage is clicked(do it in onclick of 1st image)
circleimage.setVisibility(View.VISIBLE);
If you want to mess with drawing of the object you should overridepublic void draw(Canvas canvas) and not protected void onDraw(Canvas canvas)
EDIT:Please read comments, this first statement of my answer is probably wrong
but I would use a FrameLayout or a RelativeLayout and put the images one on top of another.
Then you can play with the visibility of the overlaying image in order to hide/show it.
EDIT:
In case your circle is not an image and needs to be drawn, make your own circle class extending View and use it as a component in the FrameLayout or RelativeLayout as you would do if it were an image
I'm working on a paint-like app, but I've run it to some troubles.
I know I have re-draw all the objects each frame, but this in turn makes performance slow further on when many objects are visible.
I've also noticed that clearing the background only once, then adding objects to be drawn to the surface when painting is active makes the screen flash almost to the point of inducing epilepsy.
So what is the best way to make a paint app 100% smooth no matter how many objects that are drawn?
Epilepsy-inducing code:
public void run()
{
while (running)
{
if (!holder.getSurface().isValid())
continue;
if (drawObjectsToAdd.size() == 0)
continue;
drawing = true;
Canvas c = holder.lockCanvas();
if (redrawBackground)
{
c.drawARGB(255, 255, 255, 255);
redrawBackground = false;
}
drawObjects.addAll(drawObjectsToAdd);
drawObjectsToAdd.clear();
for (DrawObject draw : drawObjects)
{
draw.Draw(c, paint);
}
holder.unlockCanvasAndPost(c);
drawing = false;
}
}
this adds a new object once it's been added outside of the thread, but it makes the screen flash so much it gives me headaches - and I only redraw the background once.
Smooth at first but becomes laggy after a while, probably due to having to add hundreds and hundreds of objects in the end:
public void run()
{
while (running)
{
if (!holder.getSurface().isValid())
continue;
if (drawObjectsToAdd.size() > 0)
{
drawObjects.addAll(drawObjectsToAdd);
drawObjectsToAdd.clear();
redraw = true;
}
if (clear)
{
drawObjectsToAdd.clear();
drawObjects.clear();
redraw = true;
clear = false;
}
if (!redraw)
continue;
drawing = true;
Canvas c = holder.lockCanvas();
c.drawARGB(255, 255, 255, 255);
for (DrawObject draw : drawObjects)
{
try
{
draw.Draw(c, paint);
}
catch (Exception ex) { }
}
holder.unlockCanvasAndPost(c);
drawing = false;
redraw = false;
}
}
I, at least for this app wanna store all the objects that are added so it doesn't matter how it's painted as long as it's smooth all the way. Preferably, add a circle - it will render a new Bitmap on to the surface, instead of having to redraw lots of objects each frame - instead store them but do not add objects already drawn.
UPDATE
Pseudo-Code of how I want it to be:
If no background is drawn
Draw background color
If new items have been added
Draw only new items to the background
Store new items in objects list
This way, we'll only draw the background once. When a new item is added, only draw that item to the existing surface. When the objects increases, looping through every item will reduce performance greatly and it will not be pleasant to work with.
UPDATE 2:
private void Draw()
{
while (running)
{
if (!holder.getSurface().isValid())
continue;
if (picture == null)
{
picture = new Picture();
Canvas c = picture.beginRecording(getWidth(), getHeight());
c.drawARGB(255, 255, 255, 255);
picture.endRecording();
}
if (drawObjectsToAdd.size() > 0)
{
drawObjects.addAll(drawObjectsToAdd);
drawObjectsToAdd.clear();
Canvas c = picture.beginRecording(getWidth(), getHeight());
for (DrawObject draw : drawObjects)
{
draw.Draw(c, paint);
}
picture.endRecording();
drawObjects.clear();
}
Canvas c2 = holder.lockCanvas();
c2.drawPicture(picture);
holder.unlockCanvasAndPost(c2);
}
}
This last method from Update 2 makes it render all the lines like the "Snake game" when adding circles. Looks like a moving snake on a background, where some of it's circles disappear one frame and others don't the next. If I skip to redraw each frame, it will instead vary which of these circles that are visible.
what about that Picture implementation? increase MAX_DRAWERS to some reasonable value and see how it works
class SV extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final int MAX_DRAWERS = 8;
private boolean mRunning = true;
private List<Picture> mPictures = new LinkedList<Picture>();
private List<Drawer> mDrawers = new LinkedList<Drawer>();
private Paint mPaint;
public SV(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(0xffffff00);
getHolder().addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
new Thread(this).start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public synchronized void surfaceDestroyed(SurfaceHolder holder) {
mRunning = false;
notify();
}
#Override
public synchronized boolean onTouchEvent(MotionEvent event) {
Drawer drawer = new Drawer(event.getX(), event.getY());
mDrawers.add(drawer);
if (mDrawers.size() > MAX_DRAWERS) {
Picture picture = new Picture();
Canvas canvas = picture.beginRecording(getWidth(), getHeight());
mPaint.setAlpha(0xbb);
for (Drawer dr : mDrawers) {
dr.draw(canvas, mPaint);
}
picture.endRecording();
mPaint.setAlpha(0xff);
mPictures.add(picture);
mDrawers.clear();
Log.d(TAG, "onTouchEvent new Picture");
}
notify();
return false;
}
#Override
public synchronized void run() {
SurfaceHolder holder = getHolder();
while (mRunning) {
// Log.d(TAG, "run wait...");
try {
wait();
} catch (InterruptedException e) {
}
if (mRunning) {
// Log.d(TAG, "run woke up");
Canvas canvas = holder.lockCanvas();
canvas.drawColor(0xff0000ff);
for (Picture picture : mPictures) {
picture.draw(canvas);
}
for (Drawer drawer : mDrawers) {
drawer.draw(canvas, mPaint);
}
holder.unlockCanvasAndPost(canvas);
}
}
Log.d(TAG, "run bye bye");
}
class Drawer {
private float x;
private float y;
public Drawer(float x, float y) {
this.x = x;
this.y = y;
}
public void draw(Canvas canvas, Paint paint) {
canvas.drawCircle(x, y, 8, paint);
}
}
}
You generate your list of objects each and every frame, just to discard it after drawing. Why? Generate your list of draw objects once, then draw them.
That's all you need for your drawing thread...
public void run() {
while (running)
{
Canvas c = holder.lockCanvas();
c.drawARGB(255, 255, 255, 255);
for (DrawObject draw : drawObjects)
{
try
{
draw.Draw(c, paint);
}
catch (Exception ex) { }
}
holder.unlockCanvasAndPost(c);
}
}
I am doing animation, some translate animation using but this not what I want I have given the reference of an app Front screen with animation...having three bubbles .initially they will be all together and after onTouch() it just opens up translating to its x,y coordinates
This is the class i am using to translate but i know lots of work has to be done
My Draw view class-
public class DrawView extends View {
Paint paint = new Paint();
private int height;
Bitmap circlegreen ,circlered,circleyellow;
public DrawView(Context context, int height) {
super(context);
this.height = height;
circlegreen=BitmapFactory.decodeResource(getResources(), R.drawable.circlegreen);
circlered=BitmapFactory.decodeResource(getResources(), R.drawable.circlered);
circleyellow=BitmapFactory.decodeResource(getResources(), R.drawable.circleyellow);
this.height= this.height+circleyellow.getHeight();
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.RED);
canvas.drawBitmap(circlegreen, 30, height, paint);
canvas.drawBitmap(circlered, 30, height, paint);
canvas.drawBitmap(circleyellow, 30, height, paint);
// canvas.drawRect(30, height, 60, 300, paint );
}
And in the fragment i am adding this DrawView to container..
#SuppressLint("NewApi")
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
//View view = inflater.inflate(R.layout.fragment_home, container, false);
//dineInBtn=(Button) view.findViewById(R.id.dinein);
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
height = size.y;
Log.v("width=", width+"");
Log.v("height=", height+"");
final CountDownTimer timer = new CountDownTimer(2000, 50) {
#Override
public void onTick(long millisUntilFinished) {
height = height - 10;
drawView = new DrawView(getActivity(), height);
drawView.setBackgroundColor(Color.WHITE);
container.addView(drawView);
}
#Override
public void onFinish() {
}
};
Runnable run=new Runnable() {
#Override
public void run() {
timer.start();
}
};
new Thread(run).start();
Also attaching the image..
Can use arc menu library :
here is library
Its ARC Menu Library you can find the sample example below
https://github.com/daCapricorn/ArcMenu
I want to zoom in the canvas board partially as the letter tray button will be fixed and the board will be zoom,
The partially coding is as mention below and the screen is fully draw in canvas which can be viewed as mention at the bottom.. please help and thanks for you concern.
public class BoardView extends SurfaceView implements SurfaceHolder.Callback
{
class DrawingThread extends Thread implements OnTouchListener {
public DrawingThread(SurfaceHolder holder, Handler handler) {
mSurfaceHolder = holder;
public void setRunning(boolean b) {
mRun = b;
}
#Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
// System.gc();
// c.scale(canvasScaleX, canvasScaleY);
// c.save();
// c.translate(canvasTranslateX, canvasTranslateY);
doDraw(c);
}
updateGame();
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
private void doDraw(Canvas canvas) {
if (ge == null)
return;
Rect bRect = new Rect(0, 0, dims.getTotalWidth(),
dims.getScoreHeight() + dims.getBoardheight());
Drawable drawable = getResources().getDrawable(R.drawable.board);
drawable.setBounds(bRect);
drawable.draw(canvas);
Rect tRect = new Rect(0, dims.getScoreHeight()
+ dims.getBoardheight(), dims.getTotalWidth(),
dims.getTotalHeight());
canvas.drawRect(tRect, fillTrayPaint);
int topHeight = dims.getScoreHeight() + dims.getBoardheight();
int bottom = (dims.getTotalHeight() + 5)
- (dims.getTotalWidth() / Tray.TRAY_SIZE);
Rect rect = new Rect(0, topHeight, dims.getTotalWidth(), bottom - 7);
Drawable drawableTray = getResources()
.getDrawable(R.drawable.strip);
drawableTray.setBounds(rect);
drawableTray.draw(canvas);
drawTray(canvas);
drawBoard(canvas);
// drawScore(canvas);
drawMovingTile(canvas);
}
public BoardView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// endTurn=(ImageButton)findViewById(R.id.endturn_button_horizontal);
thread = new DrawingThread(holder, handler);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
final float scale1 = getResources().getDisplayMetrics().density;
defaultFontSize = (int) (MIN_FONT_DIPS * scale1 + 0.5f);
thread.setDefaultFontSize(defaultFontSize);
dimensions = calculateDimensions(getWidth(), getHeight());
thread.setDimensions(dimensions);
thread.setRunning(true);
// if (thread != null && !thread.isAlive())
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
We can simply do it by canvas.clipRect(rectangle), at this point what we are suppose to do is save the canvas canvas.save() and after canvas.clipRect(rectangle) call canvas.restore().
Consider trying something like this:
Create a bitmap from the canvas you wish to zoom into.
When rendering that bitmap to the screen, you can change the scr rect
(which will "zoom" into the bitmap).
I hope this helps.
I think you need to render your game board into offscreen bitmap and then draw this bitmap at canvas using Matrix, so you will be able to change its position and scale.
I believe the easiest way to do this would be to use Canvas#scale(float scale, int pivotx, int pivoty) method. It essentially grows the entire canvas uniformally which really is what zooming is from a 2D perspective.
canvas.scale(2.0f, getWidth()/2, getHeight()/2) will scale the image by 2 from the center. canvas.scale(1.0f, getWidth()/2, getHeight()/2) will shrink it back.
I have never tried this in this context, so if you decide to try it report back the results please! I'd like to know for future reference.