1

I created a Custom View class that takes a path, then fills it white and colors its edge red:

StrokeFill.java:

package com.kf.pathshape;
...

public class StrokeFill extends View{
private Path shapePath;

public StrokeFill(Context context, Path path) {
    super(context);
    this.shapePath = path;

    // TODO Auto-generated constructor stub
}

public StrokeFill(Context context, AttributeSet attrs, Path shapePath) {
    super(context, attrs);
    this.shapePath = shapePath;
}

protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    //canvas.drawColor(Color.BLACK);
    super.onDraw(canvas);

    //Sets paints and draws the shapes
    Paint fillPaint = new Paint();
    fillPaint.setColor(android.graphics.Color.WHITE);
    fillPaint.setStyle(Paint.Style.FILL);
    fillPaint.setStrokeWidth(0);
    Paint strokePaint = new Paint();
    strokePaint.setColor(android.graphics.Color.RED);
    strokePaint.setStyle(Paint.Style.STROKE);
    strokePaint.setStrokeWidth(2);

    canvas.drawPath(shapePath, fillPaint);
    canvas.drawPath(shapePath, strokePaint);
}
}

My layout XML (main.xml) is very simple:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.kf.pathshape.StrokeFill
    android:id="@+id/pathshape"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Activity:

setContentView(R.layout.main);
shapeView = (StrokeFill) findViewById(R.id.pathshape);
shapeView = new StrokeFill(this, testpath);

testpath is a valid path. It's giving me errors even if I comment out the lines defining "shapeView". Logcat:

07-11 01:50:17.150: E/AndroidRuntime(24321): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.kf.pathshape/com.kf.pathshape.PathshapeActivity}: android.view.InflateException: Binary XML file line #6: Error inflating class com.kf.pathshape.StrokeFill
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1651)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.os.Handler.dispatchMessage(Handler.java:99)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.os.Looper.loop(Looper.java:130)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread.main(ActivityThread.java:3691)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at java.lang.reflect.Method.invokeNative(Native Method)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at java.lang.reflect.Method.invoke(Method.java:507)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at dalvik.system.NativeStart.main(Native Method)
07-11 01:50:17.150: E/AndroidRuntime(24321): Caused by: android.view.InflateException: Binary XML file line #6: Error inflating class com.kf.pathshape.StrokeFill
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.createView(LayoutInflater.java:508)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:234)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.Activity.setContentView(Activity.java:1679)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at com.kf.pathshape.PathshapeActivity.onCreate(PathshapeActivity.java:73)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1050)
07-11 01:50:17.150: E/AndroidRuntime(24321):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615)
07-11 01:50:17.150: E/AndroidRuntime(24321):    ... 11 more
07-11 01:50:17.150: E/AndroidRuntime(24321): Caused by: java.lang.NoSuchMethodException: StrokeFill(Context,AttributeSet)

I searched through the forum but didn't find what I need. I already defined the constructor taking context and attrs. What am I missing here?

tangfucius
  • 444
  • 7
  • 14

3 Answers3

2

As you are extending a view, you need to implements 3 constructors:

public class StrokeFill extends View{
    private Path mShapePath;

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

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

    public StrokeFill(Context context, AttributeSet attrs, int defstyle) {
        super(context, attrs, defstyle);
        init();
    }

    private void init(){
        //some code... or not =)
    }

    public void setPath(Path path){
        mShapePath = path;
    }
    /* rest of your code */
}

Then in your activity:

shapeView = (StrokeFill) findViewById(R.id.pathshape);
shapeView.setPath(yourPath);

Hope this helps you

AMerle
  • 4,354
  • 1
  • 28
  • 43
0

no need to create it again

shapeView = new StrokeFill(this, testpath);

modify like this

setContentView(R.layout.main);
shapeView = (StrokeFill) findViewById(R.id.pathshape);
RajaReddy PolamReddy
  • 22,428
  • 19
  • 115
  • 166
  • But both shapeView and testpath come from the Activity, so I need to instantiate shapeView somehow. Plus even if I don't define shapeView, setContentView is already giving me an error. If I have StrokeFill in the XML, does it mean it has to be created in onCreate? – tangfucius Jul 10 '12 at 18:45
0

When You create your custom view from xml android calls StrokeFill(Context,AttributeSet) constructor. You have to create that constructor if you want to inflate your view from xml. You can also create your view in code, then delete it from xml, in this case you don't need StrokeFill(Context,AttributeSet) constructor.

For example:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>

Activity:

setContentView(R.layout.main);
LinearLayout v = (LinearLayout)findViewById(R.id.myLayout);
shapeView = new StrokeFill(this, testpath);
v.addView(shapeView);
Leszek
  • 6,568
  • 3
  • 42
  • 53
  • This works, thanks. I am wondering if there is a way where I can directly use StrokeFill in XML directly instead of LinearLayout though, as this feels more like a workaround. – tangfucius Jul 10 '12 at 19:25