How do I automatically `layout_below` sequential controls in an Android layout? - android

I often seem to make Android layouts that have a series of controls that are meant to sit one below the other. For example
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/a"/>
<TextView
android:id="#+id/b"
android:layout_below="#+id/a"/>
<TextView
android:id="#+id/c"
android:layout_below="#+id/b"/>
<TextView
android:id="#+id/d"
android:layout_below="#+id/c"/>
<TextView
android:id="#+id/e"
android:layout_below="#+id/d"/>
</RelativeLayout>
The android:layout_below attributes are necessary: without them the TextViews all bunch up together in the same place.
They are also, usually, redundant and a general source of bugs and tedium. As control IDs change, as controls are added and removed, all of these strings must be edited to match up properly. To illustrate the general redundancy of this scheme, note how it promotes this sort of spaghetti:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/e"
android:layout_below="#+id/d"/>
<TextView
android:id="#+id/b"
android:layout_below="#+id/a"/>
<TextView
android:id="#+id/d"
android:layout_below="#+id/c"/>
<TextView
android:id="#+id/a"/>
<TextView
android:id="#+id/c"
android:layout_below="#+id/b"/>
</RelativeLayout>
I can see how explicit layout_below directives (and friends such as layout_above) could be useful in some circumstances. But is there no way of configuring the layout (e.g. the RelativeLayout) to simply assume that the each control in the series that it contains should automatically layout_below the preceding control?

LinearLayout might be more suitable for this kind of UI structure. It does exactly what you need, and it does it automatically for you. All that you really have to specify is its android:orientation which can be either vertical or horizontal.
More information on LinearLayout can be found here.
All children of a LinearLayout
are stacked one after the other, so a vertical list will only have one
child per row, no matter how wide they are, and a horizontal list will
only be one row high (the height of the tallest child, plus padding).
Here's a quick example:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/text_view_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hey, I'm TextView A!"/>
<TextView
android:id="#+id/text_view_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hey, I'm TextView B!"/>
<TextView
android:id="#+id/text_view_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hey, I'm TextView C!"/>
<!-- ..and so on. -->
</LinearLayout>

What you are looking for is LinearLayout with a vertical orientation.

Related

Relativelayout position view between two views

so I'm currently working on an app on Android, and I got stuck on a specific problem regarding the RelativeLayout, which I can't find a way to solve.
I have in the layout three views as follows: TextView, Textview and ImageView (laid horizontally), here is a screenshot of the ios counterpart:
the Textview at the middle should stick to the first one, until he gets to the Imageview, when he does, he keeps his minimum size (wrap content), while the first Textview truncate.
On IOS I setted priorities to the constraint to accomplish this, but I can't figure out how to solve this on Android.
Here what I tried:
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#drawable/daily_movie_title_box">
<TextView
android:id="#+id/daily_header_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="New Text aawi oa ioawfwi"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#color/white"
android:lines="1"
android:singleLine="true"
android:layout_alignParentStart="true"
/>
<TextView
android:id="#+id/duration_text"
android:text="138 mins"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:textSize="13sp"
android:textColor="#color/white"
android:lines="1"
android:layout_alignBaseline="#id/daily_header_textview"
android:layout_toStartOf="#+id/certification_icon"
android:layout_toEndOf="#id/daily_header_textview"
/>
<ImageView
android:id="#id/certification_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:src="#drawable/uk12a"
android:layout_alignBottom="#id/daily_header_textview"
app:layout_aspectRatio="100%"/>
</android.support.percent.PercentRelativeLayout>
Which resulted in this (which is what I want):
But when I increase the first Textview text it's not behaving as I desire...
Is it possible to achieve the behaviour I want in Android (keep the middle Textview wrap content, and truncate the first one if needed)?
I will post an update if I find a solution eventually, just wanted to see if anyone can find an easy way to achieve this behaviour, as I suspect there is.
Thanks.
From my understanding, you want the first TextView to be as large as possible, without adding space after the text if the text is too small. The second TextView should only wrap_content, but it should fill the rest of the parent layout when the row doesn't. The ImageView is set to wrap_content.
I tested it with this layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="0"
android:stretchColumns="1">
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="Shrinking text dddddddddddddddddddddd"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Midle column"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#mipmap/ic_launcher"/>
</TableRow>
</TableLayout>
</LinearLayout>
The only problem is that if the second column has a incredibly large text, it will push the other views out of the parent. But in your case, I don't think that will be a problem. Otherwise, I think it does the job.
These are some suggested solutions:
You can use LinearLayout with horizontal orientation and weight for each component (TextViews and ImageView).
You can set the minimum and maximum text length for the second TextView.
But i prefer to apply the first solution. You can assign a weight for each component ( amount of space on the screen ) using:
android:layout_height

