Gesture Detector with onDraw() called multiple times - android

I am using GestureDetector to identify the touch.I have two Relative layoutsof same layout size.I am trying to draw an image A on one layout and move an image B(created using onDraw) on another layout.While I move my image B I am using GestureDetector to identify the touch.When I move my image B, image A(view) onDraw() method is called multiple times. Please help me to avoid calling onDraw() multiple times.Here is my code
public class TouchExampleActivity extends Activity {
RelativeLayout r1;
RelativeLayout r2;
Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = TouchExampleActivity.this;
r1 = (RelativeLayout) findViewById(R.id.r1);
r2 = (RelativeLayout) findViewById(R.id.r2);
TouchExampleView view = new TouchExampleView(this);
DrawCircle drawCircle = new DrawCircle(context);
r1.addView(view);
r2.addView(drawCircle);
}
class DrawCircle extends View {
Paint p;
public DrawCircle(Context context) {
super(context);
// TODO Auto-generated constructor stub
p = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Log.v("Touch", "Called Draw Circle");
p.setColor(Color.BLUE);
canvas.drawCircle(60, 50, 50, p);
}
}
}
TouchExampleView.java
public class TouchExampleView extends View {
private Drawable mIcon;
private float mPosX;
private float mPosY;
static boolean fStartDrag = false;
static boolean fDrag = false;
private float ypos = 40;
private float xpos = 30;
public static float sx, sy;
private VersionedGestureDetector mDetector;
private float mScaleFactor = 1.f;
public TouchExampleView(Context context) {
this(context, null, 0);
}
public TouchExampleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mIcon = context.getResources().getDrawable(R.drawable.icon);
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
canvas.save();
canvas.translate(mPosX, 0);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.drawRect(0, 0, 30, 30, paint);
canvas.restore();
}
private class GestureCallback implements VersionedGestureDetector.OnGestureListener {
public void onDrag(float dx, float dy) {
if ((dx == -1) && (dy == -1)) {
fStartDrag = true;
fDrag = false;
}
else if (fStartDrag) {
if (dy >= mPosY && dy <= ypos + mPosY && dx >= mPosX && dx <= mPosX + xpos) {
fDrag = true;
fStartDrag = false;
}
} else if (fDrag) {
System.out.println("fDrag");
if (mPosX < 3)
mPosX = 3;
else if (mPosX > 400)
mPosX = 400;
else
mPosX = dx;
// mPosY = dy;
postInvalidate();
}
}
public void onScale(float scaleFactor) {
mScaleFactor *= scaleFactor;
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
postInvalidate();
}
}
}
My sample xml
<RelativeLayout
android1:id="#+id/r1"
android1:layout_width="620dip"
android1:layout_height="320dip"
android1:layout_alignParentBottom="true"
android1:layout_alignParentLeft="true"
android1:layout_marginBottom="94dp" >
</RelativeLayout>
<RelativeLayout
android1:id="#+id/r2"
android1:layout_width="620dip"
android1:layout_height="320dip"
android1:layout_alignParentBottom="true"
android1:layout_alignParentLeft="true"
android1:layout_marginBottom="94dp" >
</RelativeLayout>
If I use two relative layouts of different size and position then it works fine, onDraw() is not called multiple times

After trying so much I found this answer to my question.setDrawingCacheEnabled(true) prevents calling onDraw() multiple times.Its working for me.I hope I am going right.
View circleView;
r2 = (RelativeLayout) findViewById(R.id.r2);
circleView= r2;
circleView.setDrawingCacheEnabled(true);

Related

How to draw a moving circle on the bottom line of the oval?

