I have a huge layout file called visit_registration.xml. In order to support different screen sizes, I've duplicated the file and created the files layout-sw600dp/visit_registration.xml and layout-sw720dp/visit_registration.xml.
There is a single small difference between the layouts:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="#dimen/app_margin"
android:paddingRight="#dimen/app_margin">
<TextView
android:id="#+id/visitRegistrationTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/visit_registration" />
<!-- TONS of UI elements here! -->
</LinearLayout>
The original layout file (above) shows the TextView with the id "visitRegistrationTextView".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="#dimen/app_margin"
android:paddingRight="#dimen/app_margin">
<TextView
android:id="#+id/visitRegistrationTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="#string/visit_registration" />
<!-- TONS of UI elements here! -->
</LinearLayout>
Each copy uses a different visibility. The example above uses "gone". Sometimes the changes are different, but small, like a UI element moved to another place in the layout. The rest of the code remains the same.
The main question is about layout duplication. I don't want to maintain three different layouts because of the classical duplication problems like "What would happen if I need to change a common UI element present in three files and forget to change it in a single place?"
Is it possible to have a single "base layout" with the common UI elements and include the small layout changes on it accordingly with the current screen size ?
Try to make resources file eg. values-sw600dp/strings.xml, values-sw720dp/strings.xml with
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="visibility">gone</string>
</resources>
or
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="visibility">visible</string>
</resources>
and your layout file (only one):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="#dimen/app_margin"
android:paddingRight="#dimen/app_margin">
<TextView
android:id="#+id/visitRegistrationTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="#string/visibility"
android:text="#string/visit_registration" />
<!-- TONS of UI elements here! -->
</LinearLayout>
You can define a Layout with a single text view, one for each of your screen size. Then you create a general layout in which you can include the previous.
Let's call it text_layout, one for each screen size.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/visitRegistrationTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="#string/visit_registration" />
</LinearLayout>
Then you create the main layout, one for all screen size.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="#dimen/app_margin"
android:paddingRight="#dimen/app_margin">
<include layout="#layout/text_layout"/>
<!-- TONS of UI elements here! -->
</LinearLayout>
That's it, less duplication, more maintenance.
Related
I want to dynamically add a custom styles to textviews in code. I can use the following workaround to do this when there is only textview in question:
android set style in code
However, if I try this method and create a template.xml file with 2 textview, each with a different style applied, this no longer works.
i.e. my template file will look something like this instead:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="This is a template"
style="#style/my_style" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="This is another template"
style="#style/my_style2" />
</LinearLayout>
How do I extend this solution so it works with more than one textview and more than one style?
I am thinking to create a layout whose height is much more than the screen height. OK say, the parent layout is LinearLayout and it is set to provide a vertical scrollbar automatically.
Inside the parent layout, there are many controls (listview, gridview, listboxes, editboxes etc). To make it easier for design, can I put listview in one xml, gridview in one xml, listbox in one, editbox in one etc and then later use some defined function to concatenate and allocate them all in the parent layout ?
If this is not possible, how can I design a layout that has many controls allocated that design screen can't fit at design time ?
xml_common.xml
code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/common_topheader_width"
android:background="#drawable/topheaderfor9patch" >
<ImageView
android:id="#+id/xml_common_header_imageLogotop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="2dp"
android:layout_marginRight="#dimen/common_left_right_margin"
android:src="#drawable/qarrow" />
</RelativeLayout>
///////////////////////////////////////////
Main_view.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/mainbg"
android:orientation="vertical" >
<include layout="#layout/xml_common" />
</LinearLayout>
you can set different images as per your choice set in runtime of common view.
I am new to Android and am reading Wrox's professional android 4 app dev book. In chapter 4 of the book it explains how to modify the existing text view. The problem i am facing is that the listview in my app hides the edit text box. Its hidden (can be seen in the background) but still works that is more stuff can be added to the list through it. Below is the code for my main activity xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/addItemContentDescription"
android:hint="#string/addItemHint"
/>
<ListView
android:id="#+id/myListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
and my todolist_item xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.wroxexample.ToDoListItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:scrollbars="vertical"
android:textColor="#color/notepad_text"
android:fadingEdge="vertical"
/>
The first option you have is to use a LinearLayout instead of a RelativeLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/addItemContentDescription"
android:hint="#string/addItemHint"
/>
<ListView
android:id="#+id/myListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
A RelativeLayout will allow you to position the elements relatively to the others.
On the other hand a LinearLayout will position the elements one below the other in the order they appear in the xml file.
The second option you have is to keep your RelativeLayout and just add the following tag to your ListView:
android:layout_below="#id/myEditText"
This will position the ListView below the EditText.
Try this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/addItemContentDescription"
android:hint="#string/addItemHint"
android:layout_alignParentTop="true"
/>
<ListView
android:id="#+id/myListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/myEditText"/>
</RelativeLayout>
Use a LinearLayout and the property android:layout_weight
http://developer.android.com/reference/android/widget/LinearLayout.LayoutParams.html
Try something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/myListView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:entries="#array/testea"
android:layout_height="wrap_content"/>
<EditText
android:id="#+id/myEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/addItemContentDescription"
android:hint="#string/addItemHint"
/>
</LinearLayout>
This way ListView will grow to fill only the unused space.
Timothee got there before me but ill just add a little more.
you can, as he says, use a linear layout, or as user1387035 says, you can set the listview to be below the editText.
Relative Layout means "i want to lay things out relatively" and if you dont tell things where to go they will just float to where the 'gravity' is pulling them. The default gravity is top - so I'm guessing your items both ended up bunched at the top left?
As a rule of thumb - do you want your items to come one after another, bunched together (either horizontally or vertically)? if yes then use linear layout. If you want them to be pushed in different directions, use a relative layout. There are some exceptions, normally involving the "weight" attribute you can set in a linearlayout. (here's one I've just had to use: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/)
If you have a Relative layout and are just using the layout_below/above attributes, without any 'alignParentBottom' or other thing set, then you probably just want a linearlayout
In your case I would say it sounds like you want Timothee's solution. If you want a little separation between the objects, you can use padding/margins to space them a little.
As for gravities, here is a useful blog entry that helped me get my head around LinearLayout's gravities (as well as generally): http://sandipchitale.blogspot.co.uk/2010/05/linearlayout-gravity-and-layoutgravity.html
I need your advice regarding my design and if you have a better idea (or you agree with me) that it is good. for some reason I have a feeling it is a "stone age programming style" but lets see.
Basically I have my xml relative layout. In the center (vertical and horizenatlly). I want to display "either" 3 buttons OR 3 texts depending on some user input. So what I did is the following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
android:clipToPadding="false" >
<RelativeLayout android:id="#+id/Buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<Button1 .../>
<Button2 .../>
<Button3 .../>
</RelativeLayout>
<RelativeLayout android:id="#+id/Texts"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<TextView1 .../>
<TextView2.../>
<TextView3.../>
</RelativeLayout>
</RelativeLayout>
Depending on the user input in the code I set visibility to either Visible or Invisible
Is this alright? and if not what do you suggest?
What you need is View.GONE, and View.VISIBLE.
With View.GONE - the layout doesn't occupy any space (almost as if it didn't exist at all). If you use View.INVISIBLE, to the user, the view (buttons, or text in your case) will not be visible, but they will still be there on the screen, thus shifting the other view (buttons, or text) up or down (the view won't be in dead center).
TIP: You can use 'android:layout_centerInParent' instead of 'android:layout_centerHorizontal' and 'android:layout_centerVertical'.
In my opinion, what you have done may be primitive, but it is simple, which is good :) But if you still want some options and make life complicated, then
Put each of the blocks in a separate xml and use include.
Make 2 views and then use ViewFlipper to flip them based on user requirements.
But for the simple requirement that you have, I think u r doing fine.
The include option would work something like this,
layout_1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Buttons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<Button1 .../>
<Button2 .../>
<Button3 .../>
</RelativeLayout>
layout_2.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Texts"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<TextView1 .../>
<TextView2.../>
<TextView3.../>
</RelativeLayout>
your main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clipChildren="false"
android:clipToPadding="false" >
<include layout="#layout/layout_1" />
<include layout="#layout/layout_2" />
</RelativeLayout>
The include helps you in making reusable layouts and also helps in keeping your xml files grow out of proportions, specially when you have complicated UIs.
First option is:
You can add all the three buttons or textviews in Linearlayout and center it in parent by using android:layout_centerInParent.
Second option is:
You can center the middle button out of all the three buttons and adjust the other two buttons with respective to the middle button. Same way we should also repeat this for textviews. In this option, we should make all the three views visibility to View.GONE explicitly.
I have made myself a custom LinearLayout by the name of com.theflyingnerd.DroidMe.DiscreteNumericalRangeSelectorWidget that hosts a couple of spinner widgets. This custom LinearLayout inflates the following XML layout (You might not need to look at this too carefully but it's here for completeness):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- Min value Spinner -->
<Spinner
android:id="#+id/discrete_numerical_range_selector_min_value_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_weight="1" />
<TextView
android:id="#+id/to_text"
android:text="to"
android:textSize="14sp"
android:paddingLeft="10sp"
android:paddingRight="10sp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_weight="0">
</TextView>
<!-- Max value Spinner -->
<Spinner
android:id="#+id/discrete_numerical_range_selector_max_value_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_weight="1" />
I have placed one such object in the layout for one of my activities like so:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<include layout="#layout/search_form_section_generic_top"/>
<include layout="#layout/search_form_section_car_specific"/>
<com.theflyingnerd.DroidMe.DiscreteNumericalRangeSelectorWidget/>
<include layout="#layout/search_form_section_advanced_options" />
</LinearLayout>
The problem is that my app force closes immediately upon startup. I've checked by putting breakpoints in my custom LinearLayout that none of my custom code is even being run yet. Furthermore, if I copy-paste the layout code for my compound widget in place everything works, which indicates to me that I probably haven't left any important XML attributes out. What could be going wrong?
I fixed it by making the LinearLayout XML element in the widget layout into a merge instead, and moved all of the layout parameters out of the widget XML file and into the activity XML itself, thus replacing
<com.theflyingnerd.DroidMe.DiscreteNumericalRangeSelectorWidget/>
with
<com.theflyingnerd.DroidMe.DiscreteNumericalRangeSelectorWidget
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
If someone could tell me why this worked, it might help me and others doing it again, and you can take credit.
because you must specify the width and height of every view you use in you xml?