0

我创建了一个自定义视图,当您在屏幕上拖动手指时绘制线条,然后我在 xml 布局中添加了视图,但是当我尝试在我添加到xml布局中的那个视图上绘制一些东西时,它给了我nullpointer异常

定义视图是这样的

public class page extends View  
{
    private static final String TAG = "DrawView";

    private static final float MINP = 0.25f;
    private static final float MAXP = 0.75f;

    private Context context;
    private Paint mPaint = new Paint();
    private int[] pencolor = { Color.BLUE, Color.GREEN, Color.MAGENTA,
              Color.BLACK, Color.CYAN, Color.GRAY, Color.RED, Color.DKGRAY,
              Color.LTGRAY, Color.YELLOW };

    private Canvas  mCanvas;
    private Path    mPath;

    private ArrayList<Path> paths = new ArrayList<Path>();


    public void resetPenColor()
    {
        Random random = new Random();
        random.setSeed(System.currentTimeMillis());

        int color_index = random.nextInt(pencolor.length);
       //   Toast.makeText(context, "Pen Color "+color_index, Toast.LENGTH_SHORT).show();
        mPaint.setColor(pencolor[color_index]);
    }

    public page(Context context) {
        super(context);
        this.context = context;
        setFocusable(true);
        setFocusableInTouchMode(true);

       //this.setOnTouchListener(this);

        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(6);
        mCanvas = new Canvas();
        mPath = new Path();
        paths.add(mPath);


    }



    public page(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public page(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);
        }

        @Override
        protected void onDraw(Canvas canvas) {            

            for (Path p : paths){
                canvas.drawPath(p, mPaint);
                Log.v("draw", "---line");
            }
        }

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;

        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);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw            
            mPath = new Path();
            paths.add(mPath);
        }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub
         super.onTouchEvent(event);
         float x = event.getX();
          float y = event.getY();

          switch (event.getActionMasked()) {
              case MotionEvent.ACTION_DOWN:
                  touch_start(x, y);
                  invalidate();
                  break;
              case MotionEvent.ACTION_MOVE:
                  touch_move(x, y);
                  invalidate();
                  break;
              case MotionEvent.ACTION_UP:
                  touch_up();
                  invalidate();
                  break;
              case MotionEvent.ACTION_POINTER_DOWN:
                  resetPenColor();
                //  Toast.makeText(context, "Multitouch", Toast.LENGTH_SHORT).show();
                  invalidate();
                  break;
          }
          return true;
    }




}

在主要活动中添加布局

public void onCreate(Bundle onsavestate)
    {
        super.onCreate(onsavestate);

        page pageview = new page(this);
        setContentView(R.layout.book);
}

最后是 xml 文件“book.xml”

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

    <LinearLayout
        android:id="@+id/buttonlayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:background="@drawable/buttoncontainer"
        android:gravity="bottom"
        android:orientation="horizontal" >

        <ImageButton
            android:id="@+id/refresh"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@color/white"
            android:src="@drawable/refresh"
            android:layout_marginLeft="4dp" />

        <ImageButton
            android:id="@+id/save"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@color/white"
            android:src="@drawable/save"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="4dp" />
    </LinearLayout> 

    <com.gsmappstabs.autographplease.page
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/buttonlayout" />

</RelativeLayout>

日志文件

10-31 15:21:58.038: E/AndroidRuntime(478): FATAL EXCEPTION: main
10-31 15:21:58.038: E/AndroidRuntime(478): java.lang.NullPointerException
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.gsmappstabs.autographplease.page.touch_start(page.java:100)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.gsmappstabs.autographplease.page.onTouchEvent(page.java:134)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.View.dispatchTouchEvent(View.java:3885)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.os.Handler.dispatchMessage(Handler.java:99)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.os.Looper.loop(Looper.java:123)
10-31 15:21:58.038: E/AndroidRuntime(478):  at android.app.ActivityThread.main(ActivityThread.java:3683)
10-31 15:21:58.038: E/AndroidRuntime(478):  at java.lang.reflect.Method.invokeNative(Native Method)
10-31 15:21:58.038: E/AndroidRuntime(478):  at java.lang.reflect.Method.invoke(Method.java:507)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
10-31 15:21:58.038: E/AndroidRuntime(478):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
10-31 15:21:58.038: E/AndroidRuntime(478):  at dalvik.system.NativeStart.main(Native Method)
4

2 回答 2

2

当您View在 XML 文件中定义时。不调用第一个构造函数。您需要确保所有变量都是从每个构造函数初始化的,如下所示:

public page(Context context) 
{
    super(context);
    init(context);   
}

public page(Context context, AttributeSet attrs)
{
    super(context, attrs);
    init(context);
}

public page(Context context, AttributeSet attrs, int defStyle) 
{
    super(context, attrs, defStyle);
    init(context);
}

private void init(Context context) {
    this.context = context;
    setFocusable(true);
    setFocusableInTouchMode(true);

    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(6);
    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);
}

现在,无论调用哪个构造函数,您的mPath变量都将被初始化并且不会有 NPE。

另请注意:您这样做page pageview = new page(this);没有意义,因为您的页面是从 XML 文件初始化的。

于 2013-10-31T10:39:05.567 回答
0

您只mPath在构造函数中创建字段public page(Context context),默认情况下它是null在此之前。但是,如果您使用 xml,这不是布局充气器调用的构造函数。

您需要确保您的字段是在其他构造函数中创建的,public page(Context context, AttributeSet attrs, int defStyle)并且public page(Context context, AttributeSet attrs).

您调用super这些其他构造函数。你的意思是打电话this(context)吗?

于 2013-10-31T10:40:07.213 回答