Reputation: 1751
ok,
what i am trying to do is to embed a custom view in the default layout main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.lam.customview.CustomDisplayView
android:id="@+id/custom_display_view1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/prev"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="50"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/prev" />
</LinearLayout>
</LinearLayout>
as you can see the class is called com.lam.customview.CustomDisplayView, with the id of custom_display_view1.
now in the com.lam.customview.CustomDisplayView class, i want to use another layout called custom_display_view.xml because i don't want to programmatically create controls/widgets.
custom_display_view.xml is just a button and an image, the content of which i want to change based on certain conditions:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/display_text_view1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<ImageView
android:id="@+id/display_image_view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
</LinearLayout>
i tried to do:
1)
public CustomDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
try
{
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
View.inflate(context, R.layout.custom_display_view, null);
...
but got this error, "03-08 20:33:15.711: ERROR/onCreate(10879): Binary XML file line #8: Error inflating class java.lang.reflect.Constructor ".
2)
public CustomDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
try
{
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
View.inflate(context, R.id.custom_display_view1, null);
...
but got this error, "03-08 20:28:47.401: ERROR/CustomDisplayView(10806): Resource ID #0x7f050002 type #0x12 is not valid "
also, if i do it this way, as someone has suggested, it's not clear to me how the custom_display_view.xml is associated with the custom view class.
thanks.
Upvotes: 35
Views: 65363
Reputation: 24480
This blog post helped me understand what to do immensely http://trickyandroid.com/protip-inflating-layout-for-your-custom-view/. In case the blog post disappears, here are some parts of the code:
public class Card extends RelativeLayout {
public Card(Context context) {
super(context);
init();
}
public Card(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Card(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
inflate(getContext(), R.layout.card, this);
}
}
with this layout:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/card_padding"
android:background="@color/card_background">
<ImageView
... />
<TextView
... />
</merge>
The control is included like:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin">
<com.trickyandroid.customview.app.view.Card
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/card_background"
android:padding="@dimen/card_padding"/>
</FrameLayout>
Where com.trickyandroid.customview.app.view is the namespace of class card. One thing that was new to me was the "merge" tag, which ends up being the same node as the Card tag in the containing doc.
Upvotes: 9
Reputation: 30164
When you inflate your layout, you should pass in a reference to the view instance to identify it as the root. So instead of calling:
View.inflate(context, R.layout.custom_display_view, null);
Call:
View.inflate(context, R.layout.custom_display_view, this);
See: The docs
Upvotes: 5
Reputation: 12782
Try using
context.getLayoutInflater().inflate( R.id.custom_display_view1, null );
Upvotes: 0
Reputation: 3233
Line #8 is your custom view in the first layout. Are you trying to load the wrong layout, so it's trying to load itself recursively? (I just did the same thing)
also you have:
R.layout.custom_display_view
vs.
R.id.custom_display_view1
with the 1 on the end there... which one is it?
Upvotes: 0
Reputation: 1116
I had the exact same issue, and the problem was that I was using the wrong ID... and it look's like you are too.
You should be referencing
R.layout.custom_display_view
-not-
R.id.custom_display_view
Upvotes: 70
Reputation: 10955
You can inflate the cutom_display_view into your custom class by:
public CustomDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(inflater != null){
inflater.inflate(R.layout.custom_display_view, this);
}
}
Upvotes: 7