I would like to place a layout on the bottom of a LinearLayout, but I can't seem to get it to work. I know that I can use RelativeLayout to do this, but I should be able to use LinearLayout, shouldn't I?
EDIT: Actually this is more confusing than I thought. The layout below is simplified. In reality, I'm using fragments on a pre-3.0 device, with the compatibility layer.
I used Hierarchy Viewer to examine what's going on, and found that an android.support.v4.app.NoSaveStateFrameLayout was added to my layout, and that layout has layout_height set to wrap_content. That seems to be what's causing my problem, but I haven't yet figured out how to fix it.
Specifically, why doesn't this work? Shouldn't the layout_gravity place it at the bottom?
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
... stuff here ...
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal">
... more stuff here ...
</LinearLayout>
</LinearLayout>
BTW, changing layout_height to fill_parent or setting layout_weight don't seem to work either. I just want to better understand what is going on, because clearly I'm missing something important. Thanks.
First of all nice question.
Android behaves we can say weird in the situation like this.
if you have selected your parent linear layout's orientation horizontal then you can set its child component at bottom by setting its layoug_gravity=bottom. suppose you have added 2 text views in that horizontal linear layout and second textview's layout_gravity is bottom then it will set to bottom but it work like it is set at bottom in other column then the first text view. NOTE : you can set textview's layout_gravity = "left" or "right" when its parent linearlayout is horizontal but you cant see its result.
Oppositely, if you have selected parent linearlayout's orientation vertical then you can set its child component at left or right by using layout_gravity. but the second textview will shown in you can say next row with left or right gravity as you have set. NOTE you can set textview's layout_gravity = "top" or "bottom" when its linear layout is vertical but you can not see its result.
Try to make sample xml design as i have stated above so you get better idea.
Strange but True!!! Try to understand this behavior. :)
Just add space between what you want at the bottom and all the rest:
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
So I resolved the problem. It's a two-part solution:
First, the way to do this without using LinearLayout is to provide weight to the element above so that it takes up all of the empty space. BTW, you can see this example in the API demos: http://developer.android.com/resources/samples/ApiDemos/res/layout/linear_layout_3.html
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
... stuff here ...
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weight="1"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
... more stuff here ...
</LinearLayout>
</LinearLayout>
This by itself didn't solve my problem, as I had a NoSaveStateFrameLayout with layout_width="wrap_content" as a parent view, and so I needed to get that fixed first. I'm using code based on the wonderful Google I/O App, and when I searched the code for NoSaveStateFrameLayout, I found this:
// For some reason, if we omit this, NoSaveStateFrameLayout thinks we are
// FILL_PARENT / WRAP_CONTENT, making the progress bar stick to the top of the activity.
mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
Thanks for an awesome comment Google!!! I added this into my source and everything worked great!
The moral of the story: Hierarchy Viewer and comments are your friends.
LinearLayout will just stack things as they are placed in there. Since it is vertical, it will keep placing items one after the next in a vertical manner. Can you change the android:gravity of the linearLayout and not the layout_gravity of the nested one and see if that works.
RelativeLayout of course should be the first way but you stated you didnt want to do that. Is there reason for that?
It could be that, as per https://stackoverflow.com/a/13366783/513038, you need to set the parent LinearLayout to have android:baselineAligned="false". Worked in my case.
Related
Related question. Answer: RelativeLayout can't do it. I'm asking how to do it anyway, with not just RL, or with something else.
General story: you have a complex layout that would be difficult to adjust, and along comes a request for something to be added, aligning with a nested view.
What is the best approach? A popup with a custom style? (not familiar with those yet)? Spending days changing the whole hierarchy to a single RelativeLayout? A custom Layout class as wrapper?
AbsoluteLayout (deprecated) or FrameLayout with programmatically changed LayoutParams or margins? (this I'd rather avoid, I prefer not to touch onMeasure, etc)
Simplified example (no relation to pic above):
LinearLayout defines relative heights of the elements. I don't know to do it with RelativeLayout.
anExpandableView is something to be animated as sliding from under someBar (here; full-width, but perhaps it may need to align its width, as well as vertical position).
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/topStuff"
layout="#layout/incl_topstuff"
android:layout_width="match_parent"
android:layout_weight="7"
android:layout_height="0dip" />
<include
android:id="#+id/someBar"
layout="#layout/incl_filters_and_stuff"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
android:id="#+id/bottomStuff"
layout="#layout/incl_bottomstuff"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="10" />
</LinearLayout>
<include
android:id="#+id/anExpandableView"
layout="#layout/incl_filters"
android:visibility="gone"
android:layout_below="#id/someBar"/>
</RelativeLayout>
I know SO has an aversion to general questions, but I don't want an ad-hoc solution. I am asking what to do in cases which would be solved if only a wrapping RelativeLayout would allow alignment to a view that is not a direct sibling.
Putting it simply, RelativeLayout can only measure and layout it's direct children based on each other, but I guess you already knew that.
The only general solution would be to implement your own custom Layout class, which I wouldn't recommend. If I had to guess why RelativeLayout does not traverse the entire layout hierarchy at it's level and below, it's probably for performance reasons.
Unfortunately if you're using RelativeLayouts and LinearLayouts and you want views to be dependent on each other you have to pick one approach and stick to it, either the flat hierarchy of RelativeLayout, or the nested one of LinearLayout.
Based on your example, as far as I know, there is no way to implement weighted views with a RelativeLayout, so you're stuck with using a LinearLayout.
The easiest way to do what you want is to inflate your expandableView in code, align it with the bottom of the RelativeLayout, set it's height and position based on bottomStuff, and animate from there.
If you really want to do it in xml, I can think of one somewhat hacky, ad-hoc approach, but which can can be generalized to mirroring the measurement and layout of any hierarchy with a bit of work.
Create a parallel but invisible LinearLayout that is a sibling of the first one. Give it an empty view with weight 7 on top, an invisible copy of someBar in the middle, then your expandable view under that with weight 10. To have it slide up, either animate the height of the invisible someBar and the weight of the empty view on top towards 0, or remove them/set them to gone and set animateLayoutChanges on your LinearLayout.
This is what is causing me many problems:
<RelativeLayout
android:id="#+id/galleryLayout"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="#color/white">
<android.support.v4.view.ViewPager
android:id="#+id/imageViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true" />
<com.viewpagerindicator.CirclePageIndicator
android:id="#+id/circlePageIndicator"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:padding="#dimen/padding_middle"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
Right now this code kind of works only because I've set RelativeLayout's height to 180dp but I don't want to have it this way. I want the whole thing to have height according to ViewPager's child.
There are exactly 2 problems if I set RelativeLayout's height to WrapContent.
Problem 1
ViewPager will expand throughout the whole screen. It just doesn't respect it's wrap_content height attribute. But I've partially solved that with this answer. I'd still appreciate if there's a better solution though.
Problem 2
I want have CirclePageIndicator on the bottom of it's parent (RelativeLayout) so I've added attribute layout_alignParentBottom="true" but now because of this, the RelativeLayout will expand throughout the whole screen for some reason.
So what I'm trying to have is a RelativeLayout which wraps around ViewPager which wraps around it's child. The child is downloaded from web so I can't pre-set it. And on the bottom of that RelativeLayout, I want to have a ViewPagerIndicator.
As for the problem 1 you solved the issue correctly, ViewPager will not wrap its children by default.
As for the second problem, this is a normal RelativeLayout behaviour. If you set its height to wrap_content and add two children, one with layout_alignParentTop="true" and second one with layout_alignParentBottom="true", they will stretch your layout height-wise.
What you should do is: ask yourself if you really need RelativeLayout. If you've provided the whole layout of yours I don't see a need for RelativeLayout (its costly). Vertical LinearLayout would do just fine. If you decide that you really need RelativeLayout, try changing your Indicator's rule from layout_alignParentBottom="true" to android:layout_below="#+id/imageViewPager".
Background
I have a RelativeLayout inside a FrameLayout/RelativeLayout (doesn't matter to me), which should be at the bottom of the screen (like a toolbar), and should hold a few views in it.
Its height is set to "wrap_content" and so does its child-views.
The child-views of this layout are : A textView that is on the left, and a Horizontal LinearLayout on the right with a few buttons.
The problem
It seems that no matter what I do, the textview is causing the RelativeLayout to take the whole space, instead of just its children.
The code
Here's the minimal XML content that causes this problem. I've removed the extra stuff (LinearLayout and its children, and also some attributes that don't matter) since they don't cause this problem in case I remove the TextView:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000" >
<!-- Here I've put some views that don't have any relation with the views below, so it doesn't have anything with do with the problem -->
<RelativeLayout
android:id="#+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#drawable/vertical_gradient_transparent_to_black" >
<!-- Here I've put a LinearLayout that doesn't cause the problem, so I've removed it for simplicity-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</RelativeLayout>
I've tried many possible attributes, and also tried adding additional layouts to try to "fool" the RelativeLayout, but none of those have succeeded.
The question
Why does it occur?
A working solution would be to use a Horizontal LinearLayout (with a weight for the TextView ) instead RelativeLayout , but I still want to know why can't I use a RelativeLayout, and why it occurs. Also how to fix it while still using 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.
I have encountered the same issue before, this might be caused by android:layout_alignParentBottom attribute.Maybe you can find another way to achieve your desired effect. See this for more information.
This is some kind of Strange issue. Maybe someone else has the explanation.
I found it working when i removed the line
android:layout_alignParentBottom="true"/>
and it also worked when i tried some like this
<TextView
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:layout_height="wrap_content"/>
I'm getting some weird left and right side margins when using a custom listview item layout. They are margins (or at least not padding of the container), since the background doesn't extend to the edge.
In this layout, I'm using a simple vertical LinearLayout with a bunch of textviews and a progressbar. If I switch back the built-in simple_list_item_activated_1.xml, the margins disappear. The linear layout itself doesn't have any layout margins. I specifically stripped it of any attributes, leaving only the id, the layout_width="match_parent" and layout_height="wrap_content", and the margins were still there.
Is there anything I'm missing here?
A screenshot of the problem can be seen here:
Edit 1: #Grishu: As I've said earlier, these margins appear even with a very simple layout, such as this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/some_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
I just typed this from memory, so it might contain syntax errors. But you get the idea.
Edit2: I just went over all my layouts. The problematic margin was set on one of the parent containers, thus it has nothing to do with list items. Sorry for the spam.
i had a similar problem with a listview item layout, it looked fine in the graphical layout in eclipse, i solved it by setting:
android:layout_margin="0dp"
android:padding="0dp"
in the main relative layout, hope this helps.
I have many activities with a scrollview inside a tablelayout. However, it is necessary a small design change, so I have to put a black transparent view over the whole screen from the top to the bottom. Is it possible to do it in the tablelayout or the scrollview?
RelativeLayout allows for easy overlapping of views. You'll have to adjust the existing views in your app because it doesn't do anything automatically.
EDIT:
A quick way to do this would be to take your existing view (the ScrollView) that is already organized and put it in a top-level RelativeLayout. Then, all you have to do is add new view inside the RelativeLayout with the width and height both set to MATCH_PARENT. The result should be the black transparent view will be visible over the ScrollView.
I normally use FrameLayout to achieve any kind of 'layering' of views.
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
//your existing layout
<View
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#33000000" />
</FrameLayout>
As DeeV said, you can probably use RelativeLayout in a similar way, but you might have to set additional attributes on its children to achieve this.