Search code examples
androidandroid-layoutandroid-relativelayout

Trying to add a RelativeLayout programmatically but seems like it's off screen or too big


I have this xml for a screen where I at the top I will have a spinner with a list of search conditions, a button next to it (this is what I call control area) and each time is pressed, a group of views will be added for an extra search. The group comprises of another spinner where the user will specify the operator (AND, OR), a text box with the title of the search condition and an edit text where the user will put the input (this is what I call filter area). This will be used to build a search query for a database search later on.

The xml below is what I have so far with a group hardcoded so I can show what I add programatically.

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true"> <!--IMPORTANT otherwise backgrnd img. will not fill the whole screen -->

    <RelativeLayout
        android:id="@+id/searchLayout"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:context="com.kadis.materialref.Search">

        <Spinner
            android:id="@+id/attributeSelector"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/controlElementHeight"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"/>

        <Button
            android:id="@+id/addAttributeButton"
            android:layout_width="@dimen/controlElementHeight"
            android:layout_height="@dimen/controlElementHeight"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_toRightOf="@+id/attributeSelector"
            android:layout_toEndOf="@+id/attributeSelector"
            android:onClick="addSearchCondition"
            android:text="@string/addSearchAttributeString"/>

        <View
            android:id="@+id/dividerControl1"
            style="@style/Divider"
            android:layout_below="@+id/attributeSelector"/>

        <View
            android:id="@+id/dividerControl2"
            style="@style/Divider"
            android:layout_below="@+id/dividerControl1"/>

        <RelativeLayout
            android:layout_width="match_parent"
            android:id="@+id/FilterArea0"
            android:layout_height="@dimen/controlElementHeight"
            android:layout_below="@+id/dividerControl2"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true">

                <Spinner
                    android:id="@+id/filterOperator0"
                    android:layout_width="@dimen/controlElementHeight"
                    android:layout_height="match_parent"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true"/>

                <TextView
                    style="@style/SearchFormTitle"
                    android:id="@+id/filterTitle0"
                    android:text="@string/column1"
                    android:layout_toRightOf="@id/filterOperator0"
                    android:layout_toEndOf="@id/filterOperator0"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"/>

                <EditText
                    style="@style/SearchFormFieldText"
                    android:layout_below="@+id/filterTitle0"
                    android:layout_toRightOf="@id/filterOperator0"
                    android:layout_toEndOf="@id/filterOperator0"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"/>

        </RelativeLayout>
    </RelativeLayout>
</ScrollView>

The screen is something like this enter image description here

The function called when the button is pressed to add another filter area is the following. The function generateViewId is the same as after API 17, I just added it in the class for API < 17.