I need to implement something like SeekBar. I created my class heir from View. In which I paint an oval on canvas. When touched, this oval goes up and down. I can not correctly calculate the position for the point (thumb).
enter image description here
here is my code, but it has already been redone many times and stopped working:
public class BalanceView extends View {
private Paint ovalPaint;
private Paint thumbPaint;
private float ovalBottom = 0f;
private Bitmap thumb;
private RectF oval1;
//params
private int maxValue = 18;
private float ovalPaintWidth = 2.0f;
private float ovalHeight = 60f;
//end params
private float touchX = 0f;
private float touchY = 0f;
private float mUnreachedRadius;
public BalanceView(Context context) {
super(context);
init(context, null);
}
public BalanceView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public BalanceView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context ctx, #Nullable AttributeSet attrs){
if (attrs != null){
}
if (ovalPaint == null){
ovalPaint = new Paint();
ovalPaint.setAntiAlias(true);
ovalPaint.setStrokeWidth(ovalPaintWidth);
ovalPaint.setStyle(Paint.Style.STROKE);
Shader shader = new SweepGradient(10, 10, new int[]{R.color.white, R.color.black, R.color.white}, null);
ovalPaint.setShader(shader);
}
if (thumbPaint == null){
thumbPaint = new Paint();
}
thumb = BitmapFactory.decodeResource(getResources(), R.drawable.move_point);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//refershPosition();
}
#Override
protected void onDraw(Canvas canvas) {
paintOval(ovalPaint, canvas);
float cos = computeCos(touchX, touchY);
float y = calcYLocationInWheel(cos);
Log.d("balance", "cos: " + cos + " y: " + y + " touchX: " + touchX + " touchY: " + touchY + "mUnreachedRadius: " + mUnreachedRadius) ;
canvas.drawBitmap(thumb, touchX, y, thumbPaint);
super.onDraw(canvas);
}
private void paintOval(Paint paint, #NonNull Canvas canvas){
if (paint != null) {
int right = getWidth() - 30;
int left = (getWidth() - right) / 2;
float top = ovalBottom - ovalHeight;
oval1 = new RectF(left, top, right + left, ovalBottom);
canvas.drawOval(oval1, paint);
}
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getY() >= getTop() && event.getY() <= getBottom()) {
touchY = event.getY();
}
if (event.getX() <= oval1.right - thumb.getWidth() && event.getX() >= oval1.left) {
touchX = event.getX();
}
ovalBottom = touchY;
invalidate();
return super.dispatchTouchEvent(event);
}
private float computeCos(float x, float y) {
float width = x - oval1.width() / 2;
float height = y - oval1.height() / 2;
float slope = (float) Math.sqrt(width * width + height * height);
return height / slope;
}
private float calcYLocationInWheel(double cos) {
return oval1.bottom * (float) cos;
}
}
I try so:
private float getY(float a, float b, float x){
// return (float) (Math.pow(b, 2d) * ((Math.pow(a, 2d) - Math.pow(x, 2d)) / Math.pow(a, 2d)));
return (float)
((Math.pow(b, 2d) / Math.pow(a, 2d)) * (Math.sqrt(b * b * (a * a - x * x))));
}
But the data is wrong.

Android: Circle moves to random location when tapping it

I am writing a program that draws a circle at a random location on the phone screen. What it is supposed to do is when the circle is touched, it removes that circle and moves it to another random location.
Currently, when the screen is tapped the old circle is removed, and redrawn at another random location on the screen. It is very close, but I was wondering how I get over this hurdle.
public class Circle extends View {
private float x = 300;
private float y = 300;
private int r = 150;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Random random = new Random();
// draws circle
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
// constructors
public Circle(Context context) {
super(context);
init();
}
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Circle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
// might be used later for some data collection
}
// gets random number,,
void generateRandom() {
int w = getWidth() - r - 50;
int h = getHeight()- r - 50;
int border = r + 50;
this.x = border + random.nextInt(w-border);
this.y = border + random.nextInt(h-border);
}
// when screen is tapped, old circle removed, new circle drawn
#Override
public boolean onTouchEvent(MotionEvent event) {
generateRandom();
invalidate();
return super.onTouchEvent(event);
}
}
Change the code like this ,
#Override
public boolean onTouchEvent(MotionEvent event) {
if (isInsideCircle(event.getX(), event.getY())) {
generateRandom();
invalidate();
}
return super.onTouchEvent(event);
}
boolean isInsideCircle(float xPoint, float yPoint) {
float dx = (x - xPoint);
float dxPow = (float) Math.pow(dx, 2);
float dy = (y - yPoint);
float dyPow = (float) Math.pow(dy, 2);
float radPow = (float) Math.pow(r, 2);
return (dxPow + dyPow) < radPow || (dxPow + dyPow == radPow);
}

