1

我正在做一个小型绘画 android 应用程序。我想创建一个自定义视图来在上面画一些东西。创建布局并添加我的视图时。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.androidpaint.PaintView 
android:id="@+id/paintPlace"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</RelativeLayout>

它有一个错误

java.lang.NullPointerException
    Exception details are logged in Window > Show View > Error Log
    java.lang.NullPointerException
        at android.graphics.Canvas.drawPath(Canvas.java:1021)
        at com.example.androidpaint.PaintView.onDraw(PaintView.java:69)
        at android.view.View.draw(View.java:13712)
        at android.view.View.draw(View.java:13596)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13594)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13594)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13715)
        at android.view.View.draw(View.java:13596)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13715)

这是我的 PaintView 类:

public class PaintView extends View{
        boolean isEraser = false;
        private Bitmap  mBitmap;
        private Canvas  mCanvas;
        private Path    mPath;
        private Paint   mBitmapPaint;
        private Paint   mPaint;
        private Paint   mPaintScreen;
        int color;
        public PaintView(Context c) {
            super(c);
            mPaintScreen = new Paint();
            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(5);
            color = mPaint.getColor();
            mPath = new Path();

            mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);


        }
        public PaintView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public PaintView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
        @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);
            mBitmap.eraseColor(Color.WHITE);
        }
        private float mX =-100, mY = -100;
        Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.background );
        private static final float TOUCH_TOLERANCE = 7;

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(mBitmap,0,0,mPaintScreen);
            canvas.drawPath(mPath, mPaint);
            canvas.drawBitmap(b, 10, 10, mPaint);
        }
        private void touch_start(float x, float y) {
            mPath.reset();
            mPath.moveTo(x, y);
            mX = x;
            mY = y;
        }
        private void touch_move(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 touch_up() {
           mPath.lineTo(mX, mY);
           mCanvas.drawPath(mPath, mPaint);
           mPath.reset();
           mX =-100;
           mY = -100;

        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
            switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                break;
            }
            postInvalidate();
            return true;
            }
        public void setColor(int c){
            if(isEraser)
                mPaint.setColor(Color.WHITE);
            else{
                mPaint.setColor(Color.CYAN);
                //mPaint.setColor(c);
                color = c;
                postInvalidate();
        }
        }
        public float getLineWidth(){
            return mPaint.getStrokeWidth();
        }
        public void setLineWidth(float w){
            mPaint.setStrokeWidth(w);
        }
        public int getDrawingColor(){
            return mPaint.getColor();
        }
        public void clearPaint(){
            mPath.reset();
            mBitmap.eraseColor(Color.WHITE);
            invalidate();
        }
        public void setEraserIcon(){
            b = BitmapFactory.decodeResource(getResources(),R.drawable.eraser );
            color = mPaint.getColor();
            mPaint.setColor(Color.WHITE);
            isEraser = true;
        }
        public void setBrushIcon(){
            b = BitmapFactory.decodeResource(getResources(),R.drawable.brush );
            mPaint.setColor(color);
            isEraser = false;

        }
        public void saveImage(){
            String fileName = "Image" + System.currentTimeMillis();

            ContentValues values = new ContentValues();
            values.put(Images.Media.TITLE,fileName);
            values.put(Images.Media.DATE_ADDED,System.currentTimeMillis());
            values.put(Images.Media.MIME_TYPE,"image/jpeg");

            Uri uri = getContext().getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
            try{
                OutputStream outStream = getContext().getContentResolver().openOutputStream(uri);
                mBitmap.compress(Bitmap.CompressFormat.JPEG,100, outStream);
                outStream.flush();
                outStream.close();

                Toast message = Toast.makeText(getContext(), R.string.message_saved, Toast.LENGTH_SHORT);
                message.setGravity(Gravity.CENTER, message.getXOffset(),message.getYOffset());
                message.show();

            }catch(Exception ex){
                Toast message = Toast.makeText(getContext(),R.string.message_error_saving, Toast.LENGTH_SHORT);
                message.setGravity(Gravity.CENTER, message.getXOffset()/2,message.getYOffset()/2);
                message.show();
            }
        }
    }`

我创建了一个新的活动并设置这样的代码:

 protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(new PaintView(this));
        }

但是,当调用包含 PaintView 的我的 XML 时。它得到我上面所说的错误

我是android的新手,所以非常感谢你帮助我!

4

1 回答 1

3

尝试在public PaintView(Context context, AttributeSet attrs)构造函数中添加初始化代码。所以它看起来像:

   public PaintView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintScreen = new Paint();
        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(5);
        color = mPaint.getColor();
        mPath = new Path();

        mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}

并打电话给你,setContentView(new PaintView(this));setContentView(your.xml);你的 View 作为标签在哪里。

你得到了NullPointerException因为你没有正确初始化你的 custom View。当您创建ViewXML 文件时,YourView(Context context, AttributeSet attrs)将调用构造函数。

当您通过 using 动态创建视图时YourView view = new YourView(this)' - 'YourView(Context context)被调用。

为了防止这种情况,您可以在内部创建带有初始化的小方法,您将在其中初始化组件,然后从每个构造函数调用此方法。

当您想为您的绘图动态设置一些其他值时,您需要invalidate();在每次更改后调用。

于 2013-06-17T04:52:37.827 回答