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;
}
Related
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 Working on a android project where i am stuck with removing a view on onTouch method when MotionEvent.ACTION_UP is triggered.
My code is as follows
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = 0;
int y = 0;
View point = null;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
x = (int) event.getX();
y = (int) event.getY();
if(touch_circle(x,y)) {
point = new Circle_draw(getApplicationContext(),x,y);
layout.addView(point);
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
and more code related to this are as follows
public class Circle_draw extends View{
int width;
int height;
public Circle_draw(Context context,int width,int height) {
super(context);
this.width = width;
this.height = height;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
canvas.drawCircle(width,height,5,paint);
}
}
how can i remove this view from my activity class?? using Action_UP
and the Whole Code for this activity is as follows:-
public class MainActivity extends Activity implements View.OnTouchListener{
RelativeLayout layout;
int height;
int width;
View control;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setVariables();
layout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
layout.addView(control);
control.setOnTouchListener(this);
}
public void setVariables(){
layout = (RelativeLayout) findViewById(R.id.controllerLayout);
height = getWindowManager().getDefaultDisplay().getHeight();
width = getWindowManager().getDefaultDisplay().getWidth();
control = new ThumbController(getApplicationContext());
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = 0;
int y = 0;
View point = null;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
x = (int) event.getX();
y = (int) event.getY();
if(touch_circle(x,y)) {
point = new Circle_draw(getApplicationContext(),x,y);
layout.addView(point);
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
public boolean touch_circle(int x,int y){
boolean touch = false;
x=x-width;
y=y-height;
int distance = (int) Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
//Toast.makeText(getApplicationContext(),"distance=" + String.valueOf(distance),Toast.LENGTH_SHORT).show();
if(distance<=120){
touch = true;
}
return touch;
}
public class ThumbController extends View{
public ThumbController(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int radius = 120;
Paint paint = new Paint();
width = width-75;
height = height-150;
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.GREEN);
canvas.drawCircle(width, height, radius, paint);
}
}
public class Circle_draw extends View{
int width;
int height;
public Circle_draw(Context context,int width,int height) {
super(context);
this.width = width;
this.height = height;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
canvas.drawCircle(width,height,5,paint);
}
}
}
I want to design a Scratch Card-like effect in android. Is It possible to do this with a Framelayout or RelativeLayout by stacking the coupon at the back of the bitmap and setting the colour of CustomCanvas to gray or something. I've tried doing this but I wasn't able to get the stacked image from the back. The background was just turning white and nothing else. I then tried to the COLOR.TRANSPARENT and there was no Scratch at all. How can I do this?
Below is my CustomCanvas Class extending the View class:
public class CanvasView extends View {
public int width,height;
private Bitmap bitmap;
private Canvas canvas;
Context context;
private Path mPath;
private Paint paint;
private float mX, mY;
private static final float TOLERANCE = 5;
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(100f);
}
#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);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap,0,0,paint);
canvas.drawPath(mPath, paint);
}
private void startTouch(float x, float y){
mPath.moveTo(x,y);
mX = x;
mY = y;
}
private void moveTouch(float x, float y){
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx >= TOLERANCE || dy >= TOLERANCE){
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
public void clearCanvas(){
mPath.reset();
invalidate();
}
private void upTouch(){
mPath.lineTo(mX,mY);
}
#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();
float r = calculatingPercentage(bitmap.getWidth(),bitmap.getHeight());
if(calculatingPercentage(bitmap.getWidth(),bitmap.getHeight()) >= 50.00){
Toast.makeText(getContext(),"Done 50%",Toast.LENGTH_SHORT).show();
}
invalidate();
break;
}
return true;
}
//FUNCTION I WAS USING TO CALCULATE THE SCRATCHED AREA'S PERCENTAGE
private float calculatingPercentage(int width,int height){
int[] xArray = new int[100];
int[] yArray = new int[100];
float percentTransparent;
Random r = new Random();
for(int i = 0; i<100;i++){
xArray[i] = r.nextInt(width - 10) +10;
}
for(int i = 0; i<100;i++){
yArray[i] = r.nextInt(height - 10) +10;
}
int pixelCount = 0;
for(int i = 0; i<100;i++){
int x = xArray[i];
int y = yArray[i];
int color = Color.WHITE;
int black = Color.BLACK;
if(bitmap.getPixel(xArray[i],yArray[i]) == Color.WHITE){
pixelCount++;
}
}
percentTransparent = (pixelCount/100);
return percentTransparent;
}
}
ActivityB which is calling the Canvasview class:
public class ActivityB extends Activity {
private CanvasView customCanvas;
private Button bt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_a);
customCanvas = (CanvasView) findViewById(R.id.signature_canvas);
bt = (Button) findViewById(R.id.buttonAgain);
bt.setVisibility(View.VISIBLE);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
clearCanvas();
}
});
}
public void clearCanvas(){
customCanvas.clearCanvas();
}
}
And here is my fragment_a.xml layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
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/firstFrame"
android:background="#F07818"
tools:context="com.example.dremer.fragmentspractice.FragmentA">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="40dp"
android:src="#drawable/benz"/>
<com.example.dremer.fragmentspractice.CanvasView
android:id="#+id/signature_canvas"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#FFFFFF"
android:background="#FFFFFF"/>
<Button
android:id="#+id/buttonAgain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scratch Again"
android:layout_gravity="bottom|center"
android:paddingBottom="20dp"/>
</FrameLayout>
Can you guys please help me with this?
Thanks!
Hi i am erasing bitmap that is draw at canvas with touch (fingers) that is working fine the problem i am facing is after rotate bitmap at canvas paths draw in opposition direction mean bitmap erase in opposition direction of my finger touch .
DrawingPane.class
public class DrawingPanel extends ImageView implements OnTouchListener {
private Matrix mMatrix = new Matrix();
private float mScaleFactor = 1f;
private float mRotationDegrees = 0.f;
private float mFocusX = 0.f;
private float mFocusY = 0.f;
private int mAlpha = 255;
private int mImageHeight, mImageWidth;
private ScaleGestureDetector mScaleDetector;
private RotateGestureDetector mRotateDetector;
private MoveGestureDetector mMoveDetector;
private ShoveGestureDetector mShoveDetector;
private boolean isMoving=false;
EditPhotoActivity editActivity;
Bitmap overlayDefault;
Bitmap overlay;
Bitmap bmp,bmp2;
Paint pTouch;
int whichTabSelected=0;
private Path mPath;
Display display ;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Float> xlist = new ArrayList<Float>();
private ArrayList<Float> ylist = new ArrayList<Float>();
#SuppressLint("NewApi")
public DrawingPanel(Context context, int colorPaint,Bitmap bmp) {
super(context);
if (Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
display = ((Activity)context).getWindowManager().getDefaultDisplay();
mFocusX = display.getWidth()/2f;
mFocusY = display.getHeight()/2f;
try {
overlayDefault=bmp;
overlay=bmp;
overlay=overlay.copy(Config.ARGB_8888, true);
overlay.setHasAlpha(true);
} catch (Exception e) {
e.printStackTrace();
}
mImageHeight = getHeight();
mImageWidth = getWidth();
// Setup Gesture Detectors
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mRotateDetector = new RotateGestureDetector(context, new RotateListener());
mMoveDetector = new MoveGestureDetector(context, new MoveListener());
mShoveDetector = new ShoveGestureDetector(context, new ShoveListener());
pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);
pTouch.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
pTouch.setColor(Color.TRANSPARENT);
//pTouch.setMaskFilter(new BlurMaskFilter(30, Blur.SOLID));
pTouch.setStyle(Paint.Style.STROKE);
pTouch.setStrokeJoin(Paint.Join.ROUND);
pTouch.setStrokeCap(Paint.Cap.ROUND);
pTouch.setStrokeWidth(50);
pTouch.setAntiAlias(true);
setFocusable(true);
setFocusableInTouchMode(true);
mPath = new Path();
paths.add(mPath);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mImageHeight=getHeight();
mImageWidth=getWidth();
bmp = Bitmap.createScaledBitmap(overlay, w, h, false);
bmp2 = Bitmap.createScaledBitmap(overlayDefault, w, h, false);
overlay = bmp.copy(Config.ARGB_8888, true);
overlayDefault = bmp2.copy(Config.ARGB_8888, true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
// mCanvas.drawBitmap(overlayDefault,0, 0, null); //exclude this line to show all as you draw
// mCanvas.drawCircle(X, Y, 80, pTouch);
//draw the overlay over the background
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
if(isMoving)
{
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
}
else
{
mMatrix.postTranslate(0,0);
}
canvas.setMatrix(mMatrix);
canvas.drawBitmap(overlay,0,0, null);
for (Path p : paths) {
canvas.drawPath(p, pTouch);
}
super.onDraw(canvas);
}
public Bitmap getBitmap(){
Bitmap b = Bitmap.createScaledBitmap(overlay,display.getWidth() ,display.getWidth(), false);
overlay = b.copy(Config.ARGB_8888, true);
return overlay;
}
public void setBitmap(Bitmap bmp1){
overlay = bmp1;
invalidate();
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
public void touch_start(float x, float y) {
if(xlist.size()>0 && ylist.size()>0){
xlist.clear();
ylist.clear();
}
xlist.add(x);
ylist.add(y);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
mPath.transform(mMatrix, mPath);
invalidate();
}
public 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;
mPath.transform(mMatrix, mPath);
}
xlist.add(x);
ylist.add(y);
invalidate();
}
public void touch_up() {
mPath.lineTo(mX, mY);
mPath = new Path();
mPath.transform(mMatrix, mPath);
paths.add(mPath);
invalidate();
}
public void OnTouchParent(MotionEvent event){
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
mMatrix.reset();
mMatrix.postScale(mScaleFactor, mScaleFactor);
mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY);
mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY);
float x = event.getX();
float y = event.getY();
/*switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(whichTabSelected==Constant.ERASE)
{
touch_start(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if(whichTabSelected==Constant.ERASE)
{
touch_move(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(whichTabSelected==Constant.ERASE)
{
touch_up();
invalidate();
}
break;
}
if(whichTabSelected==Constant.ERASE)
{
return true;
}
else
{
return false;
}*/
invalidate();
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(getTabMode()==Constant.PANZOOM)
{
mScaleDetector.onTouchEvent(event);
mRotateDetector.onTouchEvent(event);
mMoveDetector.onTouchEvent(event);
mShoveDetector.onTouchEvent(event);
float scaledImageCenterX = (mImageWidth*mScaleFactor)/2;
float scaledImageCenterY = (mImageHeight*mScaleFactor)/2;
}
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(getTabMode()==Constant.ERASE)
{
touch_start(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if(getTabMode()==Constant.ERASE)
{
touch_move(x, y);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if(getTabMode()==Constant.ERASE)
{
touch_up();
invalidate();
}
break;
}
invalidate();
return true;
}
public void setBottomTabMode(int mode)
{
whichTabSelected=mode;
}
public int getTabMode()
{
return whichTabSelected;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
return true;
}
}
private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
#Override
public boolean onRotate(RotateGestureDetector detector) {
mRotationDegrees -= detector.getRotationDegreesDelta();
return true;
}
}
private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
#Override
public boolean onMove(MoveGestureDetector detector) {
PointF d = detector.getFocusDelta();
mFocusX += d.x;
mFocusY += d.y;
isMoving=true;
// mFocusX = detector.getFocusX();
// mFocusY = detector.getFocusY();
return true;
}
}
private class ShoveListener extends ShoveGestureDetector.SimpleOnShoveGestureListener {
#Override
public boolean onShove(ShoveGestureDetector detector) {
mAlpha += detector.getShovePixelsDelta();
if (mAlpha > 255)
mAlpha = 255;
else if (mAlpha < 0)
mAlpha = 0;
return true;
}
}
}
I fixed my problem. Actually when i rotate canvas the event.getX() and event.getY() were not map to current rotation of matrix so by adding this line in mMatrix.invert(tempMatrix); in OnDraw() and also map current x,y in OnTouch() by adding this in OnTouch() method .
float[] coords = new float[] { event.getX(), event.getY() };
tempMatrix.mapPoints(coords);
float x = coords[0];//event.getX();
float y = coords[1];//event.getY();
its working fine .
This effect is happening because you are applying the matrix twice to paths.
Once at touch_start/touch_move by doing mPath.transform(mMatrix, mPath);.
And then again at onDraw(Canvas canvas) by canvas.setMatrix(mMatrix); and then canvas.drawPath(p, pTouch);.
To fix, try to remove the mPath.transform(mMatrix, mPath); from touch_start/touch_move.
Also, I do not know if it is a good practice to set the matrix directly to the canvas. Instead of canvas.setMatrix(mMatrix);, I would prefer to do the following:
canvas.save();
canvas.concat(mMatrix);
//write the code....
canvas.restore();
I want to move and scale the view on the right while dragging it to left side.I tried to set the layout parameters of this view on touch.It moved and scaled the view.But rendering is not correct when moving our finger fastly to both left and right sides.
This view on the right side is a custom layout extends LinearLayout having a ListView as child.And the left side is also another layout and integrated both layouts into a Framelayout(similar to slidingmenu).
Is there any way to render the layout (move and scale) the view without updating LayoutParams?
Is it possible to update the layout using canvas and matrix?
Here is the code for custom layout for view on the right side(the small view).
public class SlidingLayout extends LinearLayout {
private static String LOG_TAG = "SlidingLayout";
private boolean isTranformed = false;
private PanGestureListener gestureListener;
private GestureDetector gestureDetector;
private boolean isAnimating = false;
private boolean isScrolling = false;
private DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
private Matrix matrix = new Matrix();
private float posX = 0;
private float posY = 0;
public CustomSlidingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
gestureListener = new PanGestureListener();
gestureDetector = new GestureDetector(context, gestureListener);
matrix.setTranslate(0, 0);
matrix.setScale(1.0f, 1.0f);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.save();
/*canvas.drawColor(Color.RED);
canvas.translate(posX, posY);
super.onDraw(canvas);*/
/*canvas.restore();
matrix.reset();
matrix = canvas.getMatrix();*/
/*if (isTranformed) {
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
}
super.onDraw(canvas);*/
}
private void makeViewSmall() {
if (!isAnimating) {
isAnimating = true;
Rect rect = new Rect();
getLocalVisibleRect(rect);
ResizeMoveAnimation anim = new ResizeMoveAnimation(this,
(int) (displayMetrics.widthPixels * 0.8), displayMetrics.heightPixels / 4,
displayMetrics.widthPixels * 2, rect.bottom - displayMetrics.heightPixels
/ 4);
anim.setAnimationListener(animationListener);
anim.setDuration(1000);
anim.setInterpolator(new BounceInterpolator());
startAnimation(anim);
}
}
public void makeViewOriginal() {
if(isTranformed){
if (!isAnimating) {
isAnimating = true;
ResizeMoveAnimation anim = new ResizeMoveAnimation(this, 0, 0,
displayMetrics.widthPixels, displayMetrics.heightPixels);
anim.setAnimationListener(animationListener);
anim.setInterpolator(new BounceInterpolator());
anim.setDuration(1000);
startAnimation(anim);
}
}else{
makeViewSmall();
}
}
private AnimationListener animationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) CustomSlidingLayout.this .getLayoutParams();
if (isTranformed) {
isTranformed = false;
params.leftMargin = 0;
params.topMargin = 0;
params.width = displayMetrics.widthPixels;
params.height = displayMetrics.heightPixels;
requestLayout();
} else {
isTranformed = true;
}
isAnimating = false;
}
};
class PanGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
if (isTranformed) {
makeViewOriginal();
return true;
}
return false;
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isTranformed) {
return true;
} else {
return false;
}
}
private int _xDelta = 0;
private int _yDelta = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
//gestureDetector.onTouchEvent(event);
if (isTranformed) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
this.requestLayout();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this .getLayoutParams();
if (layoutParams.leftMargin == 0 && layoutParams.topMargin == 0) {
//this.requestLayout();
isTranformed = false;
isScrolling = false;
break;
}
isScrolling = true;
int xDiff = layoutParams.leftMargin - (X - _xDelta);
layoutParams.leftMargin = X - _xDelta;
int scaleFactor = layoutParams.leftMargin > 0 ? layoutParams.leftMargin : 1;
layoutParams.topMargin = layoutParams.topMargin - ((layoutParams.topMargin / scaleFactor) * xDiff);
if (layoutParams.leftMargin < 0) {
layoutParams.leftMargin = 0;
}
if (layoutParams.topMargin < 0) {
layoutParams.topMargin = 0;
}
layoutParams.width = (displayMetrics.widthPixels - layoutParams.leftMargin);
layoutParams.height = (displayMetrics.heightPixels - (layoutParams.topMargin * 2));
this.requestLayout();
/*final float dx = X - _xDelta;
final float dy = Y - _yDelta;
posX += dx;
posY += dy;
//matrix.postScale(scaleFactor, scaleFactor,0.0f,0.5f);
Bitmap bitmap = Bitmap.createBitmap((int)(displayMetrics.widthPixels - posX), (int)(displayMetrics.heightPixels - posY), Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
this.draw(canvas);
_xDelta = X;
_yDelta = Y;
invalidate();*/
break;
case MotionEvent.ACTION_UP:
isScrolling = false;
break;
case MotionEvent.ACTION_DOWN:
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) this
.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = X - lParams.topMargin;
posX = 0;
posY = 0;
break;
}
return true;
}
return true;
}
}
You can call invalidate() in onTouch() to execute the code in onDraw() to redraw the view.
invalidate() will force a view to draw.