如何在Android中通过按钮初始化onDraw

如何在Android中通过按钮初始化onDraw,android,android-canvas,paint,ondraw,androidpdfviewer,Android,Android Canvas,Paint,Ondraw,Androidpdfviewer,在我的项目中,用户可以查看PDF文档,我希望他们可以选择通过onDraw和Paint对文档中的每个页面进行注释。我想先打开文档进行查看,通过WhatsApp绘图功能等按钮打开和关闭绘图/绘图功能 我有一个PaintView类扩展了我的PDFView,但当我打开PDF时,会立即调用onDraw,允许我在PDF上绘制,但无法关闭此功能并在页面之间滑动。当我将initDraw移动到按钮时,我在PaintView类中得到一个空指针 java.lang.NullPointerException: Atte

在我的项目中,用户可以查看PDF文档,我希望他们可以选择通过onDraw和Paint对文档中的每个页面进行注释。我想先打开文档进行查看,通过WhatsApp绘图功能等按钮打开和关闭绘图/绘图功能

我有一个PaintView类扩展了我的PDFView,但当我打开PDF时,会立即调用onDraw,允许我在PDF上绘制,但无法关闭此功能并在页面之间滑动。当我将initDraw移动到按钮时,我在PaintView类中得到一个空指针

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference
    at com.example.dissertation814.pdfViewer.PaintView.onDraw(PaintView.java:60)
我的查看器活动:

public class PdfViewerActivity extends AppCompatActivity {

private boolean isDrawInit = false;
private PaintView paintView;

//firebase auth
private FirebaseAuth mAuth;

//variables
public String currentUserAccount;
public String teacherAccountNav = "Teacher";

PDFView pdfView;

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pdf_viewer);

    //PDFView to display PDFs
    pdfView = findViewById(R.id.pdfView);

    //use best quality
    pdfView.useBestQuality(true);

    //get data from intent
    Intent i = this.getIntent();
    Uri uri = i.getParcelableExtra("FILE_PATH_URI");

    //Get the pdf file
    assert uri != null;
    File file = new File(Objects.requireNonNull(uri.getPath()));

    if(file.canRead()){
        //load pdf file
        pdfView.fromFile(file)
                .defaultPage(0)
                .enableSwipe(true)
                .swipeHorizontal(true)
                .pageSnap(true)

                .onDrawAll(new OnDrawListener() {
                    @Override
                    public void onLayerDrawn(Canvas canvas, float pageWidth, float pageHeight, int displayedPage) {
                        Bitmap  bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);

                        Paint paint = new Paint();
                        paint.setColor(Color.BLACK);
                        canvas.drawBitmap(bitmap, 0,0, paint);
                    }
                })

                .onLoad(new OnLoadCompleteListener() {
            @Override
            public void loadComplete(int nbPages) {
                Toast.makeText(PdfViewerActivity.this, "No. of pages: " + nbPages, Toast.LENGTH_SHORT).show();
            }
        }).load();
    }

}

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public void onInitDrawClick(View view){

}

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
protected void onResume() {
    super.onResume();
    if(!isDrawInit){
        initDraw();
        isDrawInit = true;
    }
}

//initialise paint view
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initDraw(){
        paintView = findViewById(R.id.paintView);
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
        paintView.init(metrics);
}

//user finger path from paint view class
static class FingerPath{
    int colour;
    int strokeWidth;
    Path path;

    FingerPath(int colour, int strokeWidth, Path path){
        this.colour = colour;
        this.strokeWidth = strokeWidth;
        this.path = path;
    }
}
我的PaintView课程:

public class PaintView extends PDFView {
private Paint mPaint;
private Canvas mCanvas;
private Bitmap mBitmap;

private ArrayList<PdfViewerActivity.FingerPath> paths = new ArrayList<>();
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);

private static final float TOUCH_TOLERANCE = 4;

private Path mPath;
private float mX;
private float mY;
public int brushColour = Color.BLACK;
public int brushSize = 10;


public PaintView(Context context, AttributeSet set) {
    super(context, set);
    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.setXfermode(null);
    mPaint.setAlpha(0xff);
}

public void init (DisplayMetrics metrics){
    int height = (int) (metrics.heightPixels);
    int width = metrics.widthPixels;

    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    mCanvas.drawColor(Color.TRANSPARENT);

    for(PdfViewerActivity.FingerPath fp : paths){
        mPaint.setColor(fp.colour);
        mPaint.setStrokeWidth(fp.strokeWidth);
        mPaint.setMaskFilter(null);

        mCanvas.drawPath(fp.path, mPaint);
    }

    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    canvas.restore();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            touchStart(x,y);
            invalidate();
            break;
            case MotionEvent.ACTION_MOVE:
                touchMove(x,y);
                invalidate();
                break;
                case MotionEvent.ACTION_UP:
                    touchUp();
                    break;
    }
    return true;
}

private void touchUp(){
    mPath.lineTo(mX,mY);
}

private void touchMove(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;
    }
}

private void touchStart(float x, float y){
    mPath = new Path();
    PdfViewerActivity.FingerPath fp = new PdfViewerActivity.FingerPath(brushColour, brushSize, mPath);
    paths.add(fp);

    mPath.reset();
    mPath.moveTo(x,y);


    mX = x;
    mY = y;
}

