Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom View children are null after inflating the view in Android

I am working on an Android app. I have a custom view and layout as follows:

<com.hello.view.card.inner.SimpleCardView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/card_simple_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/simple_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

</com.hello.view.card.inner.SimpleCardView>

And this is the Java class:

public class SimpleCardView extends LinearLayout {
    protected SimpleCard card = null;
    protected TextView textView;

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

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

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

    protected void init(Context context) {
        textView = (TextView)findViewById(R.id.simple_label);
    }

    public void setCard(SimpleCard card) {
        this.card = card;
        textView.setText(card.getMessage());        
    }
}

And this is how I am inflating the view (I tried both following calls):

SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, null);
//SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, parent);
view.setCard(card);

The problem I am having is when view.setCard(card) is called, I see that textView is null, even though I am expecting it to be set in the init(..) method. Can anyone tell me what it not being set correctly? Thanks in advance.

like image 298
happyhuman Avatar asked Jun 28 '14 01:06

happyhuman


People also ask

What are custom views in Android?

Your custom view can also extend View directly, or you can save time by extending one of the existing view subclasses, such as Button . To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a Context and an AttributeSet object as parameters.

What is inflate method in Android?

In this context, Inflate means reading a layout XML (often given as parameter) to translate them in Java code. This process happens: in an activity (the main process) or a fragment.

What are the options present while creating custom View?

Some examples of default views present in the Android Framework are EditText, TextView, Button, CheckBox, RadioButton, etc. ViewGroup is a special view that can contain other views (called children). We can create custom views and use them in our Application.

Why LayoutInflater is used in Android?

LayoutInflater is used to create a new View (or Layout ) object from one of your xml layouts. findViewById just gives you a reference to a view than has already been created.


2 Answers

Thank you for your answers. It turns out init(context) should not be called in the constructor. The right place to call it is in onFinishInflate(). The following change helped fix it:

public class SimpleCardView extends LinearLayout {
    protected SimpleCard card = null;
    protected TextView textView;

    public SimpleCardView(Context context) {
        super(context);     
    }

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

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

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init(getContext());
    }

    protected void init(Context context) {
        textView = (TextView)findViewById(R.id.simple_label);
    }

    public void setCard(SimpleCard card) {
        this.card = card;
        textView.setText(card.getMessage());        
    }
}
like image 125
happyhuman Avatar answered Oct 18 '22 22:10

happyhuman


Instead of using root element

com.hello.view.card.inner.SimpleCardView

try using

<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:id="@+id/simple_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</merge>

then, in your init method

LayoutInflater.from(context).inflate(R.layout.card_simple, this);
setOrientation(LinearLayout.VERTICAL);
textView = (TextView)findViewById(R.id.simple_label);

When you use the view in other layouts, that's where you will want to put

<com.hello.view.card.inner.SimpleCardView />

and any properties that it needs, its id, its width/height, etc.

like image 1
ootinii Avatar answered Oct 18 '22 23:10

ootinii