Android: Draw random circles on screen on touch

I'm working on a project that requires me to draw a circle at a random location on the screen when the user touches the screen. When the touch event occurs it also needs to remove the last circle I drew, so that there can only be one circle on the screen at one time.
I have a class Circle, that I use to create a circle:
public class Circle extends View {
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public Circle(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0x000000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
}
This is the activity from which a new Circle is created. It will also monitor touch events. Right now it is drawing a circle in the upper left hand corner of the screen, but that code will need to be moved into the onTouch method. I will likely calculate the random number using Random.
public class FingerTappingActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_finger_tapping);
LinearLayout circle = (LinearLayout) findViewById(R.id.lt);
View circleView = new Circle(this, 300, 300, 150);
circleView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
circle.addView(circleView);
circle.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
}
}
I have never worked with touch events before such as these and have no idea how to go about this. Some tips would be greatly appreciated.
Do some thing like this ,
public class DrawCircles extends View {
private float x = 100;
private float y = 100;
private int r = 50;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.RED);
canvas.drawCircle(x, y, r, mPaint);
}
public DrawCircles(Context context) {
super(context);
init();
}
public DrawCircles(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DrawCircles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
void init() {
mPaint.setColor(0x000000);
// logic for random call here;
}
Random random = new Random();
void generateRandom() {
int minRadius = 100;
int w = getWidth();
int h = getHeight();
this.x = random.nextInt(w);
this.y = random.nextInt(h);
this.r = minRadius + random.nextInt(100);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
generateRandom();
invalidate();
return super.onTouchEvent(event);
}
}
This view will draw random circles inside the view . make some adjustments for generating x & y coordinates . add this view to xml then it will work.

How to draw a rectangle with black border and background transparent on Imageview?

I would like to draw a rectangle on an ImageView as a picture below (black border and transparent as background).
Basically I download an Image, put in in a ImageView and after I receive 4 points to draw a rectangle.
Thanks in advance
Your problem for android.view.InflateException can be solved by deleting the constructors from DrawView class and auto generate them again. Now for the rectangle you have to have the onDraw similar like this:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
float leftx = 50;
float topy = 50;
float rightx = 150;
float bottomy = 150;
// FILL
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
}
If you want to get the coordinates on click an then draw the rectangle override the onTouchEvent method and do something like this
class DrawView extends ImageView {
float x, y;
float width = 60.0f;
float height = 50.0f;
boolean touched = false;
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (touched) {
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
// FILL
canvas.drawRect(x, y, (x + width) / 0.5f, (y + height) / 0.5f, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(x, y, (x + width) / 0.5f, (y + height) / 0.5f, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
touched = true;
//getting the touched x and y position
x = event.getX();
y = event.getY();
invalidate();
return true;
}
}
I solved my problem in thanks the help of #vasilis.
I created:
class DrawView extends ImageView {
private int numberOfRectangles=0;
private ArrayList<Rectangles> listRect;
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberOfRectangles> 0 && listRect!= null)
{
for (int i=0; i< numberOfRectangles; i++)
{
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
float leftx = listRect.get(i).getLeftx();
float topy = listRect.get(i).getTopy();
float rightx = listRect.get(i).getRightx();
float bottomy = listRect.get(i).getBottomy();
// FILL
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
}
}
}
public void creatRectangles(ArrayList<Rectangles> arrayRettangoliTest) {
numberOfRectangles=arrayRettangoliTest.size();
this.listRect= arrayRettangoliTest;
this.invalidate();
}
}
in my xml file:
<it.path.DrawView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/placeholder" />
I create a Class Rectangles:
public class Rectangles {
private float leftx;
private float topy ;
private float rightx;
private float bottomy;
public Rectangles(float leftx, float topy, float rightx, float bottomy) {
this.leftx = leftx;
this.topy = topy;
this.rightx = rightx;
this.bottomy = bottomy;
}
#Override
public String toString() {
return "Rectangles{" +
"leftx=" + leftx +
", topy=" + topy +
", rightx=" + rightx +
", bottomy=" + bottomy +
'}';
}
public void setLeftx(float leftx) {
this.leftx = leftx;
}
public void setTopy(float topy) {
this.topy = topy;
}
public void setRightx(float rightx) {
this.rightx = rightx;
}
public void setBottomy(float bottomy) {
this.bottomy = bottomy;
}
public float getLeftx() {
return leftx;
}
public float getTopy() {
return topy;
}
public float getRightx() {
return rightx;
}
public float getBottomy() {
return bottomy;
}
}
And in my MainActivity (ex after an onClick()):
...
ArrayList<Rectangles> arrayRectanglesTest= new ArrayList<>(4);
arrayRectanglesTest.add(new Rectangles(50, 50, 100, 100));
arrayRectanglesTest.add(new Rectangles(150, 150, 200, 200));
arrayRectanglesTest.add(new Rectangles(250, 250, 300, 300));
arrayRectanglesTest.add(new Rectangles(350, 350, 400, 400));
arrayRectanglesTest.add(new Rectangles(450, 450, 500, 500));
imageView.creatRectangles(arrayRectanglesTest);
...
So I made dynamic the number of rectangles
here the Result