public void clear(){
    paths.clear();
    invalidate();
}
public类PaintView扩展了PDFView{
私人油漆;
私人帆布mCanvas;
私有位图mBitmap;
私有ArrayList路径=新ArrayList();
专用油漆mBitmapPaint=新油漆(油漆抖动标志);
专用静态最终浮动接触公差=4;
专用路径mPath;
私人浮动mX;
私人浮动我的;
公共颜色=颜色。黑色;
公共大小=10;
公共画图视图(上下文,属性集){
超级(上下文,集合);
mPaint=新油漆();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(油漆、样式、笔划);
mPaint.setStrokeJoin(油漆.连接.圆形);
mPaint.setStrokeCap(油漆盖圆形);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
}
公共void init(DisplayMetrics){
int高度=(int)(metrics.heightPixels);
int width=metrics.widthPixels;
mBitmap=Bitmap.createBitmap(宽度、高度、Bitmap.Config.ARGB_8888);
mCanvas=新画布(mBitmap);
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
canvas.save();
mCanvas.drawColor(彩色透明);
用于(PdfViewerActivity.FingerPath fp:路径){
mPaint.setColor(fp.COLOR);
mPaint.设置行程宽度(fp.行程宽度);
mPaint.setMaskFilter(null);
mCanvas.drawPath(fp.path,mPaint);
}
drawBitmap(mBitmap,0,0,mbitMapPoint);
canvas.restore();
}
@凌驾
公共布尔onTouchEvent(运动事件){
float x=event.getX();
float y=event.getY();
开关(event.getAction()){
case MotionEvent.ACTION\u DOWN:
touchStart(x,y);
使无效();
打破
case MotionEvent.ACTION\u移动:
touchMove(x,y);
使无效();
打破
case MotionEvent.ACTION\u UP:
修补();
打破
}
返回true;
}
私人修补{
mPath.lineTo(mX,mY);
}
私有无效触摸移动(浮动x、浮动y){
float dx=Math.abs(x-mX);
float dy=Math.abs(y-mY);
如果(dx>=接触公差| | dy>=接触公差){
兆帕四分之一秒(mX,mY,(x+mX)/2,(y+mY)/2);
mX=x;
mY=y;
}
}
专用void touchStart(浮点x、浮点y){
mPath=新路径();
PdfViewerActivity.FingerPath fp=新的PdfViewerActivity.FingerPath(笔刷颜色、笔刷大小、mPath);
添加路径(fp);
mPath.reset();
移动到(x,y)的速度;
mX=x;
mY=y;
}
公共空间清除(){
清除路径();
使无效();
}
我的XML:

 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout
     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:background="@color/black"
     tools:context=".pdfViewer.PdfViewerActivity">

<Button
    android:id="@+id/initDraw"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="init"
    app:layout_constraintBottom_toTopOf="@+id/relativeLayout"
    app:layout_constraintEnd_toStartOf="@+id/homeButton"
    app:layout_constraintStart_toEndOf="@+id/backButton"
    app:layout_constraintTop_toTopOf="parent"
    android:onClick="onInitDrawClick"/>

<ImageButton
    android:id="@+id/backButton"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:background="@color/black"
    android:contentDescription="@string/back_button"
    android:onClick="onBackClicked"
    android:src="@drawable/backward_arrow"
    app:layout_constraintBottom_toTopOf="@+id/relativeLayout"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.112"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.8" />

<ImageButton
    android:id="@+id/homeButton"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:layout_marginEnd="64dp"
    android:layout_marginRight="64dp"
    android:background="@color/black"
    android:onClick="onHomeClicked"
    android:src="@drawable/ic_home_black_24dp"
    app:layout_constraintBottom_toTopOf="@+id/relativeLayout"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="1.0"
    app:layout_constraintStart_toEndOf="@+id/backButton"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.8" />

<RelativeLayout
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="800dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.919"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">

    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.example.dissertation814.pdfViewer.PaintView
        android:id="@+id/paintView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/transparent"/>


</RelativeLayout>

 </androidx.constraintlayout.widget.ConstraintLayout>

onDraw
是一种方法,因此它不是您要初始化的东西。我认为您也不应该尝试禁用该方法。尽管您可以重写它,这会让您控制绘制的内容

考虑问题的另一种解决方案。您可以控制哪个视图处理用户输入,而不是启用或禁用
onDraw
方法


解决方案:

在方法
onTouchEvent
中返回
true
时,您声明在视图层次结构中不需要处理此输入

相反,您应该做的是检查绘图功能是否应启用。如果绘图功能被禁用,则返回
false
。否则,如果绘图功能被启用,则处理输入,然后返回
true

例如:

@Override
public boolean onTouchEvent(MotionEvent event) {
    // Check whether or not the drawing feature is disabled
    if (drawingIsEnabled == false) { 
         // Let parent views process this input
         return false;
    }

    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            touchStart(x,y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(x,y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touchUp();
            break;
    }

    // Prevent parent views from processing this input
    return true;
}
返回
false
时,输入将在视图层次结构中进一步向上传递,以便父视图有机会处理输入。(这将允许您滑动页面)

但是,如果返回
true
,则会阻止父视图处理输入。(这将阻止父视图在绘图时滑动页面,这将非常烦人)



希望这有帮助!

谢谢,是的,这很有意义!然后我如何通过单击按钮来控制drawingIsEnabled?我的活动中有一个按钮,但不知道如何控制drawingIsEnabled,因为它位于不同的类中。问得好。我想也许你可以将视图中的上下文转换为活动引用并访问它o以这种方式启动活动。
PdfViewerActivity myActivity=(PdfViewerActivity)getContext();
值得一试。