如何在Android中通过按钮初始化onDraw
在我的项目中,用户可以查看PDF文档,我希望他们可以选择通过onDraw和Paint对文档中的每个页面进行注释。我想先打开文档进行查看,通过WhatsApp绘图功能等按钮打开和关闭绘图/绘图功能 我有一个PaintView类扩展了我的PDFView,但当我打开PDF时,会立即调用onDraw,允许我在PDF上绘制,但无法关闭此功能并在页面之间滑动。当我将initDraw移动到按钮时,我在PaintView类中得到一个空指针如何在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
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();
值得一试。