Gravity of two side-by-side TextViews

I'm trying to have two TextViews side-by-side, and I want one to be touching the right-side of the screen and the other, the left-side. I don't want to define the widths using numbers because screens of different sizes would behave differently. So I'm trying to use layout_gravity, which is not working for some reason.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:layout_gravity="left"
android:text="rrr"
android:textColor="#color/secondTextColor"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textSize="16dp"
android:text="sss"
android:textColor="#color/secondTextColor" />
</LinearLayout>
Can anyone tell me why? Thanks!
You can create one LinearLayout for each TextView as follows :
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="start">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:text="rrr"
android:textColor="#f2f2"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:text="sss"
android:textColor="#f3f3" />
</LinearLayout>
</LinearLayout>
And the important thing is that in your first LinearLayout you put android:gravity="start" and in your second one android:gravity="end", then it will work :)
Use end instead of right to ensure correct behavior in right-to-left locales.
Why is "end" better than "right"?
Using Gravity#LEFT and Gravity#RIGHT can lead to problems when a layout is rendered in locales where text flows from right to left.
Use Gravity#START and Gravity#END instead. Similarly, in XML gravity and layout_gravity attributes, use start rather than left.
For XML attributes such as paddingLeft and layout_marginLeft, use paddingStart and layout_marginStart.
NOTE: If your minSdkVersion is less than 17, you should add both the older left/right attributes as well as the new start/right attributes. On older platforms, where RTL is not supported and the start/right attributes are unknown and therefore ignored, you need the older left/right attributes. There is a separate lint check which catches that type of error.
(Note: For Gravity#LEFT and Gravity#START, you can use these constants even when targeting older platforms, because the start bitmask is a superset of the left bitmask. Therefore, you can use gravity="start" rather than gravity="left|start".)
You can try with android:layout_weight & android:gravity .
Read What does android:layout_weight mean & Layout Weight
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:weightSum="1" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:gravity="left"
android:text="Intellij" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:gravity="right" // You can add end instead of right
android:text="Amiya" />
</LinearLayout>
You could use android:layout_weight="1" on TextView's and 0dp for width.

How to Align Controls to each Other on Eclipse

I'm new to Eclipse and Android and I need to align controls to each other.
In Visual Studio, I can easily align controls and distribute spaces between them. How can I do this in Eclipse?
I got this xml. Just dragged and dropped them to layout. There must be an easy way to align and disstribute. Especially distrubute.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.sbs.MainActivity" >
<!-- Ders adları -->
<TextView
android:id="#+id/lblTurkce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="42dp"
android:layout_marginTop="78dp"
android:text="#string/Turkce" />
<TextView
android:id="#+id/lblDil"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/lblTarih"
android:layout_alignParentBottom="true"
android:layout_marginBottom="166dp"
android:text="#string/ingilizce" />
<TextView
android:id="#+id/lblMatematik"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/lblTurkce"
android:layout_below="#+id/lblTurkce"
android:layout_marginTop="15dp"
android:text="#string/Matematik" />
<TextView
android:id="#+id/lblFen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/lblMatematik"
android:layout_below="#+id/lblMatematik"
android:layout_marginTop="18dp"
android:text="#string/FenveTeknoloji" />
<TextView
android:id="#+id/lblTarih"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/lblFen"
android:layout_below="#+id/lblFen"
android:layout_marginTop="24dp"
android:text="#string/tarih" />
<TextView
android:id="#+id/lblDin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/lblTarih"
android:layout_centerVertical="true"
android:text="#string/din" />
So, this is what a friend did and than I started doing too and I can align stuff pretty well.
So ,what you have to do ,is to work with LinearLayouts and their property Orientation property.
Now I don't exactly know what you want to do but I can give you a little example so that you ,hopefully understand what I am writing here.
Let's say you got 3 TextViews and you want to arrange them like two on top of the screen and the last one, you want to be below the two already aligned button.It would look pretty much like a pyramid but with the top being pointed down.
You would do this like that: The first two textViews will be put in a LinearLayout with the Orientation being set to Horizontal (so that the second textView will be in the right of the first textView but on the same line (so aligned to the first textView's right).
Now, the other one won't be necessary to be contained by a LinearLayout ,BUT, the first LinearLayout (with the first and second TextView) and the third textView have to be contained by a LinearLayout that has the Orientation being Vertical.This way the third textView is below the LinearLayout containing the two textViews.
Let me know if you need more explication.
RelativeLayout provides various alignment attributes you can use. For example, if you want to line up the left edges of two different TextViews in your RelativeLayout, you can use the layout_alignLeft attribute like so:
<?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="match_parent">
<TextView
android:id="#+id/textViewOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="Text One"/>
<TextView
android:id="#+id/textViewTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/textViewOne"
android:layout_alignLeft="#id/textViewOne"
android:text="Text Two"/>
</RelativeLayout>
Note that I forced the first TextView to have a left margin and that the second TextView correctly left aligns to the first. If you take the layout_alignLeft attribute off of the second TextView, it will align to the parent's left edge instead.

Alternative to LinearLayouts' layout_weight attribute?

I need a View to hold a number of TextViews, and the exact number I will not know unfortunately. I need the TextViews to sort of stack either under each other or right next to each other (imagine Tetris, but with just rectangles or squares). The way I have tried thinking about it is using LinearLayout to hold them either horizontally or vertically. I then use their weights to stretch them appropriately if they are next to each other. Otherwise, I use a vertical orientation. Problem is the performance with nested LinearLayouts with more complicated stacks. I thought about using RelativeLayout, but that wouldn't work because I need the TextViews to not overlap. So like if they are next to each other, they need to each take enough space evenly. With layout_weight it works great. I was hoping someone had any idea on how to make this work right/alternative.
Heres an example that is giving me a warning (only a simple example of what I am doing programmatically):
<LinearLayout 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"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Hello World 1"
android:background="#000000"
android:layout_weight="1"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Hello World 3"
android:background="#000000"
android:layout_weight="1"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Hello World 4"
android:background="#000000"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World 2"
android:background="#000000" />
</LinearLayout>
I've tried it with RelativeLayout by the way, but one of the TextView's needs to be a set size, but I need them to take space evenly. I won't know specific sizes. Measuring the screen width and dividing it that way is also both clunky and not precise. I appreciate anybodies input.
Edit: So I've been thinking about it some more and thought of a solution using RelativeLayout. There is a nice example in the Android docs, but the only problem is one of the Views needs to be a set size so the other one could stretch. But if there is a way to allow all of them not to have a set size, that could work too, so then they can stretch. Anyone tried doing that at some point?
It's a bit unclear what your final use case looks like, so I don't know if this will completely solve your problem, but you might take a look at TableLayout (docs link). It's based on LinearLayout so items can still be defined to evenly occupy a given space, but it allows you to define your positions and spans in terms of rows and columns.
So, for instance, your example code would look like:
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*" >
<!-- Wrap all items in a given row in a TableRow -->
<TableRow>
<TextView
android:text="Hello World 1"
android:background="#000000"/>
<TextView
android:text="Hello World 3"
android:background="#000000"/>
<TextView
android:text="Hello World 4"
android:background="#000000"/>
</TableRow>
<!-- If a child occupies an entire row, it can be by itself -->
<TextView
android:text="Hello World 2"
android:background="#000000"/>
</TableLayout>
You can also use the android:layout_column and android:layout_span attributes to define exactly which column an item should be in, and how many columns it should occupy. Also note that TableLayout and TableRow have basically ignore any layout params applied and use very specific (documented) parameters, so adding them to your code will only confuse what is actually going on. Of course, this can all be built programmatically as well as in XML.
If this does not provide the flexibility you need, I would then recommend creating your own custom layout that either extends or is based on LinearLayout. The mechanism is uses to measure children with weight is not that complex, and then you can override how each child is placed after measurement. Here is a source link to LinearLayout if you want to see how the platform does these things.
Update: As we know the percent support library is deprecated from API level 26. ConstraintLayout is the new way to achieve the same flat xml structure.
Updated Github Project
Updated Samples:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/fifty_thirty"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ffff8800"
android:gravity="center"
android:text="#string/fifty_fifty_text"
android:textColor="#android:color/white"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5"
android:textSize="25sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.5" />
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ffff5566"
android:gravity="center"
android:text="#string/fifty_fifty_text"
android:textColor="#android:color/white"
android:textSize="25sp"
app:layout_constraintHeight_default="percent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintLeft_toRightOf="#id/fifty_thirty"
app:layout_constraintTop_toBottomOf="#id/fifty_thirty"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.5" />
</android.support.constraint.ConstraintLayout>
Deprecated
update: We can use android support library for the same.
compile 'com.android.support:percent:23.0.0'
Consider this demo for dividing the screen into 50-50 percent.
<android.support.percent.PercentRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/fifty_huntv"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff7acfff"
android:text="20% - 50%"
android:textColor="#android:color/white"
app:layout_heightPercent="20%"
app:layout_widthPercent="50%" />
<TextView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_toRightOf="#id/fifty_huntv"
android:background="#ffff5566"
android:text="80%-50%"
app:layout_heightPercent="80%"
app:layout_widthPercent="50%"
/>
</android.support.percent.PercentRelativeLayout>
Output:
Demo HERE!!!
GitHub Project HERE!!!

Uneven LinearLayout weight distribution

I have a LinearLayout that has four views layed out horizontally. The first and last component are a set size. For the inner two views I want to just share the available space 50:50. I set each to a weight of "1" but when the views are layed out, the views are different sizes depending on the content they hold.
Here is my layout xml for reference.
<?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="wrap_content">
<ImageView
android:id="#+id/status"
android:src="#drawable/white"
android:paddingRight="10dip"
android:layout_height="35dip"
android:layout_width="35dip">
</ImageView>
<TextView android:id="#+id/name"
android:text="Name"
android:layout_height="fill_parent"
android:layout_toRightOf="#id/status"
android:layout_width="wrap_content"
android:layout_weight="1"
android:textSize="25dip">
</TextView>
<TextView android:id="#+id/description"
android:text="Description"
android:layout_toRightOf="#id/name"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_weight="1"
android:textSize="25dip">
</TextView>
<TextView android:id="#+id/time"
android:text="Time"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_toRightOf="#id/description"
android:textSize="25dip">
</TextView>
</LinearLayout>
Obviously these aren't the actual column names but I changed them for privacy purposes. This layout is used by a ListView which changes the text of each view to be whatever value its presented. The name and description fields should line up since they're both given 50% of the remaining screen but when the name is longer the description is shifted right. Why?
For the weight to be considered, the layout dimension needs to be 0 (zero)
<TextView android:id="#+id/name"
android:text="Name"
android:layout_height="fill_parent"
android:layout_width="0dip"
android:layout_weight="1"
android:textSize="25dip">
</TextView>
I also recommend making your weight add up to either 1 (and use fractions) or 100.
So instead of 1 you would use either 50 or .5 for each view. The LinearLayout code will work properly with any weight sum, but it gets difficult if you want to modify your view later with additional sections.
Also, if you are not using relative layout, get rid of the toRightOf attributes. Less is more.
Try to use android:layout_width="fill_parent" instead of "wrap_content" in all children of LinearLayout. Or better yet, make such a structure in your xml:
<RelativeLayout>
<ImageView /> # status, fixed width, alignParentLeft="true"
<TextView /> # time, fixed width, alignParentRight="true"
<LinearLayout> # layout_width="fill_parent", toLeftOf="time" toRightOf="status"
<TextView /> # name, use layout_weight="1"
<TextView /> # description, use layout_weight="1"
</LinearLayout>
</RelativeLayout>
This should do what you want. Using LinearLayout instead of RelativeLayout might work too, but you have to experiment a bit (I believe using nested Layout, as in my example, will do the work).

Categories

Resources