Search code examples
androidandroid-custom-viewlayout-inflater

Inflating a custom layout view into a Layout extending class in Android


I have a custom layout defined in XML file which has a RelativeLayout root with a bunch of child view.

Now, I defined the following class:

public class MyCustomView extends RelativeLayout {

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

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

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

    private void init() {
        LayoutInflater inflater = (LayoutInflater)  getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_custom_view, this, true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        Log.d("Widget", "Width spec: " + MeasureSpec.toString(widthMeasureSpec));
        Log.d("Widget", "Height spec: " + MeasureSpec.toString(heightMeasureSpec));

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int chosenWidth = chooseDimension(widthMode, widthSize);
        int chosenHeight = chooseDimension(heightMode, heightSize);

        int chosenDimension = Math.min(chosenWidth, chosenHeight);

        setMeasuredDimension(chosenDimension, chosenDimension);
    }

    private int chooseDimension(int mode, int size) {
        if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
            return size;
        } else { 
            return getPreferredSize();
        }
    }

    private int getPreferredSize() {
        return 400;
    }
}

As you can see I'm setting the root to MyCustomView instance and the attach flag to true.

What I want to achieve is that when I will add this custom view in another layout's xml, it will instantiate the MyCustomView class which will have the layout defined in the XML.

I already tries to use <merge> tag, but that way I lose the ability to arrange my child views in the XML as I want.

I also tried to inflate the XML and add it as a view to MyCustomView, but that way I get redundant RelativeLayout.

Last thing, I added the onMeasure() just for completeness.


Solution

  • the inflation occurs but the child view are not shown

    The RelativeLayout does a bit more(a lot) than what you've done in the onMeasure layout(basically the children aren't measured at all with your code so they don't have something to show). If you extend a ViewGroup like RelativeLayout you need to let that class to do its callbacks(onMeasure, onLayout) or at least, very carefully replicate the methods and modify it like you want (if you want to see something).

    So, remove the onMeasure method to see the children or explain better why did you override it.