Position a view below a RecyclerView - android

I have a very simple question that for some reason im not being to able to implement.
I have a RecyclerView which is being filled only once upon its activity creation. I want to add another view below it.
If the RecyclerView doesnt fill the entire screen length (usually in portrait mode) the view should be positioned directly below it.
If the RecyclerView exceeds the screen length (usually in landscape mode) the view should still be positioned below it but should also be docked to the screen bottom.
Thats it.
I've tried position them in RelativeLayout, LinearLayout or CoordinatorLayout. With match_parent, wrap_content (with or without setAutoMeasureEnabled). With app:layout_anchor and app:layout_anchorGravity but nothing is working.
Appreciate any help.
This is an example of one of my tries:
<android.support.design.widget.CoordinatorLayout 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">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/features_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_anchor="#id/features_list"
app:layout_anchorGravity="bottom" />
</android.support.design.widget.CoordinatorLayout>

Try this:
Note: I'm using a ScrollView since you said the height of your RecyclerView can exceed the screen size.
<?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:orientation="vertical">
<!-- Required for the content to not exceed the screen -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:measureAllChildren="true">
<!-- Content -->
</ScrollView>
<!-- View that needs to be under the ScrollView or
clipped to the button of the screen based on the ScrollView height -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
</LinearLayout>
</LinearLayout>

Related

ListView only renders one item unless height is specified

i have a context-menu with items in a ListView, all contained within a BottomSheet from the ASL/Design lib. The activity's root view is a CoordinatorLayout as specified by BottomSheetBehavior.
The problem I'm facing is that the ListView (R.id.problematic_list below) only renders the first list-item if the list-view-container's height is either wrap_content or even match_parent (R.id.list_container below). If this list container has a generous height set (eg: 400dp) then the full list renders as expected; along with extra space (since height is over-specified). The ListView is dynamically populated so I can't set a static height in the layout-xml file.
Is there a simple layout, attribute or programmatic workaround for allowing the ListView to both populate and render without over-allocating vertical space?
My initial configuration is as described here
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/primaryBlue"
android:orientation="vertical"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar android:id="#+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"_elevation" />
<!-- main activity content -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar"
/>
</RelativeLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="true"
android:layout_gravity="bottom"
app:behavior_hideable="true"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<!-- layout_height= 300dp / wrap_content -->
<LinearLayout
android:id="#+id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/problematic_list"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
the NestedScrollView has its own set of height requirements in order to render fully. I removed it from the hierarchy and the list renders in all available space.
thanks #CoderP for the hint

Prevent specific layout move on keyboard open

I have a next problem.
Structure of my layout is:
<RelativeLayout>
<AppBarLayout>
<Toolbar></Toolbar>
</AppBarLayout>
<FrameLayout> Here I load fragments </FrameLayout>
<Footer></Footer>
</RelativeLayout>
I want to use feature:
android:windowSoftInputMode="adjustResize"
in my activity, but the problem is that the footer going up on keyboard open. I don't know how to prevent only footer to be moved but all other views to be. I'm searching for days for the solution but without success.
When I set:
android:windowSoftInputMode="adjustPan"
footer is not moving which is good, but forms with EditText are covered with keyboard which is annoying and bad UI/UX.
My footer has a
android:layout_alignParentBottom="true"
Here is the full XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_logged_in"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/main_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/main_app_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp">
<!-- Footer goes here -->
</LinearLayout>
<FrameLayout
android:id="#+id/fragment_logged_in_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/bottom_navigation"
android:layout_below="#id/main_app_bar" />
</RelativeLayout>
Thanks in advance
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/main_app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/main_app_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/fragment_logged_in_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
This worked for me.
First of all, use <RelativeLayout> as your layout root.
Now you can stack your content in two ways:
From above
From below
Say you have five pieces of content A - E. You want only E to move up when your app window resizes from the bottom (that is: the keyboard shows from below). So what you want to do is, start stacking A - D from above, and stack E from below.
Here is an example. Unnecessary attributes are left out for sake of brevity.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<AnyView
android:id="#+id/A"
android:layout_alignParentTop="true"/>
<AnyView
android:id="#+id/B"
android:layout_below="#+id/A"/>
<AnyView
android:id="#+id/C"
android:layout_below="#+id/B"/>
<AnyView
android:id="#+id/D"
android:layout_below="#+id/C"
android:layout_above="#+id/E"/> <!-- this one will fill any space left out after adding views A, B, C, and E -->
<AnyView
android:id="#+id/E"
android:layout_alignParentBottom="true"/>
</Relativelayout>
So basically what happens is that when your keyboard shows, the bottom anchor of the screen moves up. When you say android:layout_alignParentBottom="true", this will keep that view just above this bottom anchor.
But as far as other views (A, B, C, and D) are concerned, they are not directly dependent upon that bottom anchor. So, they will not move or adjust themselves.
Just one thing to keep in mind. When you build your layout like this (a little stacked from the top, and a little from the bottom), there will always be one specific view that will have a variable height, and will adjust to changing screen heights. In the above example, that view is D.

Place view below AppBarLayout without appbar_scrolling_view_behavior

