why marginBottom not working? - android

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/messageLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/messageSender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"/>
<TextView
android:id="#+id/messageSenderName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/messageSender"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="false"
android:textColor="#color/list_text_color"
android:textSize="16dp"
android:layout_marginTop="5dp" />
<TextView
android:id="#+id/messageContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/messageSender"
android:layout_below="#id/messageSenderName"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="false"
android:textColor="#color/codeFont"
android:textSize="13dp"/>
</RelativeLayout>
In my layout I have problem. When I set marginTop="5dp" it's fine, but when I use marginBottom nothing happens in my layout. Also when I set padding in RelativeLayout it does not work either. What is the problem here? Could you give me any solution?

marginBottom has no effect if you set android:layout_height="wrap_content" for <RelativeLayout>, instead set it as match_parent and check.

It is realy just a bug of the <RelativeLayout>, so you could try to wrap the RelativeLayout inside of a <LinearLayout> and set the margin there.

I am not sure in which revision of android you are experiencing this issue. I looked at RelativeLayout in Android 4.2.2 (https://android.googlesource.com/platform/frameworks/base/+/android-4.2.2_r1.1/core/java/android/widget/RelativeLayout.java) and I believe there is a bug in the onMeasure.
In lines 486 to 488, we have following code:
if (isWrapContentHeight) {
height = Math.max(height, params.mBottom);
}
In my opinion, the above should read:
if (isWrapContentHeight) {
height = Math.max(height, params.mBottom + params.bottomMargin);
}
With android:layout_height="wrap_content", RelativeLayout does not appear take into account the bottomMargin of the last vertically laid out view.
I suggest you try one of the following:
*) Add a dummy view that will be the very last vertically laid out view, and ensure that it has the android:layout_below attribute. Note that the dummy view does not have a bottom margin, it is there so that RelativeLayout considers the bottom margin of views laid out above it. For your case, the dummy view would look like this:
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/messageSender"
/>
*) As others have mentioned, achieve the same effect in other ways, such as Padding.
*) A not-so-trivial solution is bring in RelativeLayout, its platform style definitions and Pool management classes into your project, perform the bug fix I mentioned above and use this anywhere you would normally use RelativeLayout.
*) File a bug with Google
Hope this helps.

Maybe you can set android:paddingBottom="" of <RelativeLayout> to get the same effect.

Make sure the layout_height of your root container is set to match_parent instead of wrap_content.

I had a <View> inside a <RelativeLayout> and the marginBottom on that view did not work. I found out that my chain of layout_below was broken, so therefore it makes sense that the layout did not know from which view the margin should be calculated.
If you chain it properly using layout_below or the other positioning tools, you do not need to worry about wrap_content or match_parent like others are suggesting. Example:
<?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="wrap_content">
<View
android:id="#+id/separator"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginBottom="11dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/separator">
...

In some case you have lots of attributs or you just missed that you included earlier :
android:layout_margin="xdp"
You can't use it with specific layout margination

It works if you use android:layout_marginBottom with android:layout_alignParentBottom="true".
For example :
android:layout_alignParentBottom="true"
android:layout_marginBottom="50dp">

Related

layout_height="match_parent" don't work as intended

I have a simple view as follows;
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="60dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_red_dark"
android:gravity="center">
<TextView
android:Text="Some text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>
Even though both LinearLayout's height and width is clearly set to match its parent, it matches the CardView's width but wraps its content heightwise.
Why does this happen?
I would like to comment but I have no "enough reputation", anyway.
Have you added the dependecy 'androidx.cardview:cardview:1.0.0' in gradle file? Your code works fine for me, but, I dont know if you added the dependecies.
Having
android:layout_height="match_parent"
in both CardView and LinearLayout meant that LinearLayout's height is the same as CardView's parent's height which was smaller than 60dp. Then setting
android:minHeight="60dp"
in CardView changes its height to 60dp while leaving LinearLayout's height the same. I replaced these two lines in CardView to
android:layout_height="60dp"
and problem is solved.
I still think this is unintuitive but it looks like this is what happens.

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.

This LinearLayout should use android:layout_height="wrap_content"?

I have the following xml layout :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" // ==> here I get the error.
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="2dip"
android:background="#298EB5"
android:orientation="horizontal" />
</LinearLayout>
</ScrollView>
But I get the lint message :
This LinearLayout should use android:layout_height="wrap_content"
Why do I get this message?
LinearLayout's are designed for stacking elements either side by side or on top of each other. My guess is that this lint warning recommends virtical stacking due to the ScrollView
Documentation:
"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). A LinearLayout respects margins between children and the gravity (right, center, or left alignment) of each child."
its Lint warning you should use
android:layout_height="wrap_content"
wrap_content occupies the height as per the add require content.
Here height of Layout wrap according to require
It's not an error but it is not suggested as it will produce unwanted result in some cases. I follow this article by Romain while using scrollview. I hope this will explain the reason for the message.

