【问题标题】:Drawing on SurfaceView在 SurfaceView 上绘图
【发布时间】:2019-09-01 02:04:31
【问题描述】:

我正在尝试使用 onTouch 侦听器在表面视图上绘图,但我得到了奇怪的绘图(线的边缘自行移动),正如您在下面的 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变白,因为你可以看到它一开始是黑色的。谢谢!

【问题讨论】:

    标签: android surfaceview


    【解决方案1】:

    尝试以下方法:

    1) 背景问题:

    根据:

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

    表面是 Z 顺序的,因此它位于窗口后面 表面视图; SurfaceView 在其窗口中打了一个洞,以允许其 要显示的表面。视图层次结构将负责 正确地与 Surface 合成 SurfaceView 的任何兄弟姐妹 通常会出现在它上面。这可以用来放置 覆盖,例如 Surface 顶部的按钮,但请注意 它可以对性能产生影响,因为一个完整的 alpha 混合 每次 Surface 更改时都会执行合成。

    并基于 xav 的 答案:Set the Background Image of a SurfaceView

    为了改变你的表面背景颜色,你可以在表面视图的顶部放置一个视图(与表面视图重叠),表面保持像素格式为透明。

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

    【讨论】:

      【解决方案2】:

      这可能是因为您在将画布与表面视图同步之前重置了路径。

      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);
      

      【讨论】:

      • 有效!谢谢!如何解决黑屏问题?
      • 您可以尝试使用 SurfaceView 类的 setBackgroundColor 方法从您的 surfaceCreate 函数中将背景颜色初始化为白色。 surfaceView.setBackgroundColor(0Xffffffff); // 或 Color.WHITE
      • setBackgroundColor 不会让我在 surfaceView 的顶部绘制任何东西
      【解决方案3】:

      表面视图实际上是在您的窗口后面。它在窗户上打了一个洞让你看到。所以你可以在你的窗口中把东西放在它上面,但你窗口中的任何东西都不能出现在它后面。所以背景颜色不起作用。但是你会得到带有表面视图的画布,因此你可以提供自己的颜色来在画布上绘制。

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

      从 onSurfaceCreated() 调用这个函数。此外,每次刷新画布时,您都需要绘制 REFRESH_COLOR。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        相关资源
        最近更新 更多