I'm trying to draw on surfaceview using onTouch listener, but i'm getting weird drawings (the edge of the line moves on it's own) as you can see in the GIF bellow:
Here's my code:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Canvas canvas;
private Path path;
Paint mPaint = new Paint();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
surfaceView = (SurfaceView) findViewById( R.id.surfaceView );
surfaceHolder = surfaceView.getHolder();
surfaceView.getHolder().addCallback( this );
canvas = surfaceView.getHolder().lockCanvas();
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( 50);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d( "surfaceCreated", "surfaceCreated " );
path = new Path();
surfaceHolder = holder;
surfaceView.setOnTouchListener( new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float X = event.getX();
float Y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
Log.d( "surfaceCreated", "action down x="+X );
// canvas = surfaceHolder.lockCanvas();
path.moveTo(X,Y);
// mv.touch_start(X,Y);
// canvas = surfaceHolder.lockCanvas();
break;
case MotionEvent.ACTION_MOVE:
Log.d( "surfaceCreated", "action move x="+X );
path.lineTo(X,Y);
break;
case MotionEvent.ACTION_UP:
Log.d( "surfaceCreated", "action up x="+X );
path.lineTo(event.getX(),event.getY());
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset();
surfaceHolder.unlockCanvasAndPost(canvas);
// mCanvas.drawLine( downx, downy, upx, upy, mPaint );
break;
}
if(path != null){
Log.d( "surfaceCreated", "path is not null"+path );
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
return true;
}
});
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
How i can solve the issue? and how i can make the surfaceview white, as you can see it's black at the beginning. Thank you!
Try the following:
1) Background Problem:
According to:
https://developer.android.com/reference/android/view/SurfaceView
The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.
and based on xav's answer: Set the Background Image of a SurfaceView
In order to change your surface background color, you can place a view (overlapping the surface view) on top of the surfaceView with a surfaceHolder pixel format of transparent.
2) Weird Drawing Problem: "the edge of the line moves on it's own"
You already got your answer: Thanks to Guillaume Adam
3) Example:
MainActivity.class
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;
private View surfaceBackground;
private Button b_change_surface_background_color;
private Button b_clear;
private Path path;
private Paint mPaint = new Paint();
private int[] colors = new int[]{Color.WHITE, Color.GREEN, Color.MAGENTA, Color.BLUE};
private int currentSurfaceBackgroundColor = Color.WHITE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b_change_surface_background_color = (Button) findViewById(R.id.b_change_surface_background_color);
b_change_surface_background_color.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int colorIndex = new Random().nextInt(colors.length);
currentSurfaceBackgroundColor = colors[colorIndex];
changeSurfaceBackgroundColor(currentSurfaceBackgroundColor);
}
});
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceView.setZOrderOnTop(true);
surfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
surfaceView.getHolder().addCallback(this);
surfaceBackground = (View) findViewById(R.id.surfaceBackground);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(50);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void surfaceCreated(SurfaceHolder holder) {
path = new Path();
surfaceView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float X = event.getX();
float Y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
path.reset();
path.moveTo(X, Y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(X, Y);
break;
case MotionEvent.ACTION_UP:
path.lineTo(event.getX(),event.getY());
Canvas canvas1 = surfaceView.getHolder().lockCanvas();
canvas1.drawPath(path, mPaint);
surfaceView.getHolder().unlockCanvasAndPost(canvas1);
break;
}
if(path != null){
Canvas canvas = surfaceView.getHolder().lockCanvas();
canvas.drawPath(path, mPaint);
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
return true;
}
});
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
private void changeSurfaceBackgroundColor(@ColorInt int color) {
if (surfaceBackground != null) {
surfaceBackground.setBackgroundColor(color);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Change Surface Background Color"
android:textAllCaps="false"
android:layout_alignParentTop="true"
android:id="@+id/b_change_surface_background_color">
</Button>
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/b_change_surface_background_color"
android:id="@+id/surfaceView">
</SurfaceView>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/surfaceBackground"
android:layout_below="@id/b_change_surface_background_color"
android:background="@android:color/white">
</View>
</RelativeLayout>
4) Output
It may be because you reset the path before you synced the canvas with the surface view.
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset(); // move this line out
surfaceHolder.unlockCanvasAndPost(canvas);
Try to move path.reset() just before path.moveTo(X,Y).
path.reset(); // add just above moveTo
path.moveTo(X,Y);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With