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



在我的项目中,用户可以查看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();
}

我的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,则会阻止父视图处理输入。(这将防止父视图在绘图时翻页,这将非常烦人(


希望这能有所帮助!

最新更新