Changing background color of SignatureView

I found this code on stack and it works well. However, there is an issue. While I'm able to set its background color, the color changes to black as soon as the clearSignature() function is called.
Why is that happening?
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
{
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;
boolean modified = false;
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.BLACK);
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();
}
public boolean hasChanged()
{
return modified;
}
#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)
{
modified = true;
canvas.drawColor(Color.RED);
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();
}
}
Well I have updated the original SignatureView code, now it supports a custom signature background color. This color is different from the view's background color!
setSigBackgroundColor()
I also made some other optimizations, use on your own risk as this is minimal tested!
Small list of optimizations:
Better bitmap recycling etc.
Recycling of MotionEvents
Added signature background color set method
Optimizations
Changed setImage method, although still not very safe to use!
New code:
import android.annotation.SuppressLint;
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.1
*
* Modified by Rolf Smit
* -Recycle bitmaps
* -Recycle MotionEvents
* -Signature Background color changes
* -Optimizations
* -Changed setImage method, although still unsafe to use!
*/
public class SignatureView extends View {
private Path mPath;
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private int sigBackgroundColor = Color.TRANSPARENT;
private float curX, curY;
private static final int TOUCH_TOLERANCE = 4;
private static final int STROKE_WIDTH = 4;
boolean modified = false;
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 alpha, int red, int green, int blue) {
mPaint.setARGB(alpha, red, green, blue);
}
public void setSigBackgroundColor(int color){
sigBackgroundColor = color;
}
public void setSigBackgroundColor(int alpha, int red, int green, int blue){
sigBackgroundColor = Color.argb(alpha, red, green, blue);
}
public boolean clearSignature() {
if (mBitmap != null) {
createFakeMotionEvents();
}
if (mCanvas != null) {
mCanvas.drawColor(sigBackgroundColor);
mPath.reset();
invalidate();
} else {
return false;
}
return true;
}
public Bitmap getImage() {
return Bitmap.createBitmap(mBitmap);
}
public void setImage(Bitmap bitmap){
this.mBitmap = bitmap;
if(mCanvas != null){
mCanvas.setBitmap(mBitmap);
}
}
public boolean hasChanged() {
return modified;
}
#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);
mCanvas = newCanvas;
if (mBitmap != null) {
newCanvas.drawBitmap(mBitmap, 0, 0, null);
mBitmap.recycle();
} else {
newCanvas.drawColor(sigBackgroundColor);
}
mBitmap = newBitmap;
}
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);
downEvent.recycle();
upEvent.recycle();
}
#Override
protected void onDraw(Canvas canvas) {
modified = true;
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
canvas.drawPath(mPath, mPaint);
}
#SuppressLint("ClickableViewAccessibility")
#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 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();
}
}

Categories

Resources