RelativeLayout align parent *side* + margin *side* - android

I've noticed a strange behavior in RelativeLayout when you align a view to the layout's side
(any side) and having a large margin in the same direction.
I have 2 RelativeLayouts that each contains a simple view. In one layout that view is align to the top and left, in the other to the bottom and right:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="110dp"
android:layout_gravity="center"
android:background="#ff555555" >
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:background="#aa8711" />
</RelativeLayout>
<RelativeLayout
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginBottom="110dp"
android:layout_gravity="center"
android:background="#ff555555" >
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#998877" />
</RelativeLayout>
</FrameLayout>
It looks like this:
I added 130dp of margin in each direction of parent alignment. That means that the view should be only partially visible in the layout. This is what happens:
As you can see, the views are now smaller than the original size, as the get pushed on the "walls" of the layout. Next I tried to give a margin that is bigger than the layout, so I gave them 151dp of margin in the aligned directions. It looked like this:
The bottom-right aligned view now "breaks out" of the layout and is again the same size as it was originally. On the other hand, the top-left aligned view is too in its original size, but completely inside the layout instead of outside of it.
I've tried this individually and in every permutation of alignment and got the same results.
Question one: Can anyone explain this inconsistent behavior?
I tried the same thing, this time comparing the behavior to that of a FrameLayout.
Initial setup:
and after margins:
The FrameLayout keeps the view in its original size at all time and simply lets the view "exit" it. I tried to give a negative margin in the opposite direction of at least the size of the view that should be outside of the RelativeLayout and saw the same behavior as happens in the FrameLayout by default.
Question 2: Can anyone explain the difference in behavior and the opposite negative margin effect?

Why should it be only partially visible?
I added 130dp of margin in each direction of parent alignment. That
means that the view should be only partially visible in the layout
The box is getting smaller because preference is given to keeping it inside the parent layout at all costs, while still applying the margin. Since the smaller child view is 50dp, you have added a margin of 130dp, the total width it needs is 180dp but the parent view itself is only 150dp wide. That is 130dp + 50dp > 150dp - the child plus the margin cannot fit inside the parent.
This is "silly input" and the XML interpreter is doing its best to render something. The decision that it makes in the end is that it can alter the width of the child box and still respect the margin constraint. Or mathematically
130dp + 20dp == 150dp
Basically it shrinks the width of the inner box down from the assigned 50dp to 20dp so that it can fit inside the parent with its added margin. And if you look at the size of the square 20dp looks about right. It is 60% smaller.
This is clever behaviour by the interpreter because as screen sizes change and it runs into issues like this it should always preserve the margin constraint opposed to the width constraint.
In summary the interpreter is doing its best to fit the box, and its margin inside its parent, to do so it is making the box smaller. It is choosing to preserve the given margin, over the given width - probably because of the top-most parent layout.
When you say "this should be partially visible" I assume you think the child will render half inside the parent bounds, and half outside the parent bounds, similar to windows form development. This is not the case though because it will always try to keep children inside the bounds of parents in most layouts.
The choices that are made depend on the top-most parent layout too, some layouts may prefer to preserve the width of the child box rather than the margin, or even render the box outside of the parent's bounds.
In the second case:
so I gave them 151dp of margin in the aligned directions.
You are going beyond the point in which the interpreter can shrink the image. It cannot shrink the image to negative 1. That is
50dp + 151dp > 150dp
It can't meet this margin constraint you have given it so the behaviour is fairly unpredictable. At a guess I would say it knows it cannot keep both the images, along with their margins inside the parent. So it simply renders one inside and one outside.
Once again, this is silly input and the interpreter is doing its best to render what you want.
Can anyone explain the difference in behavior and the opposite negative margin effect?
A negative margin will do different things depending on the type of layout in its parent, and that it is aligned too. In a frame layout it will behave differently to a relative layout. Usually if you are looking at negative layouts you have chosen the wrong parent containers and you are trying to hack it to get it to look right.
I don't know what you are trying to do exactly but maybe you just need tweak your thought process a little and think of the poor interpreting trying to understand the XML you give it.
You wouldn't be the first person to be utterly confused by android's XML layouts. Nesting layouts inside layouts is always confusing and the behaviour changes depending on a number of things like margins, alignments, widths, etc. Most people I know simply muck around with it until it is right and try different container layout types to get the right design.
In short, avoid playing with margins (like flash or winforms) and play without layout types instead to get things where you want them.
hope that helps, sorry for tl;dr.

Related

