I want to obtain the height of a custom View so the animation can cover all the size of the layout, no matter what device is being used. The problem is, the View needs to be static, so when I try to get its height, it says I can't call a non-static method from a static class.
private static class EjemploView extends View {
private Path path = new Path();
private static float Last_X = 0;
private static float Last_Y = 0;
public EjemploView (Context context) {
super(context);
new Thread(new Runnable() {
public void run() {
y=30;
while(true){
try {
Thread.sleep(sleeptime);
if(!direction)
{
y=y+StepY_Figura;
}
else
{
y=y-StepY_Figura;
}
if(y<30)
{
direction=false;
paint.setColor(Color.BLACK);
Thread.sleep(350);
}
if(y>260)
{
direction=true;
paint.setColor(Color.WHITE);
Thread.sleep(350);
}
postInvalidate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
#Override
protected void onDraw(Canvas canvas) {
float x = canvas.getWidth() / 4;
float x2=x;
if(Unaprueba==true)
{
canvas.drawColor(Color.BLACK);
}
else
{
canvas.drawColor(Color.WHITE);
}
canvas.drawCircle(x, y, 30, paint);
x =x+x2+4;
canvas.drawCircle(x, y, 30, paint);
x =x+x2+4;
canvas.drawCircle(x, y, 30, paint);
String s =Integer.toString(sleeptime);
canvas.drawText("RITHM: "+s, 10, 20, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
int Change_coordY=10;
int Change_Delay=5;
int Minimum_Delay=5;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//path.moveTo(eventX, eventY);
Last_X=eventX;
Last_Y=eventY;
return true;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if(eventY>Last_Y+Cambio_coordY)
{
sleeptime=sleeptime-Change_Delay;
if(sleeptime<=Minimum_Delay)
{
sleeptime=Minimum_Delay;
}
}
else if(eventY<Last_Y-Change_coordY)
{
sleeptime=sleeptime+Change_Delay;
}
break;
default:
return false;
}
invalidate();
return true;
}
}
Do you know if there is any way I can get the size of the layout if the View is static? Thanks in advance.
Related
Hi I am trying to make an application that draws lines based on points a user enters. A user may input as many points possible and the object will draw these lines based on their x and y values. I have looked into many drawing tutorials and found that using a SurfaceView Runnable is the best way to do any kind of drawing or animation in Android. I have run into a problem where the run() function does not draw with for loops. Is there a way to get loops working in run() or somewhere else? My code is below.
public class draw extends SurfaceView implements Runnable {
Thread thread = null;
updateDraw draw = null;
boolean canDraw = false;
Path path;
Bitmap bitmap;
SurfaceHolder surfaceHolder;
Context mContext;
Paint paint;
int bitmapX;
int bitmapY;
int viewWidth;
int viewHeight;
ArrayList<ArrayList<Double>> XY;
Paint blue_paintbrush_stroke
public draw(Context context, ArrayList<ArrayList<Double>> XY) {
super(context);
mContext = context;
surfaceHolder = getHolder();
paint = new Paint();
path = new Path();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewWidth = w;
viewHeight = h;
draw = new updateDraw(viewWidth, viewHeight);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
options.inMutable = true;
bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bitmap, options);
setUpBitmap();
}
#Override
public void run() {
Canvas canvas;
prepPaintBrushes();
while (canDraw) {
//draw stuff
if (surfaceHolder.getSurface().isValid()) {
int x = draw.getX();
int y = draw.getY();
canvas = surfaceHolder.lockCanvas();
canvas.save();
canvas.drawBitmap(bitmap, bitmapX, bitmapY, paint);
canvas.drawPath(path, blue_paintbrush_stroke);
for(int i = 0; i < XY.size()-1; i++){
float aX = (XY.get(i).get(0), XY.get(i).get(1)).get(0) + bitmapX;
float aY = (XY.get(i).get(0), XY.get(i).get(1)).get(1) + bitmapY;
float bX = (XY.get(i+1).get(0), XY.get(i+1).get(0)).get(0) + bitmapX;
float bY = (XY.get(i+1).get(0), XY.get(i+1).get(1)).get(1) + bitmapY;
canvas.drawLine(aX, aY, bX, bY, blue_paintbrush_stroke);
}
path.rewind();
canvas.restore();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
private void updateFrame(int newX, int newY) {
draw.update(newX, newY);
}
private void setUpBitmap() {
bitmapX = (int) Math.floor(
Math.random() * (viewWidth - backGround.getWidth()));
bitmapY = (int) Math.floor(
Math.random() * (viewHeight - backGround.getHeight()));
}
public void pause() {
canDraw = false;
while (true) {
try {
thread.join();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void resume() {
canDraw = true;
thread = new Thread(this);
thread.start();
}
private void prepPaintBrushes() {
blue_paintbrush_stroke = new Paint();
blue_paintbrush_stroke.setColor(Color.BLUE);
blue_paintbrush_stroke.setStyle(Paint.Style.STROKE);
blue_paintbrush_stroke.setStrokeWidth(10);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setUpBitmap();
// Set coordinates of map.
updateFrame((int) x, (int) y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
// Updated coordinates for map.
updateFrame((int) x, (int) y);
invalidate();
break;
default:
// Do nothing.
}
return true;
}
}
Is better to override onDraw method and draw directly from it.
Create your custom class and extend from SurfaceView but is not
necessary to implement Runnable
Override onDraw(Canvas canvas)
remove run() method (use onDraw instead)
please make sure that you are calling the resume() method from the parent activity.
something like
#Override
protected void onResume(){
super.onResume();
customDraw.resume();
}
I have a problem with canvas I have two options either to draw with a paint or to add an image but when I choose to add an image after drawing the drawing is gone but when I choose drawing again and start to draw the previous drawing show up and remove the image.
public class DrawCanvas extends View {
Bitmap bitmap;
private Paint paint = new Paint();
private Path path;
ArrayList<Path> paths = new ArrayList<>();
ArrayList<Path> undo = new ArrayList<>();
final Paint mBackgroundPaint;
ArrayList<Emotion> emotions;
private boolean mDrawingEnabled = true;
float currentX = 0, currentY = 0;
public DrawCanvas(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.launcher);
paint.setAntiAlias(false);
paint.setColor(Color.BLACK);
paint.setStrokeJoin(Paint.Join.MITER);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(30f);
emotions = new ArrayList<>();
path = new Path();
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas){
if (mDrawingEnabled ) {
canvas.drawPath(path, paint);
}
else{
canvas.drawBitmap(bitmap, currentX, currentY, null);
}
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent){
int xPos =(int) motionEvent.getX(), yPos =(int) motionEvent.getY();
final int action = motionEvent.getAction();
if (mDrawingEnabled){
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(xPos, yPos);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(xPos, yPos);
break;
case MotionEvent.ACTION_UP:
paths.add(path);
break;
default:
return false;
}
}
else {
final float me_x = motionEvent.getX();
final float me_y = motionEvent.getY();
switch ( action ) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
currentX = me_x;
currentY = me_y;
break;
}
}
invalidate();
return true;
}
public void undo(){
if (paths.size()>0){
undo.add(paths.remove(paths.size()-1));
}
}
public void redo(){
if (undo.size()>0){
paths.add(undo.remove(undo.size()-1));
}
}
final void enableDrawing() { mDrawingEnabled = true; }
final void disableDrawing() { mDrawingEnabled = false; }
public void changeBrushColor(int color){
paint.setColor(color);
}
public void changeBrushSize(int size){
paint.setStrokeWidth(size);
}
}
here is the drawing
and when I add image clears the drawing
I want to keep the drawn path alongside the image.
I have problems with my drawing application. I need to catch the correct touch screen and draw them to the canvas. Changing the size of the brush is working properly. But when I change the transparency setting, the program does not work correctly. It imposes a new path on top of the previous one, and the transparency is lost. Screenshot. Where could I go wrong? I need your help. Thank you.
This is my SurfaceView code:
public class PainterView extends SurfaceView implements SurfaceHolder.Callback {
private PainterThread painterThread;
private BrushParameters brushParameters;
private Bitmap bitmap;
public PainterView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
brushParameters = new BrushParameters();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
setWillNotDraw(false);
getThread().setRunning(true);
getThread().start();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int width, int height) {
if (bitmap == null) {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
getThread().setBitmap(bitmap, true);
} else {
getThread().setBitmap(bitmap, false);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
getThread().setRunning(false);
boolean retry = true;
while (retry) {
try {
getThread().join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
painterThread = null;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
painterThread.startDraw(x, y);
break;
case MotionEvent.ACTION_MOVE:
painterThread.continueDraw(x, y);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
painterThread.finishDraw(x, y);
break;
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, null);
}
public BrushParameters getBrushParameters() {
return brushParameters;
}
public void setBrushColor(int color) {
brushParameters.setColor(color);
getThread().setBrushParameters(brushParameters);
}
public void setBrushSize(int size) {
brushParameters.setSize(size);
getThread().setBrushParameters(brushParameters);
}
public void setBrushAlpha(int alpha) {
brushParameters.setAlpha(alpha);
getThread().setBrushParameters(brushParameters);
}
public PainterThread getThread() {
if (painterThread == null) {
painterThread = new PainterThread(getHolder(), this);
}
return painterThread;
}
}
And my Thread class:
public class PainterThread extends Thread {
private SurfaceHolder surfaceHolder;
private PainterView painterView;
private boolean running = false;
private Paint paint;
private Path path;
private Bitmap mBitmap;
private Canvas mCanvas;
private float lastX, lastY;
private static float TOUCH_TOLERANCE = 4;
public PainterThread(SurfaceHolder surfaceHolder, PainterView painterView) {
this.surfaceHolder = surfaceHolder;
this.painterView = painterView;
path = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Color.BLACK);
paint.setAlpha(255);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
}
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
Canvas mCanvas;
while (running) {
mCanvas = null;
try {
mCanvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
if (mCanvas != null) {
mCanvas.drawBitmap(mBitmap, 0, 0, paint);
painterView.postInvalidate();
}
}
} finally {
if (mCanvas != null) {
surfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
public void setBitmap(Bitmap bitmap, boolean clear) {
mBitmap = bitmap;
if (clear) {
mBitmap.eraseColor(Color.WHITE);
}
mCanvas = new Canvas(mBitmap);
}
public void setBrushParameters(BrushParameters brushParameters) {
paint.setColor(brushParameters.getColor());
paint.setAlpha(brushParameters.getAlpha());
paint.setStrokeWidth(brushParameters.getSize());
}
public void startDraw(float x, float y) {
path.reset();
path.moveTo(x, y);
lastX = x;
lastY = y;
}
public void continueDraw(float x, float y) {
float dx = Math.abs(x - lastX);
float dy = Math.abs(y - lastY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
path.quadTo(lastX, lastY, (x + lastX) / 2, (y + lastY) / 2);
mCanvas.drawPath(path, paint);
lastX = x;
lastY = y;
}
}
public void finishDraw(float x, float y) {
path.moveTo(x, y);
mCanvas.drawPath(path, paint);
}
}
Thanks for help. I lost fiew days for find a cause of the problem...
I recommend getting rid of SurfaceView. You've got some confused-looking code (e.g. setBitmap() sets mCanvas, but that's getting overwritten in a loop by run()), and I think you're just making life harder on yourself.
SurfaceViews have two parts, the Surface and the View. The Surface is a separate layer that (by default) sits behind the View layer. The View part of the SurfaceView is normally just a transparent hole that lets you "see through" to the Surface layer behind.
In your case, you've overridden onDraw() in the View object, so you're actually drawing in the View. Over in your other thread you're drawing that same Bitmap onto the Surface. Even if your Bitmap has transparent pixels, you'll be seeing two identical Bitmaps layered on top of each other.
It looks like you're sharing a Bitmap and possibly a Canvas between two simultaneously-executing threads, which is a recipe for unhappiness.
If you get rid of the SurfaceView, and just use a custom View, I think everything will make more sense. The other approach is to get rid of onDraw() and the call to postInvalidate() and do everything on the Surface, but to take advantage of hardware-accelerated rendering it's better to use the custom View.
after i draw line between 2 fixed points on two different rectangles i need to rotate them.The problem is that my line is not updated, it stays on the same x1,y1 x2,y2. How to make line to follow this rectangle?
If any of you have any example code or something that can help, it would be great!
Thanks!
I dont think that i will need OnValidateUpdate tho solve this.
This is my example code to demonstrate this problem:
Object that i want to draw:
public class Object {
private int xPos;
private int yPos;
private int width;
private int height;
float xDistance = 0f;
float yDistance = 0f;
double angleToTurn = 0.0;
Matrix matrix = new Matrix();
private Rect rect;
private Paint paint;
private Point point;
Paint p = null;
public Object(int xPos, int yPos){
this.xPos = xPos;
this.yPos = yPos;
this.width = 300;
this.height = 100;
matrix = new Matrix();
rect = new Rect(xPos,yPos,xPos + width,yPos + height);
paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.BLUE);
p = new Paint();
p.setStyle(Style.FILL);
p.setStrokeWidth(15);
p.setColor(Color.BLACK);
point = new Point(this.getxPos(), this.getyPos()+this.getHeight());
}
public void rotate(float xEvent, float yEvent){
xDistance = xEvent - this.xPos;
yDistance = yEvent - this.yPos;
int angleToTurn = ((int)Math.toDegrees(Math.atan2(yDistance, xDistance)));
matrix.setRotate((int)(angleToTurn),xPos,yPos + height/2);
}
public void draw(Canvas c){
c.save();
c.setMatrix(matrix);
c.drawRect(rect, paint);
c.drawPoint(point.x,point.y,p);
c.restore();
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public Matrix getMatrix() {
return matrix;
}
public void setMatrix(Matrix matrix) {
this.matrix = matrix;
}
public int getxPos() {
return xPos;
}
public void setxPos(int xPos) {
this.xPos = xPos;
}
public int getyPos() {
return yPos;
}
public void setyPos(int yPos) {
this.yPos = yPos;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
GameView class where i draw 2 rects:
public class GameView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder surfaceHolder;
private GameloopThread gameloopThread;
float downx,downy,upx,upy;
private Object object,object1;
Line line;
public GameView(Context context) {
super(context);
gameloopThread = new GameloopThread(this);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
object = new Object(500,500);
object1 = new Object(800,700);
line = new Line(object.getPoint(),object1.getPoint());
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = surfaceHolder.lockCanvas();
onDraw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
gameloopThread.setRunning(true);
gameloopThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameloopThread.setRunning(false);
while(retry){
try {
gameloopThread.join();
retry=false;
}catch(InterruptedException e){
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent( MotionEvent event) {
float x = 0f,y=0f;
if(event.getAction() == MotionEvent.ACTION_DOWN){
downx = event.getX();
downy = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
x = event.getX();
y = event.getY();
object.rotate(x, y);
object1.rotate(x, y);
}
if (event.getAction() == MotionEvent.ACTION_UP) {
}
return true;
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawColor(Color.LTGRAY);
if(object != null)
object.draw(canvas);
if(object1 != null)
object1.draw(canvas);
if(line != null){
line._drawLine(canvas);
}
}
}
Line class that should connect two rectangles (i made class for it but it is not needed)
public class Line {
private Point point1,point2;
private Paint p;
Matrix m;
public Line(Point p1,Point p2){
this.point1 = p1;
this.point2 = p2;
p = new Paint();
p.setStyle(Style.FILL);
p.setColor(Color.RED);
m = new Matrix();
}
public void _drawLine(Canvas c){
c.setMatrix(m);
c.save();
c.drawLine(point1.x, point1.y, point2.x, point2.y, p);
c.restore();
}
public Matrix getMatrix(){
return m;
}
}
I would like to use Matrix object if possible to achieve that.There is also MainActivity and Thread class but I dont post them because thay are not relevant to this problem.
You can use ValueAnimator to animate the rectangles. On each
onAnimationUpdate(ValueAnimator animation)
you can invalidate or re-draw the line with the new position.
I found the solution I can just use Matrix.mapPoints, save them and just redraw line !
I'm making an application to create signature on file image. Here, I will load the image file from the memory card to the application and use Canvas Paint can create a signature by hand through the draw.
The problem here is the application requirements for customers to sign in a specific location. My code allows customers can sign in anywhere the customer wants, like paint on the windows. Now, I want to be signed in a specific area only... Help me...
This my code
Main.java
public class Longvan extends Activity implements OnClickListener, OnTouchListener {
ImageView choosenImageView;
Button choosePicture;
Button savePicture;
Bitmap bmp;
Bitmap alteredBitmap;
Canvas canvas;
Paint paint;
Matrix matrix;
float downx = 0;
float downy = 0;
float upx = 0;
float upy = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_longvan);
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
choosenImageView = (ImageView) this.findViewById(R.id.ChoosenImageView);
choosePicture = (Button) this.findViewById(R.id.ChoosePictureButton);
savePicture = (Button) this.findViewById(R.id.SavePictureButton);
savePicture.setOnClickListener(this);
choosePicture.setOnClickListener(this);
choosenImageView.setOnTouchListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_longvan, menu);
return true;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = event.getX();
downy = event.getY();
break;
case MotionEvent.ACTION_MOVE:
upx = event.getX();
upy = event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
choosenImageView.invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
upx = event.getX();
upy = event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
choosenImageView.invalidate();
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
return true;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (v == choosePicture) {
Intent choosePictureIntent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(choosePictureIntent, 0);
} else if (v == savePicture) {
if (alteredBitmap != null) {
ContentValues contentValues = new ContentValues(3);
contentValues.put(Media.DISPLAY_NAME, "Draw On Me");
Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, contentValues);
try {
OutputStream imageFileOS = getContentResolver().openOutputStream(imageFileUri);
alteredBitmap.compress(CompressFormat.JPEG, 90, imageFileOS);
Toast t = Toast.makeText(this, "Thank you! Image Saved!", Toast.LENGTH_LONG);
t.show();
} catch (Exception e) {
Log.v("EXCEPTION", e.getMessage());
}
}
}
}
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
Uri imageFileUri = intent.getData();
try {
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
imageFileUri), null, bmpFactoryOptions);
alteredBitmap = Bitmap.createBitmap(bmp.getWidth(),bmp.getHeight(),bmp.getConfig());
canvas = new Canvas(alteredBitmap);
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
matrix = new Matrix();
canvas.drawBitmap(bmp, matrix, paint);
choosenImageView.setImageBitmap(alteredBitmap);
choosenImageView.setOnTouchListener(this);
} catch (Exception e) {
Log.v("ERROR", e.toString());
}
}
}
}
How about a specific View for inputting Signatures? Something like this: https://github.com/CoatedMoose/CustomViews/tree/master/library/src/com/coatedmoose/customviews
Then, add this setter for the Bitmap:
public void setImage(Bitmap bitmap) {
this.mBitmap = bitmap;
this.invalidate();
}
Or, if you dont want the applied bitmap as part of your signatureview (use it as background, and not as canvas), replace the onDraw method with this:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
canvas.drawPath(mPath, mPaint);
}
and then just use mSignatureView.setBackgroundResource(R.drawable.background);
Edit:
Just create a Class with the code from coatedMoose, and use it in your layout XML:
<com.example.myapp.gui.views.SignatureView
android:id="#+id/signature"
android:layout_width="match_parent"
android:layout_height="80dp"/>
Somewhere in your code, or even as an XML attribute, you can set the background.
Edit: signatureView class:
package me.other;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* A simple view to capture a path traced onto the screen. Initially intended to be used to captures signatures.
*
* #author Andrew Crichton
* #version 0.1
*/
public class SignatureView extends View {
#SuppressWarnings("unused")
private Path mPath;
private Paint mPaint;
private Paint bgPaint = new Paint(Color.TRANSPARENT);
private Bitmap mBitmap;
private Canvas mCanvas;
private float curX, curY;
private static final int TOUCH_TOLERANCE = 4;
private static final int STROKE_WIDTH = 4;
public SignatureView(Context context) {
super(context);
init();
}
public SignatureView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SignatureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
setFocusable(true);
mPath = new Path();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(STROKE_WIDTH);
}
public void setSigColor(int color) {
mPaint.setColor(color);
}
public void setSigColor(int a, int red, int green, int blue) {
mPaint.setARGB(a, red, green, blue);
}
public boolean clearSignature() {
if (mBitmap != null)
createFakeMotionEvents();
if (mCanvas != null) {
mCanvas.drawColor(Color.TRANSPARENT);
mCanvas.drawPaint(bgPaint);
mPath.reset();
invalidate();
}
else {
return false;
}
return true;
}
public Bitmap getImage() {
return this.mBitmap;
}
public void setImage(Bitmap bitmap) {
this.mBitmap = bitmap;
this.invalidate();
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
int bitmapWidth = mBitmap != null ? mBitmap.getWidth() : 0;
int bitmapHeight = mBitmap != null ? mBitmap.getWidth() : 0;
if (bitmapWidth >= width && bitmapHeight >= height)
return;
if (bitmapWidth < width)
bitmapWidth = width;
if (bitmapHeight < height)
bitmapHeight = height;
Bitmap newBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas();
newCanvas.setBitmap(newBitmap);
if (mBitmap != null)
newCanvas.drawBitmap(mBitmap, 0, 0, null);
mBitmap = newBitmap;
mCanvas = newCanvas;
}
private void createFakeMotionEvents() {
MotionEvent downEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_DOWN, 1f, 1f ,0);
MotionEvent upEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_UP, 1f, 1f ,0);
onTouchEvent(downEvent);
onTouchEvent(upEvent);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
canvas.drawPath(mPath, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(x, y);
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
break;
case MotionEvent.ACTION_UP:
touchUp();
break;
}
invalidate();
return true;
}
/**----------------------------------------------------------
* Private methods
**---------------------------------------------------------*/
private void touchDown(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
curX = x;
curY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x - curX);
float dy = Math.abs(y - curY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(curX, curY, (x + curX)/2, (y + curY)/2);
curX = x;
curY = y;
}
}
private void touchUp() {
mPath.lineTo(curX, curY);
if (mCanvas == null) {
mCanvas = new Canvas();
mCanvas.setBitmap(mBitmap);
}
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
}
Some random layout XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.mysignatureviewapp.views.SignatureView
android:id="#+id/sign"
android:layout_width="match_parent"
android:layout_height="204dp">
</com.example.mysignatureviewapp.views.SignatureView>
</RelativeLayout>
In the onCreate() method:
private SignatureView sign;
//
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mysignatureviewlayout);
sign = (SignatureView) findViewById(R.id.sign);
sign.setBackgroundResource(R.drawable.mybackgrounddrawable);
}
//get your signature when you press, say, the back button
#Override
public void onBackPressed() {
Bitmap mySignature = sign.getImage();
//do something with bitmap
}
Getting both the background and the signature:
BitmapDrawable mySignature = new BitmapDrawable(sign.getImage());
Drawable background = sign.getBackground();
LayerDrawable ld = new LayerDrawable(new Drawable[] { mySignature, background});