public void addSearchCondition(View view)
{
    // Get selection from spinner in control area; the attribute to add in the search conditions.
    Spinner attributeSelector = (Spinner) findViewById(R.id.attributeSelector);
    String attributeSelected = attributeSelector.getSelectedItem().toString();

    // Get layout where I will add stuff.
    RelativeLayout searchLayout = (RelativeLayout) findViewById(R.id.searchLayout);

    // Get last id of the last child so we know under which to add the new layout
    int bottomChildId = searchLayout.getChildAt(searchLayout.getChildCount()-1).getId();

    //
    // New Relative Layout to be added.
    //
    RelativeLayout filterLayout = new RelativeLayout(this);
    filterLayout.setId(generateViewId());
    // Define width and height parameters.
    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            R.dimen.controlElementHeight);
    // Define position
    rlp.addRule(RelativeLayout.BELOW, bottomChildId);
    rlp.addRule(RelativeLayout.ALIGN_PARENT_START);
    rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    filterLayout.setLayoutParams(rlp);

    //
    // Add the operator spinner.
    //
    Spinner operatorSpinner = new Spinner(this);
    operatorSpinner.setId(Search.generateViewId());
    // Get the options for the spinner.
    String[] operators = getResources().getStringArray(R.array.operators);
    // Add items on the spinner.
    ArrayAdapter<String> spinnerArrayAdapter =
            new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, operators);
    spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    operatorSpinner.setAdapter(spinnerArrayAdapter);
    // Define width and height parameters.
    RelativeLayout.LayoutParams rlpSp = new RelativeLayout.LayoutParams(
            R.dimen.controlElementHeight,
            R.dimen.controlElementHeight);
    // Define position
    rlpSp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    rlpSp.addRule(RelativeLayout.ALIGN_PARENT_START);
    // Set layout parameters
    operatorSpinner.setLayoutParams(rlpSp);
    // Add spinner on the layout
    filterLayout.addView(operatorSpinner);

    //
    // Add a text view as the title
    //
    final TextView tv = (TextView)getLayoutInflater().inflate(R.layout.search_attribute_title, null);
    tv.setId(Search.generateViewId());
    // Set text to display
    tv.setText(attributeSelected);
    // Define width and height parameters.
    RelativeLayout.LayoutParams rlpTV = new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT);
    // Define position
    rlpTV.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    rlpTV.addRule(RelativeLayout.ALIGN_PARENT_END);
    rlpTV.addRule(RelativeLayout.RIGHT_OF, operatorSpinner.getId());
    rlpTV.addRule(RelativeLayout.END_OF, operatorSpinner.getId());
    // Set layout parameters
    tv.setLayoutParams(rlpTV);
    // Add spinner on the layout
    filterLayout.addView(tv);

    // Add an Edit Text as the placeholder for the user input
    final EditText et = (EditText)getLayoutInflater().inflate(R.layout.search_attribute_input, null);
    et.setId(Search.generateViewId());
    // Set text to display
    et.setText(attributeSelected);
    // Define width and height parameters.
    RelativeLayout.LayoutParams rlpET = new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT);
    // Define position
    rlpET.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    rlpET.addRule(RelativeLayout.ALIGN_PARENT_END);
    rlpET.addRule(RelativeLayout.RIGHT_OF, operatorSpinner.getId());
    rlpET.addRule(RelativeLayout.END_OF, operatorSpinner.getId());
    rlpET.addRule(RelativeLayout.BELOW, tv.getId());
    // Set layout parameters
    et.setLayoutParams(rlpET);
    // Add spinner on the layout
    filterLayout.addView(et);

    // Adding the whole filter layout to the search layout (whole screen)
    searchLayout.addView(filterLayout);
}

I am not sure if the problem might be the LayoutParameters for textView and editText but to add the rules I have to have the LayoutParameters and I have to pass some arguments. Maybe I should pass the wrap_content since in the xml hardcoded I have I don't pass them?

I have debugged and the Layout is created and added. The ids are generated and when I press on the screen is like the white space below the hardcoded xml reacts like it's the spinner with the operator choices. So I am guessing something goes wrong with the dimensions maybe? After pressing the button and the filter area is "added" If I press the white area where it was supposed to be the spinner of the are (with the operators) is triggered

enter image description here

The dimensions I have so far are the following defined just in case

    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

    <!-- Fonts sizes -->
    <dimen name="titleBig">48sp</dimen>
    <dimen name="titleMed">36sp</dimen>
    <dimen name="titleSmall">24sp</dimen>
    <dimen name="searchTitle">10sp</dimen>
    <dimen name="searchField">15sp</dimen>

    <!-- Padding -->
    <dimen name="titlePadding">20dp</dimen>

    <!-- Element heights -->
    <dimen name="controlElementHeight">40dp</dimen>

Also, when I choose another choice in the spinner with the attributes (the search filters) the button disappears, I think gets shoved off screen to the right? How can I fix that?


Solution

  • So in the code where you create the LayoutParams for the RelativeLayout:

    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            R.dimen.controlElementHeight);
    

    You are not actually passing the dimension as the height, but rather the unique identifier of that dimension resource. You can actually see the value if you open R.java for your project and search for controlElementHeight. So you are probably passing a huge integer value in as the height as the IDs are values like 0x7f0a0047.

    What you really want is something like this:

    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.MATCH_PARENT,
                    getResources().getDimensionPixelSize( R.dimen.controlElementHeight) );
    

    This will request the actual value of the defined dimension resource, scaled to the device's screen density.