I have a Custom View on which I have to draw with my finger(like in the FingerPaint example).
I've tried to add a button below this view programmatically by Making a LinearLayout and adding the required views to it.
However, I cannot see the button itself.
I understand this is a problem due to my implementation of onMeasure, since if I revert to the default, the button is displayed but the view is not.
MainActivity Class
public class FingerPaintActivity extends Activity implements ColorPickerDialog.OnColorChangedListener
{
MyView mv;
AlertDialog dialog;
ArrayList<Integer> colorList;
private LinearLayout.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layout.setLayoutParams(params);
Button submitButton = new Button(this);
params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
submitButton.setLayoutParams(params);
submitButton.setGravity(Gravity.CENTER);
submitButton.setText("Done");
mv = new MyView(this);
params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
mv.setLayoutParams(params);
mv.setDrawingCacheEnabled(true);
mv.setAdjustViewBounds(true);
layout.addView(mv);
layout.addView(submitButton);
setContentView(layout);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
private Paint mPaint;
#Override
public void colorChanged(int color)
{
mPaint.setColor(color);
Log.i("COLOR", color + "");
}
public class MyView extends ImageView
{
private Bitmap mBitmap, originalBitmap, originalNonResizedBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private BitmapFactory.Options options = new BitmapFactory.Options();
public MyView(Context c)
{
super(c);
context = c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
options.inMutable = true;
originalNonResizedBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.amsler_boundary, options));
originalNonResizedBitmap = getResizedBitmap(originalNonResizedBitmap);
originalBitmap = originalNonResizedBitmap.copy(Bitmap.Config.ARGB_8888, true);
mBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
mCanvas = new Canvas(mBitmap);
}
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
// mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
// mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y)
{
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y)
{
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up()
{
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
// mPaint.setMaskFilter(null);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN :
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
touch_up();
// Need to set null or clogs the Paint
mPaint.setXfermode(null);
invalidate();
break;
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int newWidthMeasure = MeasureSpec.makeMeasureSpec(mBitmap.getWidth(), MeasureSpec.EXACTLY);
int newHeightMeasure = MeasureSpec.makeMeasureSpec(mBitmap.getHeight(), MeasureSpec.EXACTLY);
setMeasuredDimension(newWidthMeasure, newHeightMeasure);
// super.setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
// MeasureSpec.getSize(heightMeasureSpec));
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void clearScreen()
{
mCanvas.drawColor(Color.TRANSPARENT);
mCanvas.drawBitmap(originalBitmap, 0, 0, mBitmapPaint);
invalidate();
}
public Rect getCoordinateRect()
{
return new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
}
}
public Bitmap getResizedBitmap(Bitmap bm)
{
int width = bm.getWidth();
int height = bm.getHeight();
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int newDimen = size.x;
float scaleWidth = ((float) newDimen) / width;
float scaleHeight = ((float) newDimen) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
This is how the layout looks with the above code:
Related
I have written an Android application with a Canvas for drawing with a stylus. It works well. When I'm pushing the upper function key of my stylus I would like to erase the drawing by brushing over the text. The normal drawing is in black, so I thought to do the erase with white (on top of the black line). My problem is that all lines change the color when I press the upper function key of the stylus (i.e. all lines are then white) instead of just painting the new draw line in white.
Another option would be to delete elements from the path for the erase. If somebody has a solution for this, I would be happy too.
The layout looks as follows:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="StylusBaselineA">
<inf.ethz.ch.affectivestudy.CanvasView
android:id="#+id/baselineACanvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textColor="#FFFFFF" />
</android.support.constraint.ConstraintLayout>
The CanvasView class look as follows:
public class CanvasView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Path mPathErase;
Context context;
private Paint mPaint;
private Paint mPaintErase;
private float mX, mY;
private static final float TOLERANCE = 5;
private boolean erase = false;
public CanvasView(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;
// we set a new Path
mPath = new Path();
mPathErase = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
mPaintErase = new Paint();
mPaintErase.setAntiAlias(true);
mPaintErase.setColor(Color.WHITE);
mPaintErase.setStyle(Paint.Style.STROKE);
mPaintErase.setStrokeJoin(Paint.Join.ROUND);
mPaintErase.setStrokeWidth(4f);
}
// override onSizeChanged
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// your Canvas will draw onto the defined Bitmap
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw the mPath with the mPaint on the canvas when onDraw
if (erase) {
canvas.drawPath(mPathErase, mPaintErase);
} else {
canvas.drawPath(mPath, mPaint);
}
}
// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
if (erase) {
mPathErase.moveTo(x, y);
} else {
mPath.moveTo(x, y);
}
mX = x;
mY = y;
}
// when ACTION_MOVE move touch according to the x,y values
private void moveTouch(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOLERANCE || dy >= TOLERANCE) {
if (erase) {
mPathErase.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
} else {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
}
mX = x;
mY = y;
}
}
public void clearCanvas() {
mPath.reset();
mPathErase.reset();
invalidate();
}
// when ACTION_UP stop touch
private void upTouch() {
if (erase) {
mPathErase.lineTo(mX, mY);
} else {
mPath.lineTo(mX, mY);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
// Upper function key of stylus
erase = true;
} else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER) {
// Touch input
erase = false;
return false;
} else {
erase = false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
}
Try this.
public class CanvasActivity extends AppCompatActivity {
private Paint mPaint;
View mView;
Button clear;
private Canvas mCanvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_canvas);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.Linear_layout);
mView = new DrawingView(this);
layout.addView(mView, new LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT));
clear= (Button) findViewById(R.id.clear);
clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCanvas.drawColor(Color.WHITE);
}
});
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
}
I have a custom view that allows me to draw a bitmap on it when it is created, and then the user can draw on it with their finger.
My issue is that the canvas fills the whole width/height of the available area in my layout, but I want it to simply match the size of the bitmap that is drawn so that the user can only draw on the picture. This seems like it needs to be done in onSizeChanged since I need to resize the bitmap if they go to landscape from portrait. etc.
My code:
class DrawingCameraPanel extends View implements OnTouchListener {
public Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
private Bitmap background;
int width;
int height;
public Bitmap getOutputBitmap() {
Bitmap.Config config = Bitmap.Config.RGB_565;
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
onDraw(canvas);
return bitmap;
}
public DrawingCameraPanel(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
public DrawingCameraPanel(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
public DrawingCameraPanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
public void setPaintColor(int color) {
mPaint.setColor(color);
}
public void setBackgroundPic(Bitmap bitmap) {
this.background = bitmap;
mCanvas = new Canvas();
mPath = new Path();
paths.add(mPath);
mCanvas.save();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
background = resizeImage(background, w, h);
}
#Override
protected void onDraw(Canvas canvas) {
if (background != null) {
canvas.drawBitmap(background, 0, 0, null);
}
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
}
public Bitmap resizeImage(Bitmap image, int maxWidth, int maxHeight) {
Bitmap resizedImage = null;
try {
int imageHeight = image.getHeight();
if (imageHeight > maxHeight)
imageHeight = maxHeight;
int imageWidth = (imageHeight * image.getWidth())
/ image.getHeight();
if (imageWidth > maxWidth) {
imageWidth = maxWidth;
imageHeight = (imageWidth * image.getHeight())
/ image.getWidth();
}
if (imageHeight > maxHeight)
imageHeight = maxHeight;
if (imageWidth > maxWidth)
imageWidth = maxWidth;
resizedImage = Bitmap.createScaledBitmap(image, imageWidth,
imageHeight, true);
} catch (OutOfMemoryError e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return resizedImage;
}
public void clear() {
this.paths.clear();
mPath = new Path();
paths.add(mPath);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath = new Path();
paths.add(mPath);
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
Of course, why shouldn't Canvas take all space in the layout if its width and height is (most probably) set to match_parent or fill_parent? (Well, technically: View - it's the View that's adjusting its bounds and the canvas just "follows" them).
I think you're reinventing the wheel here. Instead of writing all of the code yourself, I would suggest to:
Sublass ImageView instead of View.
Call setAdjustViewBounds(true) in the constructor. This is the important part. This will actually change the bounds of the view to match the contained image - it preserves aspect ratio and will ensure the image fits in the space the layout is offering.
Make setBackgroundPic() to simply call ImageView.setImageBitmap() since the background on which the user draws is image source from ImageView perspective.
Leave all the drawing code as is - i.e. the OnTouchListener implementation.
What is cool here is that the your custom view is now automatically resized. So, you don't have to worry about the bounds in which the user is allowed to paint because they will be set for you.
For now I want the canvas to just draw a color.
public class AndroidTentaTestActivity extends Activity {
private Bitmap bm;
private Canvas c;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
bm = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
c = new Canvas(bm);
c.drawARGB(100, 0, 0, 150);
}
}
The code above is what I´ve written so far that obviously does not work. I suspect the Bitmap is somehow not connected to what I am doing but I don´t know how to fix it. How do I?
Change the desired color in mPaint.setColor().
public class AndroidTentaTestActivity extends AppCompatActivity {
MyView mv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mv = new MyView(this);
mv.setDrawingCacheEnabled(true);
setContentView(mv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
}
private Paint mPaint;
#Override
public void onClick(View v) {
}
public class MyView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
public MyView(Context c) {
super(c);
context = c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(0xFFFFFFFF);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 1;
private void touch_start(float x, float y) {
//showDialog();
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
// mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); //2,2.old values
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
LinearLayout ll = (LinearLayout) findViewById(R.id.rect);
Paint paint = new Paint();
paint.setColor(Color.parseColor("#CD5C5C"));
Bitmap bg = Bitmap.createBitmap(ll.getWidth(),ll.getHeight() , Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bg);
canvas.drawARGB(200, 0, 225, 255);
ll.setBackgroundDrawable(new BitmapDrawable(bg));
/I got the following code:
public class SketchActivity extends Activity implements OnClickListener, OnSeekBarChangeListener {
private MyView myView;
private Button clearBtn;
private ToggleButton embossBtn, blurBtn, eraseBtn, srcaBtn;
private RelativeLayout layout, layout2;
private TextView penSizeTxt;
SharedPreferences pref;
private Preview preview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
init();
preview = new Preview(this);
layout2 = (RelativeLayout) findViewById(R.id.paint_layout2);
layout = (RelativeLayout) findViewById(R.id.paint_layout);
layout.addView(preview);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
myView = new MyView(SketchActivity.this, layout.getWidth(), layout.getHeight());
layout2.addView(myView);
layout2.bringToFront();
}
}, 50);
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(5);
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private void init() {
clearBtn = (Button) findViewById(R.id.clearBtn);
embossBtn = (ToggleButton) findViewById(R.id.embossBtn);
blurBtn = (ToggleButton) findViewById(R.id.blurBtn);
eraseBtn = (ToggleButton) findViewById(R.id.eraseBtn);
srcaBtn = (ToggleButton) findViewById(R.id.srcatopBtn);
clearBtn.setOnClickListener(this);
embossBtn.setOnClickListener(this);
blurBtn.setOnClickListener(this);
eraseBtn.setOnClickListener(this);
srcaBtn.setOnClickListener(this);
}
private static Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
public void colorChanged(int color) {
mPaint.setColor(color);
}
private void setToggleOf() {
embossBtn.setChecked(false);
eraseBtn.setChecked(false);
blurBtn.setChecked(false);
srcaBtn.setChecked(false);
}
#Override
public void onClick(View v) {
if (v.getId() == embossBtn.getId()) {
if (mPaint.getMaskFilter() != mEmboss) {
setToggleOf();
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
mPaint.setMaskFilter(mEmboss);
embossBtn.setChecked(true);
} else {
mPaint.setMaskFilter(null);
embossBtn.setChecked(false);
}
} else if (v.getId() == blurBtn.getId()) {
if (mPaint.getMaskFilter() != mBlur) {
setToggleOf();
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
mPaint.setMaskFilter(mBlur);
blurBtn.setChecked(true);
} else {
mPaint.setMaskFilter(null);
blurBtn.setChecked(false);
}
} else if (v.getId() == eraseBtn.getId()) {
if (eraseBtn.isChecked()) {
setToggleOf();
eraseBtn.setChecked(true);
mPaint.setMaskFilter(null);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
} else {
mPaint.setMaskFilter(null);
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
}
} else if (v.getId() == srcaBtn.getId()) {
if (srcaBtn.isChecked()) {
setToggleOf();
mPaint.setMaskFilter(null);
srcaBtn.setChecked(true);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
mPaint.setAlpha(0x80);
} else {
mPaint.setMaskFilter(null);
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
}
}
else if (v.getId() == clearBtn.getId()) {
layout2.removeAllViews();
myView = new MyView(SketchActivity.this, layout.getWidth(), layout.getHeight());
layout2.addView(myView);
}
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Bitmap bitmap;
int x = 0;
int y = 0;
int r = 0;
public MyView(Context c, int width, int height) {
super(c);
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int w = display.getWidth(); // deprecated
int h = display.getHeight();
// setFocusable(true);
// setBackgroundResource(R.drawable.download);
// setting paint
mPath = new Path();
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAntiAlias(true);
mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
this.getContext().getResources();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.smoke);
Bitmap bm2 = getResizedBitmap(bm, h, w);
// converting image bitmap into mutable bitmap
bitmap = bm2.createBitmap(w, h, Config.ARGB_8888);
mCanvas = new Canvas();
mCanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
mCanvas.drawBitmap(bm2, 0, 0, null);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
//mCanvas.drawCircle(x, y, r, mPaint);
// canvas.drawBitmap(bitmap, 0, 0, null);
canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
super.onDraw(canvas);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
// mPath.lineTo(x, y);
// mCanvas.drawPoint(x, y, mPaint);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if ((dx >= TOUCH_TOLERANCE) || (dy >= TOUCH_TOLERANCE)) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
// invalidate();
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public Bitmap getImage() {
return mBitmap;
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// TODO Auto-generated method stub
penSizeTxt.setText(String.valueOf(progress + 2));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
}
I want it to clear the second layout and show the content of the camera, on touch. So that if i make a curved line with my finger on the screen it would set those pixels to alpha, and see the camera from the back layout. The problem is that if for example, i make a curved line, the app erases the content of that curve too. So that if i would make a circle with my finger it would erase the content of the circle too, not only the margin.
A screenshot with how it looks: http://imgur.com/5gjNB
onCreate i had:
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(5);
And then on my View i had:
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAntiAlias(true);
mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
Overriding the mPaint, and that's what made it not work properly. By deleting the second:
mPaint = new Paint();
I made it work
I need to create a "Scratch Card" App for my final project in school and can't find the way how to implement the scratching event (How do I create background image and put Grey rectangles over it, so when I will scratch those rectangles I will see the picture under them)
The Implementation must be in Android because I don't how to develop In Objective-C yet.
I saw a reference for Objective-C Implementation, but it's no good as I don't understand it.
My Code is:
public class FingerPaint extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
MyView myView = new MyView(this);
myView.requestFocus();
myView.PaintObjectInit();
// setContentView(myView);
LinearLayout upper = (LinearLayout) findViewById(R.id.LinearLayout01);
upper.addView(myView);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
// MyImageView myImageView = new MyImageView(this);
// setContentView(myImageView);
}
}
public class MyView extends View {
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context context) {
super(context);
this.mPaint = new Paint();
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
protected void PaintObjectInit() {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
//mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
try
{
//Bitmap bm1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.scratch).copy(Bitmap.Config.ARGB_8888, true);;
//Bitmap bm2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.main).copy(Bitmap.Config.ARGB_8888, true);;
//mBitmap = toTransparency(bm1, 0xFFAAAAAA, true, bm2);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
// mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
// mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
Please help regarding this.
I come across this problem recently and then I created a library for this so everyone can have a quick implementation of scratch view, hope this can help those who still looking for answer
https://github.com/winsontan520/Android-WScratchView
I found this library very useful.
https://github.com/sharish/ScratchView
Very easy to integrate
<com.cooltechworks.views.ScratchImageView
android:id="#+id/sample_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:src="#drawable/img_sample2"
/>
you can make "Scratch Card" application like this way. you need to follow the below code which is working code. you just need to required understand and implement your own logic.
public class MainActJava extends AppCompatActivity {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
setContentView(new MyView(this, bitmap));
}
public class MyView extends View implements View.OnTouchListener {
private static final float TOUCH_TOLERANCE = 4;
private Paint mPaint;
private Bitmap oBitmap;
private Bitmap holder;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY;
public MyView(Context context) {
super(context);
}
public MyView(Context context, Bitmap bitmap) {
super(context);
setOnTouchListener(this);
this.oBitmap = bitmap;
this.mPaint = new Paint();
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
init();
}
protected void init() {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(35);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
holder = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(holder);
}
#Override
protected void onDraw(Canvas canvas) {
onDrawing(canvas);
}
private void onDrawing(Canvas canvas) {
mCanvas.drawColor(0xFFAAAAAA);
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(oBitmap, getWidth()/2, getHeight()/2, mBitmapPaint);
canvas.drawBitmap(holder, 0, 0, mBitmapPaint);
}
private void touch_start(float x, float y) {
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
}
#Override
public boolean onTouch(View view, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
}
Output: