在 SurfaceView 上绘图
Drawing on SurfaceView
我正在尝试使用 onTouch 侦听器在 surfaceview 上绘图,但我得到了奇怪的绘图(线条的边缘自行移动),正如您在下面的 GIF 波纹管中看到的那样:
这是我的代码:
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) {
}
}
我该如何解决这个问题?以及如何使 surfaceview 变白,正如您看到的,它一开始是黑色的。谢谢!
这可能是因为您在将 canvas 与表面视图同步之前重置了路径。
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset(); // move this line out
surfaceHolder.unlockCanvasAndPost(canvas);
尝试将 path.reset() 移动到 path.moveTo(X,Y).[= 之前12=]
path.reset(); // add just above moveTo
path.moveTo(X,Y);
表面视图实际上在您的后面 window。它在 window 上打了一个洞让你看到。所以你可以在你的 window 中把东西放在它上面,但是你的 window 中的任何东西都不能出现在它后面。所以背景颜色不起作用。但是你得到 canvas 的表面视图,所以你可以提供自己的颜色来绘制 canvas。
private void setRefreshColor(){
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
surfaceHolder.unlockCanvasAndPost(canvas);
}
从 onSurfaceCreated() 调用此函数。另外每次刷新canvas需要绘制REFRESH_COLOR。
尝试以下操作:
1)背景问题:
根据:
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.
并基于 xav 的 答案:Set the Background Image of a SurfaceView
为了改变你的表面背景颜色,你可以在 surfaceView 的顶部放置一个视图(重叠表面视图),surfaceHolder 像素格式为透明。
2) 奇怪的绘图问题:"the edge of the line moves on it's own"
您已经得到答案:感谢 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
我正在尝试使用 onTouch 侦听器在 surfaceview 上绘图,但我得到了奇怪的绘图(线条的边缘自行移动),正如您在下面的 GIF 波纹管中看到的那样:
这是我的代码:
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) {
}
}
我该如何解决这个问题?以及如何使 surfaceview 变白,正如您看到的,它一开始是黑色的。谢谢!
这可能是因为您在将 canvas 与表面视图同步之前重置了路径。
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset(); // move this line out
surfaceHolder.unlockCanvasAndPost(canvas);
尝试将 path.reset() 移动到 path.moveTo(X,Y).[= 之前12=]
path.reset(); // add just above moveTo
path.moveTo(X,Y);
表面视图实际上在您的后面 window。它在 window 上打了一个洞让你看到。所以你可以在你的 window 中把东西放在它上面,但是你的 window 中的任何东西都不能出现在它后面。所以背景颜色不起作用。但是你得到 canvas 的表面视图,所以你可以提供自己的颜色来绘制 canvas。
private void setRefreshColor(){
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
surfaceHolder.unlockCanvasAndPost(canvas);
}
从 onSurfaceCreated() 调用此函数。另外每次刷新canvas需要绘制REFRESH_COLOR。
尝试以下操作:
1)背景问题:
根据:
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.
并基于 xav 的 答案:Set the Background Image of a SurfaceView
为了改变你的表面背景颜色,你可以在 surfaceView 的顶部放置一个视图(重叠表面视图),surfaceHolder 像素格式为透明。
2) 奇怪的绘图问题:"the edge of the line moves on it's own"
您已经得到答案:感谢 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