在SurfaceView上绘制

5

我正在尝试使用 onTouch 监听器在 SurfaceView 上绘制图形,但是我得到了奇怪的绘图结果(线条的边缘自行移动),如下图所示:

enter image description here

这是我的代码:

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变为白色,因为你可以看到它一开始是黑色的。谢谢!

3个回答

5

请尝试以下方法:

1) 背景问题:

根据https://developer.android.com/reference/android/view/SurfaceView

表面是按Z顺序排列的,以便在窗口后面保持其SurfaceView;SurfaceView在其窗口中打洞,以允许其表面被显示。视图层次结构将负责与Surface正确合成该SurfaceView的任何兄弟姐妹,这些兄弟姐妹通常出现在其上方。这可以用于放置覆盖层,例如按钮,位于Surface的顶部,但请注意,每次Surface更改时,将执行完整的Alpha混合合成,这可能会对性能产生影响。

根据xav的答案:设置SurfaceView的背景图片

为了更改您的表面背景颜色,您可以在表面视图上方放置一个视图(重叠表面视图),其surfaceHolder像素格式为透明。

2) 奇怪的绘制问题:“线条边缘自行移动”

你已经得到了答案:感谢Guillaume Adam

3) 示例:

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) 输出

输出


1
可能是因为您在将画布与SurfaceView同步之前重置了路径。
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawPath(path, mPaint);
path.reset(); // move this line out
surfaceHolder.unlockCanvasAndPost(canvas);

尝试将path.reset()放在path.moveTo(X,Y)之前。
path.reset(); // add just above moveTo
path.moveTo(X,Y);

可以工作了!谢谢!如何解决黑屏问题? - Nizar
你可以尝试在surfaceCreate函数中使用SurfaceView类的setBackgroundColor方法将背景颜色初始化为白色。 surfaceView.setBackgroundColor(0Xffffffff); // 或者 Color.WHITE - Guillaume Adam
setBackgroundColor不允许我在surfaceView的顶部绘制任何东西。 - Nizar

0

Surface view 实际上是在你的窗口后面。它为你打了一个窗口可见的洞。所以你可以在你的窗口中将一些东西放在它的顶部,但是窗口中的任何东西都不会出现在它的后面。因此背景颜色不起作用。但是你可以使用 surface view 的画布,提供自己的颜色来绘制画布。

 private void setRefreshColor(){
    Canvas canvas = surfaceHolder.lockCanvas();
    canvas.drawColor(Color.WHITE);
    surfaceHolder.unlockCanvasAndPost(canvas);
}

在onSurfaceCreated()函数中调用此函数。并且每次刷新画布时,您需要绘制REFRESH_COLOR。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接