Вопрос

I've created a view that I want to use like a custom widget to draw on in my layout. But on the start I have this error I can go over it. So please help!

this is my main layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <com.example.SignatureView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

this is my SignatureView class:

public class SignatureView extends View {

      private static final float STROKE_WIDTH = 5f;

      /** Need to track this so the dirty region can accommodate the stroke. **/
      private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;

      private Paint paint = new Paint();
      private Path path = new Path();

      /**
       * Optimizes painting by invalidating the smallest possible area.
       */
      private float lastTouchX;
      private float lastTouchY;
      private final RectF dirtyRect = new RectF();

      public SignatureView(Context context, AttributeSet attrs, int background) {
        super(context, attrs);
        setBackgroundResource(background);
        paint.setAntiAlias(true);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(STROKE_WIDTH);

      }

      public void setColor(int color){
          paint.setColor(color);
      }

      /**
       * Erases the signature.
       */
      public void clear() {
        path.reset();

        // Repaints the entire view.
        invalidate();
      }

      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawPath(path, paint);
      }

      @Override
      public boolean onTouchEvent(MotionEvent event) {
        float eventX = event.getX();
        float eventY = event.getY();

        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            path.moveTo(eventX, eventY);
            lastTouchX = eventX;
            lastTouchY = eventY;
            // There is no end point yet, so don't waste cycles invalidating.
            return true;

          case MotionEvent.ACTION_MOVE:
          case MotionEvent.ACTION_UP:
            // Start tracking the dirty region.
            resetDirtyRect(eventX, eventY);

            // When the hardware tracks events faster than they are delivered, the
            // event will contain a history of those skipped points.
            int historySize = event.getHistorySize();
            for (int i = 0; i < historySize; i++) {
              float historicalX = event.getHistoricalX(i);
              float historicalY = event.getHistoricalY(i);
              expandDirtyRect(historicalX, historicalY);
              path.lineTo(historicalX, historicalY);
            }

            // After replaying history, connect the line to the touch point.
            path.lineTo(eventX, eventY);
            break;

          default:
//          Log.("Ignored touch event: " + event.toString());
            return false;
        }

        // Include half the stroke width to avoid clipping.
        invalidate(
            (int) (dirtyRect.left - HALF_STROKE_WIDTH),
            (int) (dirtyRect.top - HALF_STROKE_WIDTH),
            (int) (dirtyRect.right + HALF_STROKE_WIDTH),
            (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

        lastTouchX = eventX;
        lastTouchY = eventY;

        return true;
      }

      /**
       * Called when replaying history to ensure the dirty region includes all
       * points.
       */
      private void expandDirtyRect(float historicalX, float historicalY) {
        if (historicalX < dirtyRect.left) {
          dirtyRect.left = historicalX;
        } else if (historicalX > dirtyRect.right) {
          dirtyRect.right = historicalX;
        }
        if (historicalY < dirtyRect.top) {
          dirtyRect.top = historicalY;
        } else if (historicalY > dirtyRect.bottom) {
          dirtyRect.bottom = historicalY;
        }
      }

      /**
       * Resets the dirty region when the motion event occurs.
       */
      private void resetDirtyRect(float eventX, float eventY) {

        // The lastTouchX and lastTouchY were set when the ACTION_DOWN
        // motion event occurred.
        dirtyRect.left = Math.min(lastTouchX, eventX);
        dirtyRect.right = Math.max(lastTouchX, eventX);
        dirtyRect.top = Math.min(lastTouchY, eventY);
        dirtyRect.bottom = Math.max(lastTouchY, eventY);
      }
    }

and this is what I have in my main Draw class:

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        }

and finally this is what I'm getting in the logCat

02-19 17:41:51.708: E/AndroidRuntime(7530): FATAL EXCEPTION: main
02-19 17:41:51.708: E/AndroidRuntime(7530): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.Draw}: android.view.InflateException: Binary XML file line #6: Error inflating class com.example.SignatureView
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1662)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1678)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread.access$1500(ActivityThread.java:118)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:932)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.os.Looper.loop(Looper.java:130)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread.main(ActivityThread.java:3698)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at java.lang.reflect.Method.invokeNative(Native Method)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at java.lang.reflect.Method.invoke(Method.java:507)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:875)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:633)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at dalvik.system.NativeStart.main(Native Method)
02-19 17:41:51.708: E/AndroidRuntime(7530): Caused by: android.view.InflateException: Binary XML file line #6: Error inflating class com.example.SignatureView
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.createView(LayoutInflater.java:508)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.Activity.setContentView(Activity.java:1657)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at com.example.Draw.onCreate(Draw.java:13)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1626)
02-19 17:41:51.708: E/AndroidRuntime(7530):     ... 11 more
02-19 17:41:51.708: E/AndroidRuntime(7530): Caused by: java.lang.NoSuchMethodException: SignatureView(Context,AttributeSet)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at java.lang.Class.getMatchingConstructor(Class.java:643)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at java.lang.Class.getConstructor(Class.java:472)
02-19 17:41:51.708: E/AndroidRuntime(7530):     at android.view.LayoutInflater.createView(LayoutInflater.java:480)
02-19 17:41:51.708: E/AndroidRuntime(7530):     ... 21 more
Это было полезно?

Решение

The error is pretty self explainatory:

Caused by: java.lang.NoSuchMethodException: SignatureView(Context,AttributeSet)

You don't have a Contructor that takes only a Context, and an AttributeSet. Add that constructor to your SignatureView class, like this:

public SignatureView(Context c, AttributeSet as){
    super(c, as);
}

Другие советы

You need a constructor that takes in a Context and a AttributeSet. You added a 3rd parameter to yours. That won't work when inflating through xml, it requires that exact signature to work.

Also, it would confuse things even more because if a default style is applied then the xml inflater looks for a 3 parameter version (the third is the theme's resource id), which would call your current 3 parameter method by mistake. The end result would be you trying to set the backgroudn resource of a random theme id, and I don't know what would result but my guess is a crash.

02-19 17:41:51.708: E/AndroidRuntime(7530): Caused by: java.lang.NoSuchMethodException: ***SignatureView(Context,AttributeSet)***

Looks like you are missing a constructor? Try adding a constructor for SignatureView(Context,AttributeSet) and see how that works.

instead of passing int background in te constructor, try passing it as an xml attribute. That way you are still replying on the default constructors and it gives you the flexibility to set the background from the xml.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top