LinearLayout, RelativeLayout, etc. margins do not work as expected - android

Margins in group layouts do not seem to work.
For example,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="40dip"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="I'm a button" />
</LinearLayout>
should display a button with 40p margins on all sides. However, it has 80p margins on the right and bottom.
Am I doing something wrong?
Is this a bug?
A workaround would be to use gravity, but this only works with even margins.
BTW, there is a similar question posted here but has not been answered.

android:padding="40dp" on the LinearLayout or android:layout_margin="40dp" on the Button will give you the effect you want. Padding defines the space between a views edges and its content, layout margin defines extra space on the sides of a view.

The problem is actually the way FrameLayout interprets margins. setContentView() attaches your "main" layout to a FrameLayout, which is the actual root of the view hierarchy (you can see that with Hierarchy Viewer) and is offered to you by the phone.
Margins are managed by the parent layout, so in this case that main FrameLayout. I don't know if it's a feature or a bug, but that's how this layout interprets margins.
So well, the solution was already posted while I was typing: use padding instead.

if you need set margin for a layout, simply wrap it with another linear or relative layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:layout_margin="40dip"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="I'm a button" />
</LinearLayout>
</LinearLayout>

Wrapping the Linear Layout with another layout is the best strategy.

Related

layout_gravity="center_vertical" not working

My problem
I can't seem to figure out why android:layout_gravity="center_vertical" is not working in my case.
Please note that I am not interested in solving the problem of making it vertically aligned, so much so that I am trying to understanding exactly what is the cause of this behavior itself for pedagogical reasons.
My code
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/blue_100">
<android.support.v7.widget.AppCompatTextView
android:background="#color/red_100"
android:text="HELLO WORLD"
android:textSize="18sp"
android:textColor="#color/black"
android:gravity="center_vertical"
android:maxLines="2"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v7.widget.LinearLayoutCompat>
A LinearLayout with vertical orientation will ignore the vertical component of any child's android:layout_gravity attribute. Similarly, a LinearLayout with horizontal orientation will ignore the horizontal component of a child's android:layout_gravity.
For the special case of the center gravity value, it's helpful to know that this behaves identically to center_horizontal|center_vertical, down to the actual integer value of the constants (0x11 vs 0x01|0x10). As such, using android:layout_gravity="center" in a vertical linear layout will be equivalent to just android:layout_gravity="center_horizontal".
As for why, consider this:
<LinearLayout orientation=vertical>
<View layout_gravity=top/>
<View layout_gravity=bottom/>
</LinearLayout>
What would you do here? If you position the first view at the top of the screen and the second view at the bottom of the screen, then you're not really a linear layout.
Even though you said you're not interested in how to solve the problem, you can do so with the android:gravity attribute on the LinearLayout itself. This will cause the LinearLayout to stack all the views together at the top, center, or bottom of the linearlayout.

Putting two child layout inside a parent layout with equal weight distribution in Android

I want to use two child layout (one linear layout and one relative layout) inside a parent layout (relative layout) in such a way that both of the child layout will take exactly half of the screen and items inside of each child layout will not cause one child layout to get more width than another one!
It is pretty easy, use parameter layout_weight in children of LinearLayout, something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
</RelativeLayout>
<RelativeLayout
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
</RelativeLayout>
</LinearLayout>
If I understand correctly from your illustration, the red box is a RelativeLayout, whereas the green boxes are a LinearLayout and a RelativeLayout.
A simple solution would be to center an empty View inside the RelativeLayout and align the two child Views against it:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="#+id/v_center" />
<View
android:id="#+id/v_center"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#+id/v_center" />
</RelativeLayout>
A nice little bonus here is that you can provide some spacing between the two by specifying the View's dimensions.
Beware, however, that RelativeLayouts aren't very efficient, and nesting them is an especially bad idea. I suggest using the hierarchy viewer tool to inspect the layout timings to make sure it's relatively fast, and to try to avoid nesting the layouts in this fashion.

ScrollView not scrolling to the end of inner LinearLayout's bottom margin