How do I make a Button so that when I put part of it out of bounds the program doesn't just cut the parts of it that aren't inbound

How do I make a Button so that when I put part of it out of bounds the program doesn't just cut the parts of it that aren't inbound. What I mean is this.This is a rotating view, the rectangles are rotating around the circle, but since I put 2 of the buttons partially out of bound their parts get cut off. Is there a quick fix for this?
(If programmatical fix is necessary I am writing in Kotlin)
The reason this is happening is because the RelativeLayout in which you're adding these four Views (buttons), has the width of screen's width. You need to increase its width to contain both the left and right buttons completely. Then, when you rotate the RelativeLayout, the buttons will be visible.
For testing purpose, try giving this width to RelativeLayout
<RelativeLayout
android:layout_width = "1000dp"
android:layout_height = "1000dp">
<!--Your buttons here-->
</RelativeLayout>
See if this works out. If it does, then you'll have to calculate the width of RelativeLayout programmatically.

how to limit textView's width according to left width

I have a layout (can be relative, linear or constraint)
with TextView aligned to parent left and then ImageView (fix width) aligned that start right to the textView.
I want the image to be rendered first and only then to render the text view.
Meaning I want the text view to be truncated according to the left space after the image was rendered.
<RelativeLayout
android:id="#+id/account_name_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="#dimen/account_menu_account_name_layout_bottom_margin">
<TextView
android:id="#+id/account_name"
style="#style/AccountDataAccountName"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:lines="1"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:text="emailisverylongaswellwewantittogettruncated#gmail.longdomain.com"/>
<ImageView
android:id="#+id/account_name_chevron"
android:layout_width="#dimen/account_menu_chevron_size"
android:minWidth="#dimen/account_menu_chevron_size"
android:layout_height="#dimen/account_menu_chevron_size"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/account_name"
android:layout_marginTop="#dimen/account_menu_chevron_top_margin"
android:layout_marginLeft="#dimen/account_menu_chevron_left_margin"/>
</RelativeLayout>
I have tried few options:
1) telling the text to be left to the image view
2) putting weight on the text view - made gap between the two elements.
3) setting minWidth to the image view - didn't help just made the imageView scale smaller.
Any idea how to render the image first and how to limit textView's width according to left width?
You can force the width on the imageView. That will prevent the textview from pushing it off the space. If you are saying you did this, please post the resulting image as that wouldn't make any sense.
Your above example has no constraints to each other, no enforcement to not overlay or push off. You need some constraints, such as "toTheLeftOf" or "Weight" or LinearLayout to enforce it as Weight only works in LinearLayout.
The easiest way is to just give the imageView a hard coded DP width and height, then set the text to 0 width with a weight of 1 inside a Linear Layout.
You can also use percentages if you want, use a LinearLayout then put a weight sum of like 100 for example (representing 100%). Then assign your image whatever percentage it needs like layout_weight=30 and give the textview 70.
Any of these options will work fine for you. If you try it, and it does not, then post your tried code as it will work unless you are doing something goofy that is not visible in your current example. As I do this all the time, every time you make a row, you typically have an image on the left fixed and text on the right to grow.

Specify element to go beyond page margin in android scrollview/listview

I have a linear layout in which I have 3 views.
View1-Weight=1
View2-Weight=10
View3-Weight=1
Total weight is 12.
Now all elements have android:layout_width="match_parent". Which means that the screen is divided in proportion of their heights.
What I want to do is that I want to nest 3 ImageViews in View2 so that each image view fully occupies the available screen area to View2. And on scrolling, I must see the second image view and third image views respectively. Each must be continuous and sizes(of ImageViews) must become equal. If all were to be on a single page, I would have done it by setting their weights.But now since they are on different pages, I dont have an idea how to do it. I dont want to take absolute sizes as it may look ugly on different devices.
How is it possible and what should be used in View2-a ListView or a Scrollview? Is it possible via the xml file(my preferred solution).
Ok So here is the basic idea :
You cannot use a ScrollView or a ListView or a GridView here perfectly as you have not specified the width and height in a fixed manner by applying dp and dip. So the only thing will work here is a ViewPager(A modified version) It will scroll vertically. So heres how to do this.
You have 3 Views in the layout.
<View
android:id="v1"
android:weight="1.0"
....
/>
<View
android:id="v1"
android:weight="10.0"
....
>
<ViewPager
//so you must specify the width and height here as fill parent
android:width="fill_parent"
android:height="Fill_parent"
/>
</View>
<View
android:id="v1"
android:weight="1.0"
....
/>
Just use this view pager and you must specify your fragment imageview by supplying it the property of fitXY, it will force fix your one ImageView to be visible in the entire view 2 at a time then you can scrol vertically to access other two.

