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
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
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?
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.