I'm having issues with a Fragment consisting of a ScrollView containing a LinearLayout. I'm trying to create an effect where the LinearLayout has a white background and looks like a piece of paper scrolling on a coloured background. The way that I'm trying to achieve this is by having the ScrollView occupy the full space of the fragment and then the LinearLayout inside has android:layout_margin="16dp" to create the space around the "paper".
This way, the scroll bar of the ScrollView appears in the coloured background area, the margin at the top scrolls away along with the content and the margin at the bottom only scrolls in when one reaches the end.
Unfortunately in this configuration the ScrollView won't scroll all the way to the end and in fact cuts off a very small amount of the text at the bottom. I suspect that the ScrollView isn't taking into account its child's margins in its vertical scrolling distance. To solve this I've wrapped the LinearLayout in a FrameLayout which solves the issue, but seems superfluous. Any pointers on how to eliminate this unneeded container would be appreciated.
Note: setting android:padding="16dp" on the ScrollView and scrapping the margins doesn't have the desired effect, as then the padding appears on all four edges continuously, regardless of scroll position.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
tools:context=".ArticleFragment" >
<!-- This FrameLayout exists purely to force the outer ScrollView to respect
the margins of the LinearLayout -->
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:layout_margin="16dp"
android:background="#color/page_background" >
<TextView
android:id="#+id/article_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textIsSelectable="true" />
<TextView
android:id="#+id/article_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true" />
</LinearLayout>
</FrameLayout>
</ScrollView>
I remember having trouble with the ScrollView somehow not making it to the end of it's contents when the content layout had a top margin. I solved the problem with a little hack, adding an empty view to the end of the LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".ArticleFragment" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:layout_margin="16dp" >
<TextView
android:id="#+id/article_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textIsSelectable="true"
android:background="#color/page_background" />
<TextView
android:id="#+id/article_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:background="#color/page_background" />
<!-- Add a little space to the end -->
<View
android:layout_width="fill_parent"
android:layout_height="30dp" />
</LinearLayout>
</ScrollView>
I used a similar empty view also in the beginning of the LinearLayout to avoid top/bottom margins completely.
EDIT: I just realised that you also wanted the end of the "paper" to show up when reaching the end of the view. In that case you might want to set the background color to the TextViews instead of the layout itself. Then make sure there's no margin between the title and the article (use padding as separation).
EDIT2: I should learn to check when the questions were asked... Well, maybe this still helps someone. :)
The question is old, but I've had issues with ScrollView being ill-behaved when wrapping FrameLayout. It also doesn't seem to consider the margins of contained layouts. You could replace the FrameLayout with another single-child LinearLayout, which should measure correctly. I would've removed the FrameLayout completely and simply added summed margin with padding on the inner layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="26dp"
android:background="#color/page_background" >
<!--...-->
I'd get rid of the FrameLayout and make the LinearLayout the child of the ScrollView with match_parent set as the layout height. If that still doesn't work, consider replacing the bottom margin with another arbitrary View with the desired height and background as the last item in the LinearLayout.

Left aligning images in LinearLayout using gravity or linear_gravity in XML

First off, this is not a duplicate question, to best of my ability I've tried all (there are many) similar questions. Solutions to such problems appear to be very subjective, specific to a given scenario.
My layout currently appears as follows. Black boxes are images (logo and body, respectively), colours represent each layout:
My XML:
<?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="#000"
android:padding="0px"
android:layout_margin="0px"
android:orientation="vertical">
<LinearLayout
android:layout_weight="16"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF"
android:gravity="top|center"
android:orientation="horizontal">
<ImageView
android:id="#+id/logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/logo"
android:layout_gravity="top|center" />
</LinearLayout>
<LinearLayout
android:layout_weight="4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00F"
android:gravity="bottom|left"
android:orientation="vertical">
<ImageView
android:id="#+id/body"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/body"
android:layout_gravity="bottom|left" />
</LinearLayout>
</LinearLayout>
Here you can see I have a parent linear layout, split into two children linear layouts. This is because I need the images to be positioned differently within that part of the page.
In a nutshell, I need logo to be vertically aligned to the top, and body horizontally aligned to bottom-left.
Now, a few things that I've tried:
Using RelativeLayout rather than Linear
Switching gravity with layout_gravity for both LinearLayout and ImageView, along with combinations of excluding each
Fairly confident match_parent for width and height is what I want, but I have tried different combinations with wrap_content
What I've come to understand:
gravity:top requires the parent view use orientation:horizontal
gravity:left requires the parent view use orientation:vertical
gravity applies to the children of the view
linear_gravity applies how the child aligns with it's parent
Using the same value for gravity on the parent and linear_gravity on the child might have the same effect (when using one instead of the other)?
Hopefully this is enough information. I'm having a very difficult time wrapping my head around how these layouts work.
Thank you SO much for the help!
I think your problem is you are setting dimensions of the image views to match_parent. I would use a RelativeLayout as it seems to be the most efficient in your case (pseudo-XML-code):
RelativeLayout (width=match_parent, height=match_parent)
ImageView (width=wrap_content, height=wrap_content,
alignParentTop=true, centerHorizontal=true)
ImageView (width=wrap_content, height=wrap_content,
alignParentBottom=true, alignParentLeft=true)
You don't need any gravity setting here. You might want to play with the scaleType attribute depending on your image sizes.

Using a nested LinearLayout

SOLVED: The layout_height parameter was set to Match_parent in the buttonbar definition. Changed to wrap_content.
I'm currently working on a new App which has a series of buttons at the top of the main screen. the "buttonBar" XML defines a linearLayout and is later nested within another linearLayout.
The buttons appear fine and work however if I then put a text view beneath the include statement the text does not appear. I think that it is actually appearing behind the buttons. I assumed that because it was within a parent linearLayout that it would appear after the included (nested) nested layout.
please could someone explain why this is not occurring and point me in the right direction to solve it.
much appreciated,
M
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include layout="#layout/buttonheader"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:id="#+id/textView1"
android:textColor="#ffffff">
</TextView>
</LinearLayout>
Set height and width of the included layout buttonheader
SO that you can see this included layout in your layout

Categories

Resources