Why does my relative layout occupy full screen width

Why does my relative layout occupy full screen width
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
>
<Button
android:id="#+id/Button01"
android:text="Press Here"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button
android:id="#+id/Button02"
android:text="02"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</RelativeLayout>
I have specified the relative layout to "wrap_content", then why does it occupy full screen space. Out put is same even if i say android:layout_width="fill_parent".
Enlighten me please!
EDIT : I think i was not very clear with my question earlier. Apologies for that.
When I have 2 child views in a relative layout and one of them is left aligned to parent and other is right aligned and relative layouts width is WRAP_CONTENT then I expected the layouts width to be just the sum of width of 2 buttons (isn't that's what WRAP_CONTENT means??). I know there are other ways of achieving the UI im looking for but Im just trying to understand these relative layout tags properly.
EDIT 2: I have experimented a bit and it looks like if we using Layout_AlighParentRight with its parent's width as WRAP_CONTENT then the upper layout width is used for calculation (like few answers pointed out below). But we are using just the Layout_alignParentLeft then it works as expected and layout width is not extending to the complete screen. Thanks for the help folks!
The other answers have correctly pointed out that when your relative layout's width is set to wrap_content, and its children are aligned to both left and right, the relative layout takes the width of its parent - in this case, the entire screen. If, however, both children were aligned to one side, the relative layout would be as wide as the widest child.
Now if you want the two buttons to be placed next to each other, and the relative layout to be as wide as the sum of the widths of the buttons, a slightly different approach is needed. Instead of positioning both buttons relative to the parent, do that with one button only (e.g, the first one). Let's say its positioning is left unchanged (android:layout_alignParentRight="true"). Now the button is floated to the right, so the second button, in order to be position next to it, has to be aligned to the first button's left side. Thus, we just add android:layout_toLeftOf="#id/Button01" (and remove the android:layout_alignParentLeft="true" part).
For more, I suggest you check out a very friendly tutorial on relative layouts.
cause you have a
android:layout_alignParentLeft="true"
width an object , and a
android:layout_alignParentRight="true"
width another object , then the layout extends to both side , giving you the full width layout.
But when you use Layout_alignParentXXXXX , and you put in parent WRAP_CONTENT , that makes children to go to the upper layout with a width defined.
This line makes the "Press Here" button (Button01) align to the right:
android:layout_alignParentRight="true"
That makes your layout fill the parent in width.
Another issue you may face is that if you set your 2 children to "align parent right"+"wrap_content", and your relative layout to "wrap_content", and that relative layout is contained in a full screen LinearLayout your relative layout will occupy the whole LinearLayout width.
If you do that with both "align parent left", the relative layout sticks on the left, and its width is really a "wrap content". But the behaviour is different for "align parent right", that's a bit strange.
Workaround:
To solve that issue (I had to align one of the children to the right), I actually set the 2 children to "align parent left" and played with children padding in order to get one of the children positionned on the top right corner. This is a dirty workaround but the only one i've found for now.
Possible cleaner solutions:
Another trick would be to put 2 LinearLayout inside a FrameLayout, then put your real children in each LinearLayout, and play with the gravity of those LinearLayout to position children at the right position.
RelativeLayout
LinearLayout
Child 1 (wrap_content)
LinearLayout (gravity: top right)
Child 2 (wrap_content)

Issues with padding in RelativeLayout

<View
android:id="#+id/first_sep"
android:layout_width="fill_parent"
android:layout_height="1dip"
android:paddingTop="100dip"
android:layout_below="#id/calculate"
android:background="#FFCCCCCC" />
I have this View in a RelativeLayout and the android:paddingTop property doesn't seem to work. Tried it with various values and still the View lies close to the Button "calculate".
As MGS indicates, you probably want android:layout_marginTop, or perhaps android:layout_height=101dip. I am uncertain if padding has any meaning on a generic View. If it is supported, it certainly will have no difference than simply setting the height to include the padding, since padding is considered part of the background calcluations.
For space between a widget and an adjacent widget, use margins. For space between the edges of a widget and its contents (e.g., between the edge of a Button and its caption), use padding. In the case of a transparent background, these will visually be identical. In the case of a non-transparent background, they will be substantially different visually.

Categories

Resources