I am using a CoordinatorLayout that contains an AppBarLayout and a FrameLayout that will hold different fragments at runtime. I need the FrameLayout to always be below the AppBarLayout without using the appbar_scrolling_view_behavior attribute. For reasons (namely trying to get a RecyclerView and a floating footer button to work on the Fragments) I am applying this attribute on the RecylerView in the Fragment. Scrolling works fine except the FrameLayout thinks it should have the full height of the screen. This is usually fixed by the appbar_scrolling_view_behavior, but I cannot use that here. I tried layout_anchor and layout_anchorGravity to literally no effect.
Any ideas?
Layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
style="#style/AppTheme.Toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
/>
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
style="#style/NavigationTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</android.support.design.widget.AppBarLayout>
<!-- Fragments go here; they will set appbar_scrolling_view_behavior themselves -->
<!-- layout_anchor and layout_anchorGravity don't work -->
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_anchor="#id/app_bar_layout"
app:layout_anchorGravity="bottom|left|right"/>
</android.support.design.widget.CoordinatorLayout>
Layout of one of the fragments:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:orientation="vertical"
android:paddingEnd="15dp"
android:paddingStart="15dp">
<!-- Bottom padding is so the last row isn't fully covered by the button -->
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="55dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<Button
android:id="#+id/add_photo_button"
style="#style/ProductActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="15dp"
android:drawableStart="#drawable/white_camera"
android:text="#string/product_photo_add"/>
</FrameLayout>

CoordinatorLayout moves content

I have a CoordinatorLayout, AppBarLayout, Toolbar and main content in the form of NestedScrollview and stuff inside it:
<android.support.design.widget.CoordinatorLayout
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:fitsSystemWindows="true"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fitsSystemWindows="true"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world"
/>
</android.support.v4.widget.NestedScrollView>
In the picture above, the blue section is the NestedScrollView (i.e., the main content). As you see, its height is calculated with no regard to toolbar and is just moved out of the screen.
If you replace the CoordinatorLayout with any other layout, the NestedScrollView fits well (again, the blue part is the content, i.e., the NestedScrollView):
Is it how it should behave by design? If so, how to make the NestedScrollView fit the remaining screen wholly without moving its part below?
Update: If I remove behavior on the NestedScrollView, it moves back to top, but then gets covered by the toolbar.
Update 2: Sorry if it wasn't clear, but the main idea for using the CoordinatorLayout was the ability to apply various behaviors, including the default one provided. I have some user entered text that potentially may not fit into the screen, so I surround it with NestedScrollView. Now, to ease entering the text and have more space available, I'd want the toolbar to scroll out when scrolling and typing into this input (because adjustPan and adjustResize are not ideal)
Try surrounding it with the <LinearLayout> . I mean, after the Coordinate Layout.
Use weights attributes of LinearLayout ( If necessary ) .
Set Width and height of the Nestedscrollview as Match_parent or fill_parent.
Another thing, you actually don't want to worry about the issue you specified above. It should work well when you execute.
Here is the code with <LinearLayout> . Using this tag inside will give us flexible alignment. It may be difficult at first time , but use it and practice surely it will do a trick.
Here the NestedScrollView is fixed inside the screen.
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/third"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world"
/>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Its Pretty simple.You can try this in CoordinatorLayout.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="#+id/parentlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity"
android:animateLayoutChanges="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="#dimen/margin_16"
app:expanded="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
<!-- Your Entire Code goes Here -->
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Your View will look like this
In case anyone is still interested in this issue, I guess I have the explanation why this happens.
So the main issue here is the AppbarLayout and it's ability to add scrolling behaviours when it's used with a CoordinatorLayout. Let's say you want to scroll away the toolbar when a user scrolls down on the view below the AppbarLayout (Let's say you have a ViewPager). Then the OS also needs to scroll that ViewPager up to fill the space on the top of the screen. But when that happens if the ViewPager doesn't have enough height to fill the entire screen, then there would be a space on the bottom. That's why the system adds an additional height (which is exactly the same height as the AppbarLayout has) to the bottom of theViewPager, to fill the space on the top, in case the AppbarLayout scrolls away.
If you look at the problem in this way, this is something that needs to be done to have a consistent view. So either you have to remove the AppbarLayout or decide not to use scrolling behaviours.

How to wrap Coordinator Layout in a LinearLayout?

I´m attempting to use the new Android Design Library´s CoordinatorLayout inside of another layout. The CoordinatorLayout contains a RecyclerView. What I´m attempting to do is to place a simple LinearLayout below the CoordinatorLayout. This layout should be placed below the CoordinatorLayout. This is XML I´m using:
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="fill_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:orientation="horizontal">
<EditText
android:layout_width="fill_parent"
android:layout_height="match_parent" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/ic_send_white_36dp" />
</LinearLayout>
</LinearLayout>
As you can see, I´m attempting to wrap the CoordinatorLayout inside another LinearLayout. However, on-screen the second part of the layout doesn´t even render.
That is because the CoordinatorLayout has layout_height="match_parent". That means it takes the whole size of the screen and your LinearLayout is rendered but it is below the CoordinatorLayout and off-screen.
An easy way to fix this would be setting the weight of the CoordinatorLayout to fill the parent layout but leave space necesseary to display the footer LinearLayout. This would be
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
But this is not ideal way so I would suggest leaving the CoordinatorLayout as the root element and place your LinearLayout just bellow the RecyclerView where it belongs. Since your footer LinearLayout has fixed height this can be done easily
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.design.widget.AppBarLayout>
<android.support.v7.widget.Toolbar />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:paddingBottom="150dp" />
<LinearLayout
android:layout_height="150dp"
android:layout_gravity="bottom">
<EditText />
<ImageButton />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>

Categories

Resources