RelativeLayout is taking fullscreen for wrap_content

Why does FOOBARZ get layed out all the way at the bottom when no elements are layout_height="fill_parent" in other words, all elements are wrap_content for height?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/feed_u"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_marginLeft="5dip"
android:scaleType="centerCrop"
android:drawableTop="#android:drawable/presence_online"
android:text="U" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/feed_u">
<ImageView
android:id="#+id/feed_h"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/btn_minus" />
<ImageView
android:id="#+id/feed_ha"
android:layout_toLeftOf="#id/feed_h"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/btn_plus" />
<TextView
android:id="#+id/feed_t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title">
</TextView>
<TextView
android:id="#+id/feed_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Band"
android:layout_below="#id/feed_t">
</TextView>
<TextView
android:id="#+id/feed_s"
android:layout_below="#id/feed_a"
android:text="S"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</TextView>
<TextView
android:id="#+id/feed_tm"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="FOOBARZ"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</TextView>
</RelativeLayout>
</RelativeLayout>
From the RelativeLayout doc:
Class Overview
A Layout where the positions of the children can be described in relation to each other or to the parent.
Note that you cannot have a circular dependency between the size of the RelativeLayout and the position of its children. For example, you cannot have a RelativeLayout whose height is set to WRAP_CONTENT and a child set to ALIGN_PARENT_BOTTOM
Class documentation
Which is exactly your case. RelativeLayout can not do that.
For those looking for a solution to this, like I did, you can use FrameLayout instead of RelativeLayout.
Then you can set the gravity the intended object to bottom right as below
<TextView
android:layout_gravity="bottom|right"
android:text="FOOBARZ"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</TextView>
You have set the RelativeLayout to "wrap_content"
and the TextView to android:layout_alignParentBottom="true", so it automatically tries to stretch the RelativeLayout to the bottom. Don't use such dependencies with Relative Layout, as it can count as "circular dependencies".
From the docs for RelativeLayout:
Note that you cannot have a circular dependency between the size of the RelativeLayout and the position of its children. For example, you cannot have a
RelativeLayout whose height is set to WRAP_CONTENT and a child set to ALIGN_PARENT_BOTTOM.
Try to align your TextView to something other than the parent RelativeLayout, but watch out for this problem as well:
Circular dependencies, need some help with exact code
Alternatively, try to add more sophisticated inner layouts.
Dont use alight_Parent type properties with the child views
You can use frame layout instead of RelativeLayout with respective gravity
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<TextView
android:layout_gravity="bottom|right"
android:text="Hello "
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</TextView>
</FrameLayout>
FrameLayout is usually good for placing different views one on top of each other (where the most recent child is on top of the previous child). In your case, you'd like to place views one next to each other (above, below, start, end), so I think ConstrainLayout fits better because it's exactly what it does.
Unlike RelativeLayout, you'd be able to set the ConstrainLayout width to wrap_content and still arrange its children views as you wish, for example instead of
android:layout_alignParentTop="true"
you can use
grid:layout_constraintTop_toTopOf="parent"
and instead of
android:layout_alignParentBottom="true"
you can use
grid:layout_constraintBottom_toBottomOf="parent"
Good answers. Now if you don't have layout_alignParentBottom="true" and still getting this issue watch out for android:background="#drawable/bkgnd" where bkgnd is a biggie.
I'm not sure why the clean and obvious way of accomplishing this hasn't been posted yet. This performant solution works for any View MyView with a known height.
Wrap your RelativeLayout with height wrap_content in a FrameLayout:
<!-- width here should constrain RelativeLayout -->
<FrameLayout
android:layout_width="#dimen/my_layout_width"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<MyView
...
android:layout_gravity="bottom" />
</FrameLayout>
Just note that the view at the bottom of the FrameLayout will be on top of your RelativeLayout content, so you'll need to add padding to the bottom of that layout to accomodate it. If you want that view to be variable height, you can either Subclass FrameLayout to add padding in code based on the measured view height, or just change the FrameLayout to vertical LinearLayout if you're not worried about the performance, i.e. it's not a listview item, or the views are relatively lightweight.
Not sure why all the answers here suggest FrameLayout, which is designed to render a single view or views layered in the z axis. OP's problem is a sequence of views stacked vertically, which should be in a LinearLayout.

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

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.

Categories

Resources