I am trying to get a panel which has a canvas containing an image which i will place over another image and when i touch the screen the top(overlaying) image will be erased by means of a PoerterDuffXfermode(PorterDuff.Mode) etc ,, anyway I have the functionality done and dusted thanks to the help of a guy on this forum who provided some code which basically carried out exactly what I needed, but I'm having one slight problem,, the guys implementation of the code, will not allow me to reference the Panel class properly in XML to place the Panel on a pre defined XML (main.xml) file. its giving me an error stating
Custom view Panel is not using the 2- or 3-argument View constructors; XML attributes will not work
This is what my xml looks like on a basic scale (just the view in place within the outer linearlayout).
<com.easyscratch.full.Panel
xmlns:android="http://schemas.android.com/apk/res/android"
android:id ="#+id/easyCustView"
android:layout_width="300dp"
android:layout_height="300dp"
android:visibility="visible"
android:focusableInTouchMode="true"/>
The java is as followed .( PANEL CLASS)
package com.easyscratch.full;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
class Panel extends View
{
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
Bitmap bitmap;
Canvas pcanvas ;
int x = 0;
int y =0;
int r =0;
public Panel(Context context) {
super(context);
Log.v("Panel", ">>>>>>");
setFocusable(true);
setBackgroundColor(Color.GREEN);
// setting paint
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAntiAlias(true);
// getting image from resources
Resources r = this.getContext().getResources();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.foreground_image);
// converting image bitmap into mutable bitmap
bitmap = Bitmap.createBitmap(295, 260, Config.ARGB_8888);
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bm, 0, 0, null);
}
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
pcanvas.drawCircle(x, y, r, mPaint);
canvas.drawBitmap(bitmap, 0, 0,null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// set paramete to draw circle on touch event
x = (int) event.getX();
y = (int) event.getY();
r =20;
// Atlast invalidate canvas
invalidate();
return true;
}
}
BASIC MAIN CLASS CALLING MAIN.XML
package com.easyscratch.full;
import android.app.Activity;
import android.os.Bundle;
public class easyscratch extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
,, If only Someone cud tell me what im doing wrong , or maybe an alternative implementation of the
public Panel(Context context) {
super(context);
anyway thanks alot in advanced really would appriciate some help as soon as possible :)
CHEERS GUYS!
Your constructor for Panel must also, at least, have an AttributeSet field.
public Panel(Context context, AttributeSet attr){
super.(context, attr);
Related
Follows is an SSCCE to understand animation timing, extracted from a much more complicated example. What this example when completed should do is create a circle and change its fill color between red and green every second. Right now it just draws a red circle and then nothing else. I've tried placing Runnable, Timer, Thread, and Handler code in various locations but it never seems to do anything. Another problem I've encountered in run() methods is the need for references to Canvas and the current color and the only way I've obtained them is by creating member data for them which, especially in the case of Canvas, seems like a bad idea. For what I'm ultimately doing, rotation and translation of graphic objects, SampleView and the accompanying Canvas seems to be almost certainly necessary so I want to leave SampleView in place. I think that's part of the problem, most examples of animation I've encountered place the timing code in an Activity but that won't work cleanly since the inner View's canvas must be used to update the color (unless I'm missing something).
Inside run methods I used variations on code like this.
if (color == Color.RED)
color = Color.GREEN;
else color = Color.RED;
canvas.drawOval(rectF, p);
hand.postDelayed(run, GET_DATA_INTERVAL);
Those references to color and canvas have been a pain.
package com.example.circles;
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.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
public SampleView(Context context) {
super(context);
setFocusable(true);
p = new Paint();
}
Paint p;
int color;
RectF rectF = new RectF(0, 0, 50, 50);
#Override
protected void onDraw(Canvas canvas) {
p.setStyle(Paint.Style.FILL);
color = Color.RED;
p.setColor(color);
canvas.drawOval(rectF, p);
}
}
}
I'm having a problem drawing text on a canvas that has been scaled. I want to scale the canvas so that drawing dimensions and co-ordinates are always in the range 0.0 to 1.0 i.e. independent of Canvas width and height. (If this is poor practice please feel free to comment giving a reason why this is so.) While I can draw lines and arcs on a scaled canvas correctly, I'm having great difficulty painting text and this problem only seems to occur on Android 4.2
As an example, I have created some code based upon this page here. Not however I have stripped out a lot of the code for clarity.
First, this code works correctly and is as on the above link (albeit stripped down):
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
public class DrawDemo extends Activity {
DemoView demoview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
demoview = new DemoView(this);
setContentView(demoview);
}
#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;
}
private class DemoView extends View{
private int width = 0;
private int height = 0;
public DemoView(Context context){
super(context);
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh){
width = w;
height = h;
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// custom drawing code here
// remember: y increases from top to bottom
// x increases from left to right
int x = 0;
int y = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// make the entire canvas white
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// draw some text using STROKE style
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(Color.MAGENTA);
paint.setTextSize(30);
canvas.drawText("Style.STROKE", 75, 75, paint);
}
}
}
Next I replaced the absolute pixel sizes with normalised ( 0 to 1.0) values and scaled the canvas:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
public class DrawDemo extends Activity {
DemoView demoview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
demoview = new DemoView(this);
setContentView(demoview);
}
#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;
}
private class DemoView extends View{
private int width = 0;
private int height = 0;
public DemoView(Context context){
super(context);
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh){
width = w;
height = h;
}
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// custom drawing code here
// remember: y increases from top to bottom
// x increases from left to right
int x = 0;
int y = 0;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// make the entire canvas white
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
// draw some text using STROKE style
canvas.scale(width, height);
paint.setStyle(Paint.Style.STROKE);
//paint.setStrokeWidth(1);
paint.setColor(Color.MAGENTA);
paint.setTextSize(0.2f);
canvas.drawText("Style.STROKE", 0.5f, 0.5f, paint);
}
}
}
The result is nothing appears on the screen. Could someone suggest what I'm doing wrong? Bear in mind that drawing text in the latter has worked for me on Android < 4.2. Apologies for the formatting of the code sample,s I still cannot get to grips with Stackoverflows code formatting.
When hardware acceleration is on, text is rendered into a texture at the font size you specify on the paint. This means that in your case, text is rasterized at 0.2f pixels. That texture is then scaled up at drawing time, which is why you're not seeing anything.
While this issue has been addressed in a future version of Android, I would strongly recommend you didn't use 0..1 values. You might not only run into precision issues but you will also force the rendering pipelines (software and hardware) to bypass very useful optimizations. For instance, text rendered with a scale transform in software is rendered using paths instead of bitmaps blits.
I'm still learning Android, and I decided to download an example paint application to fiddle with that and learn a bit about how Android handles graphics/drawables/painting. The code I have shows a green and red 'V' in the upper left corner, and a red dot that follows where you touch.
However, I found that the screen is being redrawn each time, so I can't use it as a painting tool. It's almost as if I'm dumping a bucket of white paint over the surface and then redrawing the circle. How can I make it so that the red dot that follows your finger leaves a trail? Here's the code.
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
public class MainActivity extends Activity implements OnTouchListener {
private float x;
private float y;
private int moveX;
Paint paint = new Paint();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomPanel view = new MyCustomPanel(this);
ViewGroup.LayoutParams params =
new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
addContentView(view, params);
view.setOnTouchListener(this);
}
private class MyCustomPanel extends View {
public MyCustomPanel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.GREEN);
paint.setStrokeWidth(6);
canvas.drawLine(moveX,10,50,50,paint);
paint.setColor(Color.RED);
canvas.drawLine(50, 50, 90, 10, paint);
canvas.drawCircle(50, 50, 3, paint);
moveX++;
canvas.drawCircle(x,y,3,paint);
}
}
public boolean onTouch(View v, MotionEvent event) {
x = event.getX();
y = event.getY();
v.invalidate();
return true;
}
}
For example, save the circles in an ArrayList. Make an ArrayList and save every xy coordinates from touch as a point.The following code is just from scratch, could not test it at the moment, so if anything is not working let me know and I will give a an example when I am at home.
private ArrayList<Point> pointList = new ArrayList<Point>
Then in On Touch:
Point xyPoint = new Point();
xyPoint.x = event.getX();
xyPoint.y = event.getY();
pointList.add(xyPoint);
invalidate();
and in onDraw, do a for-loop to get all points and draw each one:
for(int i=0;i<pointList.size();i++){
Point p = pointList.get(i);
canvas.drawCircle(p.x, p.y, 2, paint);
}
This draws circles with 2px diameter where Your finger touches. But this is just an simple example, there is a lot of more You can do and that look better. You should learn about draw on path and how to draw rects and ovales etc. Here is a good example of how to draw on path:
http://android-er.blogspot.de/2011/08/drawpath-on-canvas.html
I wanted to rotate image in android app around the center pivot and following is the code..
package com.android.maddy.canvs;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.provider.OpenableColumns;
import android.view.MotionEvent;
import android.view.View;
public class drawview extends View {
private Drawable d[]=new Drawable[2];
Boolean done=false;
Handler h;
float th=0;
public drawview(Context context) {
super(context);
d[0]=context.getResources().getDrawable(R.drawable.appdatabk);
d[1]=context.getResources().getDrawable(R.drawable.appdata);
h = new Handler();
}
Runnable r =new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
th++;
invalidate();
}
};
public void onDraw(Canvas c){
super.onDraw(c);
Paint p =new Paint();
Rect imageBounds = c.getClipBounds(); // for the background
d[0].setBounds(imageBounds);
d[0].draw(c);
Matrix m = new Matrix();
m.setTranslate(getWidth()/2, getHeight()/2);
m.preRotate(th,43,160); //my image is 86x320
Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.appdata);//image of the bottle i want to rotate
c.drawBitmap(b,m, p);
p.setColor(Color.BLUE);
h.postDelayed(r,1);
}
}
What happens here is that the matrix calculation slows down the speed of rotation and thus it gives ugly sluggish output..
If you have another method to rotate the image around center pivot without using matrix or there is some other method then
Please help me out..
I also removed the matrix and checked the rotation in drawBitmap() function using x+r*(Math.cos(th)) and y+r*(Math.sin(th)) that works fine but image doesn't rotate around pivot..
Please help..
Thanks
Matrix is quite fast. What is slowing you down is that you create classes and load bitmaps in the onDraw. Create the Paint and the Matrix one in the class, and also load the bitmap once
I had the same problem. I think what happens is the canvas stores the matrix values into an array and it fills up the more you rotate the canvas.
That same thing happens when you use Matrix.postRotate(degrees, px, py) and Canvas.concat(Matrix)
I am developing a Car Race Game. I am able to move, stop, accelerate. But i want that when i press screen then car(bitmap of car image) should look like, it had jumped on its place.I am using surfaceviewto draw view
I do not want to use 3D openGL. Any help is much appreciated
finally i used.On touch event, i create a bigger bitmap and draw it on same place. So it will give zoom effect
Bitmap bitmapToZoom; // Create a Bitmap
// Now zoom it
bitmapToZoom=Bitmap.createScaledBitmap(bitmapToZoom, bitmapToZoom.getWidth()+30,bitmapToZoom.getHeight()+30, null);
//now draw it again
canvas.drawBitmap(bitmapToZoom, 0,0,null);
So now finally, Zooming actor on touch code will be like this. Class Name ZoomonTouc.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.SurfaceView;
public class ZoomonTouc extends SurfaceView {
public Bitmap mMyChracter;
public ZoomonTouc(Context context) {
super(context);
mMyChracter = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_launcher);
setWillNotDraw(false);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mMyChracter, mMyChracter.getWidth()/2, mMyChracter.getHeight()/2, null);
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
RectF rectF = new RectF(mMyChracter.getWidth()/2, mMyChracter.getHeight()/2, mMyChracter.getWidth() + 100,
mMyChracter.getHeight() + 100);
if (rectF.contains(event.getX(), event.getY())) {
mMyChracter = Bitmap.createScaledBitmap(mMyChracter,
mMyChracter.getWidth() + 10, mMyChracter.getHeight() + 10,
false);
}
return true;
}
}
To test it properly create one activity and set above surface to activity background
setContentView(new ZoomonTouc(this));