Search code examples
androidandroid-custom-view

Instantiate custom view programmatically the right way


I have a custom view called EventItemView which I'm using in both an XML file and in a custom adapter (which extends RecyclerView.Adapter and is used in a RecyclerView). My problem is that its appearance in my RecyclerView is weird but not in my XML file :

enter image description here

  1. Declared using XML
  2. Instantiated dynamically in my adapter

And I believe this is due to the way I instanciate views in my adapter, by doing new EventItemView(context) and not passing it additional arguments AttributeSet, int, int that are probably needed for it to render like the XML version. The problem is that I don't know how to get them in my adapter.

Here's custom view declaration :

EventItemView.java

public class EventItemView extends FrameLayout {
    public EventItemView(Context context) {
        this(context, null);
    }

    public EventItemView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public EventItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr, 0);
        init(context, attrs, defStyleAttr, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public EventItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr, defStyleRes);
    }

    protected void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        eventItem = new EventItem();

        inflate(context, R.layout.view_event_item, this);
        ButterKnife.bind(this);

        TypedArray values = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EventItemView, defStyleAttr, defStyleRes);

        try {
            setSubtitle(values.getString(R.styleable.EventItemView_subtitle));
            ...
        }
        finally {
            values.recycle();
        }
    }
}

layout/view_event_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/selector_item_event"
    android:clickable="true"
    android:gravity="center"
    android:layout_height="72dp"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:padding="16dp">

    ...

</LinearLayout>

This view is then used in 1) an activity.xml file :

<com.app.package.view.EventItemView
    android:id="@+id/current_event_view"
    android:layout_height="wrap_content"
    android:layout_width="match_parent" />

and 2) in Adapter.java :

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    EventItemView itemView = new EventItemView(context);

    return new ViewHolder(itemView);
}

How can I properly instantiate my custom view with the relevant attrs, defStyleAttr and defStyleRes constructor parameters? Or maybe the view is behaving in a weird way for a totally different reason?


Solution

  • Solved my problem by changing

    public class EventItemView extends FrameLayout
    

    to

    public class EventItemView extends RelativeLayout
    

    I just don't understand why.