I want to define a custom widget, which contains some other controls and has own logic. I want to use XML file to define the UI, and the java code to define the logic. But I don’t know how to do it.
I followed this article Building mix-up custom Android component/widget using Java class and XML layout, but don’t a working one. Following is my code.
XML:
<com.example.MyView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="custom button 1"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="custom button 2"/>
</com.example.MyView>
Java code:
public class MyView extends LinearLayout {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
LayoutInflater.from(getContext()).inflate(R.layout.test_view, this); // **line 32**
}
}
And in the main layout, I invoke it like this:
<com.example.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.example.MyView>
Unfortunately, it throws an exception when running:
05-26 14:11:25.199: ERROR/AndroidRuntime(15799): FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.MyActivity}: android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1651)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
at android.app.ActivityThread.access$1500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3687)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>
at android.view.LayoutInflater.createView(LayoutInflater.java:518)
at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at com.example.MyView.onFinishInflate(MyView.java:32)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:631)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at com.example.MyView.onFinishInflate(MyView.java:32)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:631)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at com.example.MyView.onFinishInflate(MyView.java:32)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:631)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at com.example.MyView.onFinishInflate(MyView.java:32)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:631)
at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
....
You can’t declare the custom view like you did. If you use your custom view in the main layout the
onFinishInflatemethod will be called to construct the custom view and in that method the layout above will be called. The problem is that you already have a custom view reference in that layout(which will be inflated again when theLayoutInflaterencounters the custom view tag) so you’ll get in a circular inflating situation.You probably want something like this:
so when your custom view will be inflated from a layout file it will append the content of the xml layout above. The
onFinishInflatemethod will remain the same:Edit: It appears that inflating a content layout in the
onFinishInflatemethod triggers the method again(at least on older versions). You could either modify the layout to use aLinearLayoutlike this:and then in the
onFinishInflatemethod:This will introduce another useless element in the layout hierarchy so you might simply inflate the layout with
mergetag in the constructors of the custom view: