Im making a simple drawing app using canvas. The problem is when I set a background image (of a black board) for the canvas, it only occupies ~66% of the screen. See screenshot/link:
Canvas View
I want my canvas view to occupy the entire screen except the bottom part that RelativeLayout with id parLayout occupies.
What am I doing wrong in my code? Here is what I have:
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static int wandToUse1;
public static int wandToUse2;
public static int wandToUse3;
private ViewGroup rootLayout;
private ViewGroup rlWand2;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private RelativeLayout wn2;
private RelativeLayout wn1;
ImageView w1;
ImageView w2;
boolean clicked1 = false;
boolean clicked2 = false;
RelativeLayout ll;
public static int X;
public static int Y;
CanvasView canvasView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.parLayout);
canvasView = new CanvasView(MainActivity.this);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
ll = (RelativeLayout) findViewById(R.id.parLayout);
w1 = (ImageView) findViewById(R.id.wand1);
w2 = (ImageView) findViewById(R.id.wand2);
w1.setImageResource(wandToUse1);
w2.setImageResource(wandToUse2);
pl = (RelativeLayout) findViewById(R.id.coordAct);
wn1 = (RelativeLayout) findViewById(R.id.rlw1);
wn2 = (RelativeLayout) findViewById(R.id.rlw2);
w1.setOnTouchListener(new ChoiceTouchListener());
w2.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1) {
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
rootLayout.removeView(w1);
}
rlWand2 = (ViewGroup) w2.getParent();
if (rlWand2 != null) {
rlWand2.removeView(w2);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(250, 250);
wn2.addView(w2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
w1.setLayoutParams(layoutParams1);
w2.setLayoutParams(layoutParams1w2);
clicked1 = true;
clicked2 = false;
}
X = (int) event.getRawX();
Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
canvasView.dispatchTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
canvasView.dispatchTouchEvent(event);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java
public class CanvasView extends View{
private Bitmap sourceBitmap;
private Canvas sourceCanvas = new Canvas();
private Paint destPaint = new Paint();
public static Path destPath = new Path();
Bitmap rawBitmap;
public int width;
public int height;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
width = metrics.widthPixels;
height = metrics.heightPixels;
//converting drawable resource file into bitmap
rawBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.blackboard);
rawBitmap = Bitmap.createScaledBitmap(rawBitmap, width, height, false);
Rect frameToDraw = new Rect(0, 0, width, height);
RectF whereToDraw = new RectF(0, 0, width, height);
//converting bitmap into mutable bitmap
sourceBitmap = Bitmap.createBitmap(rawBitmap.getWidth(), rawBitmap.getHeight(), Bitmap.Config.ARGB_8888);
sourceCanvas.setBitmap(sourceBitmap);
sourceCanvas.drawBitmap(rawBitmap, frameToDraw,whereToDraw, null);
destPaint.setAlpha(0);
destPaint.setAntiAlias(true);
destPaint.setStyle(Paint.Style.STROKE);
destPaint.setStrokeJoin(Paint.Join.ROUND);
destPaint.setStrokeCap(Paint.Cap.ROUND);
//change this value as per your need
destPaint.setStrokeWidth(50);
destPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
#Override
protected void onDraw(Canvas canvas)
{
sourceCanvas.drawPath(destPath, destPaint);
canvas.drawBitmap(sourceBitmap, 0, 0, null);
super.onDraw(canvas);
}
public void clearCanvas() {
destPath.reset();
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
destPath.moveTo(MainActivity.X, MainActivity.Y-360);
break;
case MotionEvent.ACTION_MOVE:
destPath.lineTo(MainActivity.X, MainActivity.Y-360);
break;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordAct"
tools:context="com.simplepaintapp.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#color/colorAccent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<RelativeLayout
android:id="#+id/rlw1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="0dp"
android:layout_weight="1"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#mipmap/pen" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/rlw2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="0dp"
android:layout_weight="1"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/wand2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/eraser" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
Thank You!
I got it! I was a bit tired yesterday and couldn't think.
Just fix this line in MainActivity.java
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
To
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight());
Related
I am drawing a view in canvas with existing views. But it draw below the view. Not exactly on the view.
public class MyView extends View {
Paint paint;
ViewGroup viewGroup;
Context context;
public MyView(Context context, ViewGroup viewGroup) {
super(context);
this.viewGroup = viewGroup;
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paint = new Paint();
paint.setColor(context.getResources().getColor(R.color.gray));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Point point = getLocationOnScreen(child);
Rect rect = new Rect();
int x = point.x;
int y = point.y;
rect.left = x;
rect.top = y;
rect.right = x + child.getWidth();
rect.bottom = y + child.getHeight();
canvas.drawRect(rect, paint);
}
/*for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Rect rect = new Rect();
rect.left = child.getLeft();
rect.top = child.getTop();
rect.bottom = child.getBottom();
rect.right = child.getRight();
canvas.drawRect(rect, paint);
}*/
}
public static Point getLocationOnScreen(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return new Point(location[0], location[1]);
}
}
My MainActivity:
public class MainActivity extends AppCompatActivity {
ConstraintLayout constraintLayout;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.parent_view);
imageView = findViewById(R.id.item_profile_img);
imageView.post(() -> {
ViewGroup viewGroup = (ViewGroup) constraintLayout;
constraintLayout.addView(new MyView(MainActivity.this,viewGroup));
});
}
}
activity_main.xml:
<androidx.constraintlayout.widget.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"
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:id="#+id/parent_view">
<ImageView
android:id="#+id/item_profile_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher_background"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,MissingConstraints" />
<TextView
android:id="#+id/item_student_name_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="Student name"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="#+id/item_profile_img" />
<TextView
android:id="#+id/item_student_college"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student college"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_name_title" />
<TextView
android:id="#+id/item_student_specialization"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student specialization"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_college" />
<TextView
android:id="#+id/item_student_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student description"
app:layout_constraintTop_toBottomOf="#+id/item_profile_img"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Please review my code and let me know where I did mistake.
Try This
change you're for loop inside onDraw() like this
for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Rect rect = new Rect();
// int x = point.x;
// int x = point.x;
int x = (int) child.getX() - dpToPx(20);
int y = (int) child.getY() - dpToPx(20);
rect.left = x;
rect.top = y;
rect.right = x + child.getWidth();
rect.bottom = y + child.getHeight();
canvas.drawRect(rect, paint);
}
use a view.getX() and view.getY() it returns proper x and y position of view minus value 20 is the padding of your parent view
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
I use custom view placed over an image view like that
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="5"
tools:context=".TextRecognitionActivity">
<ImageView
android:id="#+id/surfaceViewImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:adjustViewBounds="true"
android:scaleType="fitXY"
/>
<com.gypsywaiter.app.DragRectView
android:id="#+id/dragRectView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
/>
<Button
android:id="#+id/capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_weight="1"
android:text="Capture"/>
</FrameLayout>
And I draw a rectangle in this view upon user selects and drags as follow
public class DragRectView extends View {
private Paint mRectPaint;
private int mStartX = 0;
private int mStartY = 0;
private int mEndX = 0;
private int mEndY = 0;
private boolean mDrawRect = false;
private TextPaint mTextPaint = null;
private OnUpCallback mCallback = null;
public interface OnUpCallback {
void onRectFinished(Rect rect);
}
public DragRectView(final Context context) {
super(context);
init();
}
public DragRectView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
public DragRectView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* Sets callback for up
*
* #param callback {#link OnUpCallback}
*/
public void setOnUpCallback(OnUpCallback callback) {
mCallback = callback;
}
/**
* Inits internal data
*/
private void init() {
mRectPaint = new Paint();
mRectPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
mRectPaint.setStyle(Paint.Style.FILL);
mRectPaint.setStrokeWidth(5); // TODO: should take from resources
mRectPaint.setAlpha(60);
mTextPaint = new TextPaint();
mTextPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
mTextPaint.setTextSize(20);
}
#Override
public boolean onTouchEvent(final MotionEvent event) {
// TODO: be aware of multi-touches
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDrawRect = false;
mStartX = (int) event.getX();
mStartY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
Log.d("logger", x + "//" + y);
//if (!mDrawRect || Math.abs(x - mEndX) > 5 || Math.abs(y - mEndY) > 5) {
mEndX = x;
mEndY = y;
invalidate();
//}
mDrawRect = true;
break;
case MotionEvent.ACTION_UP:
int[] location = new int[2];
getLocationOnScreen(location);
invalidate();
if (mCallback != null) {
mCallback.onRectFinished(new Rect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
Math.max(mEndX, mStartX), Math.max(mStartY, mEndY)));
}
break;
default:
break;
}
return true;
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
Math.max(mEndX, mStartX), Math.max(mEndY, mStartY), mRectPaint);
}
When I try to extract that selected part like that,
dragRectView.setOnUpCallback(new DragRectView.OnUpCallback() {
#Override
public void onRectFinished(Rect rect) {
Bitmap nBitmap = Bitmap.createBitmap(loadedImage,rect.top, rect.left , rect.bottom, rect.right);
}
});
I always get the wrong area and some times crash that x must be less than width. I think it is something related to coordinates but I can't figure it out.
The problem was in the difference between image resolution and the ImageView dimensions.
Solution is:
Resize the bitmap image to be the same width and height of the ImageView and it will work.
I made a program that moves an ImageView around the screen. This is the code:
layout.xml
<it.lorfioroni.scanner.customImageView
android:id="#+id/customImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/ic_launcher_background"
android:background="#color/colorAccent"
android:scaleType="matrix"
/>
</android.support.constraint.ConstraintLayout>
customImageView.java
public class customImageView extends android.support.v7.widget.AppCompatImageView {
public customImageView(Context context) {
super(context);
}
public customImageView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public customImageView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private int xDelta, yDelta;
#Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getRawX();
final int y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
ConstraintLayout.LayoutParams lParams = (ConstraintLayout.LayoutParams)
this.getLayoutParams();
xDelta = x - lParams.leftMargin;
yDelta = y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
Log.i("ciao", "thanks for new location");
break;
case MotionEvent.ACTION_MOVE:
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) this
.getLayoutParams();
layoutParams.leftMargin = x - xDelta;
layoutParams.topMargin = y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
this.setLayoutParams(layoutParams);
break;
}
if(this.getParent() instanceof View)
((View)this.getParent()).invalidate();
return true;
}
}
And it works, I can move the image freely in the screen. The problem is that while the image is small on the left corner (that's ok), the imageView is fullscreen... I tried to set
android:layout_width="wrap_content"
android:layout_height="wrap_content"
but when I do that, the imageView won't move anymore. Do you have any ideas?
Thanks
Ok the problem was that in ConstraintLayout I was setting the margins without setting the constraints.
I've added
app:layout_constraintTop_toTopOf="parent
app:layout_constraintLeft_toLeftOf="parent"
and now it works
I am trying to create an Android application that will erase parts of an image. I am trying to accomplish so by using a dragable object (image of eraser).
I have already implemented the features of dragging the eraser image to anywhere in the app and erasing a background image upon dragging your finger. Now I want to bridge the two features so that the background image erases only when the eraser image is being dragged. How can I accomplish this task?
Below is what I have done so far:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomView myCustomView = new MyCustomView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(myCustomView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
myCustomView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
private final class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
rootLayout.invalidate();
return true;
}
}
MyCustomView.java
public class MyCustomView extends View {
private Bitmap sourceBitmap;
private Canvas sourceCanvas = new Canvas();
private Paint destPaint = new Paint();
private Path destPath = new Path();
public MyCustomView(Context context) {
super(context);
//converting drawable resource file into bitmap
Bitmap rawBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.armissueserase);
//converting bitmap into mutable bitmap
sourceBitmap = Bitmap.createBitmap(rawBitmap.getWidth(), rawBitmap.getHeight(), Bitmap.Config.ARGB_8888);
sourceCanvas.setBitmap(sourceBitmap);
sourceCanvas.drawBitmap(rawBitmap, 0, 0, null);
destPaint.setAlpha(0);
destPaint.setAntiAlias(true);
destPaint.setStyle(Paint.Style.STROKE);
destPaint.setStrokeJoin(Paint.Join.ROUND);
destPaint.setStrokeCap(Paint.Cap.ROUND);
//change this value as per your need
destPaint.setStrokeWidth(50);
destPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
#Override
protected void onDraw(Canvas canvas) {
sourceCanvas.drawPath(destPath, destPaint);
canvas.drawBitmap(sourceBitmap, 0, 0, null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float xPos = event.getX();
float yPos = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
destPath.moveTo(xPos, yPos);
break;
case MotionEvent.ACTION_MOVE:
destPath.lineTo(xPos, yPos);
break;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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:id="#+id/coordAct"
android:background="#drawable/background"
tools:context="com.erasewithtouch.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#0000ff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="28dp"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<HorizontalScrollView
android:id="#+id/backgd"
android:layout_width="match_parent"
android:layout_height="100dp"
android:weightSum="1">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/wand1" />
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</RelativeLayout>
Any help is greatly appreciated. Thanks!
I am trying to create a simple paint app using canvas. The end product would be for the user to select a tool of choice (pen, marker, eraser, etc) and draw or erase accordingly anywhere the tool is dragged on the canvas.
As of now, I only have a pen and I am trying to draw a line wherever the pen is dragged in the canvas. However, I am finding this task challenging. I can drag the pen and I can draw lines, but I can't draw while I am dragging the pen. I am reaching out to the SO community to bridge these two features.
Below is what I have:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CanvasView canvasView = new CanvasView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java
public class CanvasView extends View{
Context context;
int width, height;
Bitmap bitmap;
Path path;
Canvas canvas;
Paint paint;
float mX, mY;
static final float TOLERANCE=4;
public CanvasView(Context context) {
super(context);
this.context=context;
path=new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(50);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
bitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
canvas=new Canvas(bitmap);
}
public void startTouch(float x, float y) {
path.moveTo(x, y);
mX = x;
mY = y;
}
public void moveTouch(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx>=TOLERANCE || dy>= TOLERANCE) {
path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
mX=x;
mY=y;
}
}
//To clear canvas
public void clearCanvas() {
path.reset();
invalidate();
}
public void upTouch() {
path.lineTo(mX,mY);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawPath(path,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
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;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<RelativeLayout 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:id="#+id/coordAct"
tools:context="com.simplepaintapp.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#0000ff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="28dp"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<HorizontalScrollView
android:id="#+id/backgd"
android:layout_width="match_parent"
android:layout_height="100dp"
android:weightSum="1">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/pen" />
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</RelativeLayout>
Current bug after implementing the dispatchTouchEvent() method inside onTouch()
An update to MainActivity and CanvasView is required. See the new source code below:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ViewGroup rootLayout;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private ImageView w1;
private boolean clicked1 = false;
CanvasView canvasView;
public static int X;
public static int Y;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
canvasView = new CanvasView(MainActivity.this);
w1 = (ImageView) findViewById(R.id.wand1);
pl = (RelativeLayout) findViewById(R.id.coordAct);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.coordAct);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
w1.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1){
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
// detach the child from parent
rootLayout.removeView(w1);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
w1.setLayoutParams(layoutParams1);
clicked1 = true;
}
X = (int) event.getRawX();
Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
canvasView.dispatchTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
canvasView.dispatchTouchEvent(event);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java:
public class CanvasView extends View{
Context context;
int width, height;
Bitmap bitmap;
Path path;
public Canvas canvas;
Paint paint;
float mX, mY;
static final float TOLERANCE=4;
public static float x;
public static float y;
public CanvasView(Context context) {
super(context);
this.context=context;
path=new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(50);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
bitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
canvas=new Canvas(bitmap);
}
public void startTouch(float x, float y) {
path.moveTo(x, y);
mX = x;
mY = y;
}
public void moveTouch(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx>=TOLERANCE || dy>= TOLERANCE) {
path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
mX=x;
mY=y;
}
}
//To clear canvas
public void clearCanvas() {
path.reset();
invalidate();
}
public void upTouch() {
path.lineTo(mX,mY);
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawPath(path,paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
startTouch(MainActivity.X,MainActivity.Y-380);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(MainActivity.X,MainActivity.Y-380);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
default:
return false;
}
invalidate();
return true;
}