【发布时间】:2020-02-08 04:37:58
【问题描述】:
我正在为学校的一个团队项目开发一个简单的绘图应用程序,而 onDraw 方法虽然被可靠地调用,但只会产生一个空白的白色屏幕。这发生在我们决定从使用活动切换到片段之后。当我们在 Draw Activity 中使用时,我的绘图视图代码可以正常工作,但现在我们使用的是 DrawFragment,它无法正常工作。我在整个 SO 中都在寻找有类似问题的人,但无济于事。本来以为是因为传递给onDraw方法的Canvas参数位图为空,但是当我将canvas设置为自己的私有变量mCanvas时,问题依旧。
编辑:我忘了提到,当我在调试器中浏览代码时,在 onDraw 方法的末尾,在调用每一行之后,我可以查看画布中包含的位图并看到是完全绿色的,并且具有我指定的路径。但是,我的设备上的实际屏幕上没有任何内容。
EDIT2:根据 Mike 的建议修改了我的 fragment_draw.xml,但我仍然面临同样的问题。我尝试将 RelativeLayout 的背景也设置为透明,以查看是否会有所作为,但没有。
我的绘图视图:
package edu.cascadia.doodlebug;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
private final int TOUCH_TOLERANCE = 4;
private float mX, mY; // coordinates for tracking path drawing
private Bitmap mBitmap; // bitmap for the canvas
private Canvas mCanvas; // canvas object to draw onto
private Path mPath; // path for drawing
private Paint mPaint; // paint to describe the line being drawn
private Paint mBitmapPaint;
private Context mContext;
public DrawingView(Context c) {
this(c, null);
}
public DrawingView(Context c, AttributeSet attr) {
super(c, attr);
mContext = c;
mPath = new Path();
setWillNotDraw(false);
setWillNotCacheDrawing(false);
// set up paint object for the line
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(12);
// bitmap paint to draw bitmap
mBitmapPaint = new Paint();
}
@Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
super.onSizeChanged(w, h, oldW, oldH);
mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
canvas = mCanvas;
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
// Test Code
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(300, 500);
mPath.quadTo(300, 500, 330, 750);
mPath.lineTo(getWidth(), getHeight());
mPath.close();
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
touchEnd();
invalidate();
break;
}
return true;
}
private void touchStart(float x, float y) {
// set up the path to start drawing from this location
mPath.reset();
mPath.moveTo(x, y);
// add the start coordinates
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
// get the change in both x and y directions
float deltaX = Math.abs(x - mX);
float deltaY = Math.abs(y - mY);
// check if greater than touch tolerance
if (deltaX >= TOUCH_TOLERANCE || deltaY >= TOUCH_TOLERANCE) {
//draw the line to the new coordinates
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touchEnd() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.close();
mPath.reset();
}
public int getLineWidth() {
return (int) mPaint.getStrokeWidth();
}
public void setLineWidth(int width) {
mPaint.setStrokeWidth(width);
}
public void setBackground(Bitmap bitmap) {
mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
}
我的 DrawFragment:
package edu.cascadia.doodlebug;
import android.app.Activity;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class DrawFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private DrawingView mView;
public DrawFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_draw, container, false);
mView = (DrawingView) v.findViewById(R.id.drawingView);
return v;
}
public void setBackground(Bitmap bitmap) { mView.setBackground(bitmap); }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void startCamera();
}
}
编辑:更新 fragment_draw.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="edu.cascadia.doodlebug.DrawFragment"
android:background="#ffff">
<view
android:id="@+id/drawingView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
class="edu.cascadia.doodlebug.DrawingView" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="@+id/imageView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:src="@drawable/color_selector"
android:contentDescription=""/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:id="@+id/linearLayout">
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgBee"
android:src="@drawable/bee_sticker" />
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgDinosaur"
android:src="@drawable/dinosaur_sticker" />
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgKitty"
android:src="@drawable/kitty_sticker" />
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgTaz"
android:src="@drawable/taz_sticker" />
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgLego"
android:src="@drawable/lego_sticker" />
<ImageView
android:layout_width="48dp"
android:layout_height="50dp"
android:id="@+id/imgTurkey"
android:src="@drawable/turkey_sticker" />
</LinearLayout>
<ImageButton
android:layout_width="70dp"
android:layout_height="55dp"
android:id="@+id/imageButttonTakePic"
android:src="@drawable/camera"
android:layout_toRightOf="@+id/imageView"
android:scaleType="fitXY"
android:layout_marginLeft="20dp" />
</RelativeLayout>
【问题讨论】:
-
RelativeLayout覆盖了您的自定义View,因为您在FrameLayout中将其宽度和高度设置为match_parent。 -
感谢 Mike,我将自定义视图包含在 RelativeLayout 中,并完全删除了 FrameLayout。但是,我仍然面临同样的问题。我已经更新了 xml 代码,但它现在似乎应该可以工作了。
-
删除此行:
canvas = mCanvas;。此外,canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);并没有真正做任何事情。它只是在所有内容上绘制一个透明的位图。 -
效果很好!非常感谢您的帮助!
-
我刚刚意识到我误读了您的代码,并且我在上一条评论中说错了。正如您所拥有的,
canvas.drawBitmap(...)调用正在将位图mBitmap绘制到自身上,因为那是mCanvas的支持位图。您没有看到任何内容,因为您创建的位图不是视图显示的屏幕位图。
标签: android