I want to create a custom height toolbar and it works fine until I add content to it. Then my content is adjusted to be between the back arrow and the actionbar buttons.
How can I make my content take the entire width so I can create a layout like below? I guess the "+" icon needs to be in a parent layout of the toolbar?
The docs say:
The application may add arbitrary child views to the Toolbar. They will appear at this position within the layout. If a child view's Toolbar.LayoutParams indicates a Gravity value of CENTER_HORIZONTAL the view will attempt to center within the available space remaining in the Toolbar after all other elements have been measured.
But I don't have the gravity set to CENTER_HORIZONTAL...
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:iosched="http://schemas.android.com/apk/res-auto"
iosched:theme="#style/ActionBarThemeOverlay"
iosched:popupTheme="#style/ActionBarPopupThemeOverlay"
android:id="#+id/toolbar_actionbar"
android:background="#color/theme_primary"
iosched:titleTextAppearance="#style/ActionBar.TitleText"
iosched:contentInsetStart="16dp"
iosched:contentInsetEnd="16dp"
android:layout_width="match_parent"
android:layout_height="128dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
... My Content
Currently my layout ends up like this when running with left margin set to 168:
I'm not sure if you still need help with this, but it has the most votes for an unanswered question in not only the android-5.0-lollipop tag, but also the android-toolbar tag right now. So, I thought I'd give it one.
This layout is pretty easy to achieve, especially with the new Design Support Library.
Implementation
The root of your hierarchy will need to be the CoordinatorLayout.
As per the docs:
Children of a CoordinatorLayout may have an anchor. This view id must
correspond to an arbitrary descendant of the CoordinatorLayout, but it
may not be the anchored child itself or a descendant of the anchored
child. This can be used to place floating views relative to other
arbitrary content panes.
So, we'll use this to position the FloatingActionButton where it needs to go.
The rest is pretty straightforward. We're going to use a vertical LinearLayout to position the Toolbar, text container, tab container, and then a ViewPager. So, the full layout looks like:
<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:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#181E80"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:paddingTop="8dp">
<ImageView
android:id="#android:id/icon"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_alignParentStart="true"
android:layout_marginStart="16dp"
android:importantForAccessibility="no"
android:src="#drawable/logo" />
<TextView
android:id="#android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#android:id/icon"
android:layout_marginStart="14dp"
android:layout_toEndOf="#android:id/icon"
android:text="Chelsea"
android:textColor="#android:color/white"
android:textSize="24sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignStart="#android:id/text1"
android:layout_below="#android:id/text1"
android:text="England - Premier League"
android:textColor="#android:color/white"
android:textSize="12sp" />
</RelativeLayout>
<FrameLayout
android:id="#+id/tab_container"
android:layout_width="match_parent"
android:layout_height="90dp"
android:background="#272F93">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:tabContentStart="70dp"
app:tabGravity="center"
app:tabIndicatorColor="#F1514A"
app:tabMode="scrollable"
app:tabSelectedTextColor="#android:color/white"
app:tabTextColor="#99ffffff" />
</FrameLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="16dp"
android:src="#drawable/ic_star_white_24dp"
app:backgroundTint="#F1514A"
app:borderWidth="0dp"
app:elevation="8dp"
app:layout_anchor="#id/tab_container"
app:layout_anchorGravity="top|right|end" />
</android.support.design.widget.CoordinatorLayout>
There's not a whole lot more to add, the only other thing I'd mention is how to use the TabLayout. If you're using a ViewPager like we are, you'd probably call one of the two:
TabLayout.setTabsFromPagerAdapter
TabLayout.setupWithViewPager
Notes
I just kind of eyeballed the dimensions, trying to match the picture as much as possible.
Results
Related
I am using Collapsing toolbar layout in my project in which I am using one NestedScrollView in which I have multiple Card Views in which the content is not static instead it changes in onActivityResult. I have set minimum height of CollapsingToolbarLayout as 100dp. So I have observed couple of issues in it:
On big phones the content scrolls up to minimum height 100dp leaving a large empty space at bottom which is not desired result. It should scroll up only when it is necessary. Necessary Condition is that when I get large text value in Text fields it should scroll otherwise not.
I have used Natario Solution in it which calculates minimum height of CollapsingToolbarLayout dynamically which works somehow but it vanish the scroll ability of NestedScrollView If I get large dynamic texts, which is not desired result.
My layout.xml file is:-
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:clickable="true"
android:id="#+id/topBlock"
app:layout_constraintTop_toTopOf="parent"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/navigation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
app:elevation="0dp"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#null"
android:minHeight="100dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapse_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#android:color/holo_blue_light"
android:minHeight="100dp"
app:layout_collapseMode="parallax"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:layout_scrollInterpolator="#android:anim/decelerate_interpolator">
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="8dp"
app:backgroundTint="#color/white"
app:fabSize="normal"
app:layout_anchor="#+id/nestedScrollView"
app:layout_anchorGravity="top|center_horizontal"
app:srcCompat="#drawable/ic_launcher_background" />
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:background="#color/white"
android:layout_height="wrap_content">
////My Scrolling Content(Contains many edit texts so its size may vary)
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I have not done anything in MyActivity.kt file. Please help me out this. I have tried nearly all solutions in this community from last 15 days still no luck. Thanks!!
Edit: As Suggested I have updated the Question with NestedScrollView as direct child and posted Screenshot of Android Studio preview in which it is taking height which is crossing preview. It should take height according to the content.If I make NestedScrollView wrap_content then still it leaves empty space at bottom. In background I have Camera running so I have to make it match parent to make cover full height.
I have no particular solution to your problem, but I highly suggest you to embrace Motion Layout. I'm developing an app with a 'collapsing toolbar' too, and I wanted to do a parallax effect, just like in Spotify. It got really difficult using Coordinator Layout and Collapsing Toolbar, besides the documentation about it are not very extensive so honestly I didn't know what I was doing.
I researched online for other ways to do it and finally I found out about this. Motion Layout lets you tweek your animations to the very little details. I know that thinking of changing your whole layout from CoordinatorLayout to MotionLayout seems like a lot of work but it isn't. And if anything it's rewarding given that Motion Layout extends from Constraint Layout and you can animate every view of your layout (if your parent is Motion Layout). Another pro-ML argument is that you have animation listeners: for example when a transition is done, a method is called automatically and this way you can chain animations if you need to, it's really fun.
Check out some of the possible animations that you can build with Motion Layout. These come with the layouts xml and the animation xml so you can learn from these (great official documentation btw):
https://developer.android.com/training/constraint-layout/motionlayout/examples
This is the tutorial I used to imitate the behavior of the Collapsing Toolbar inside a Coordinator Layout:
https://blog.stylingandroid.com/motionlayout-collapsing-toolbar-part-1/
https://blog.stylingandroid.com/motionlayout-collapsing-toolbar-part-2/
(I personally just went through part1 then continued on my own)
First of all, there is no need for ConstraintLayout since you have the CoordinatorLayout. Also as mentioned by users in comments, NestedScrollView should be a direct child of CoordinatorLayout and not in the ConstraintLayout. In this way you designed, some behaviors might not work as expected and it's actually a wrong design.
I've made the changes and here is what you'd see in the preview:
UPDATED layout:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/topBlock"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapse_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#android:color/holo_blue_light"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:layout_scrollInterpolator="#android:anim/decelerate_interpolator">
<androidx.appcompat.widget.Toolbar
android:id="#+id/myToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme"
app:title="Your title" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="MyRandomText"
android:textColor="#android:color/black"
android:textSize="42sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#+id/view"
app:layout_constraintCircleRadius="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="20sp"
android:background="#android:color/holo_blue_light"
app:layout_constraintTop_toBottomOf="#id/title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="8dp"
android:src="#mipmap/ic_launcher"
app:backgroundTint="#color/white"
app:fabSize="normal"
app:layout_anchor="#+id/nestedScrollView"
app:layout_anchorGravity="top|center_horizontal" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
P.S: Please also remember that the NestedScrollView should have only one child as it's first child.
In this way which is the right way to do, you won't have to use kotlin-java codes to achieve scrolling or other behaviors, you'll be able to achieve the behaviors using flags and attributes like layout_scrollFlags and exitUntilCollapsed and the like.
I load a smiliar layout when my fragment starts:
<ScrollView
android:layout_height="wrap_content"
android:layout_width="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/firstView" />
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/secondView" />
</LinearLayout>
</ScrollView>
When the fragment starts I want my firstView to be (so to speak) hidden and when a user scrolls down it should move with secondView so it becomes visible.
Basically I would like my ScrollView to be started with negative position. The problem is I don't know the height of firstView.
Is it possible to define this behavior with xml attributes?
Regards,
roncsak
Well, it can be done with CollapsingToolbarLayout.
Material design spec: https://material.io/develop/android/components/collapsing-toolbar-layout/
I have tried to move the button using graphical interface and android:layout_alignParentLeft in XML file, anyway it does not work. My Android Studio version is 2.2.3. Have you ever had this problem?
You need RelativeLayout or other simlilar layout as parent container because FrameLayout just draw the views one over another plus you should check the properties section to see the attibute properties that you can apply on your layout.
To read further about ViewGroups and it's sub-types with their behaviours
If you forced to use FrameLayout(e.g in Toolbar or so) and you have only one element(or small amount) to operate with(button) you can use android:layout_gravity="" attribute to align element in the FrameLayout.
<FrameLayout
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
If you have have few elements in your layout, you can: 1) Change FrameLayout to RelativeLayout or 2)Wrap all items into Relative layout and set parameters to match_parent
<FrameLayout
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="#string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
</FrameLayout>
I have a dialog fragment that contains linear layout that involves a titleText above a RecyclerView, and at the very bottom, there's a button below the recyclerView.
Since a recyclerView expands or collapses based on the number of items the adapter sets, the button sometimes gets truncated and no longer appears to be on screen, since the recyclerView just covers the entire screen.
My question is, is there a way to set the maximum height of the recyclerView without ever hiding the button underneath. I also don't want to just give the view a random height just in case the recyclerView contains no items, and it would just be a blank section.
Please let me know if you've ever run into this issue, and how you resolved this. Thanks!
UPDATED
You can achieve this easily using layout weights. Here's an example:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Title"
android:textSize="21sp"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="30dp">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="Submit"/>
</FrameLayout>
The Title and RecyclerView will wrap content according to contents and button will always take up bottom place.
I suggest using RelativeLayout as it handles the positioning of views for cases like yours, so that you can actually focus on main design.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="Some title" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/title"
android:layout_above="#+id/button"/>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center"/>
</RelativeLayout>
Above XML code is the skeleton code for what you need. you can add margins and dimensions to control the spacing. But in any case (until you provide negative margins) your views will never overlap each other.
Main trick of using RelativeLayout is the ability to use XML tags like
android:layout_below or android:layout_above or android:layout_start
or android:layout_end which perfectly aligns your view the way you
want.
I have a CoordinatorLayout and inside it, two FloatingActionButton and below them a ScrollView.
The problem is that even though I can see my FloatingActionButtons on screen I cannot click them. I suspect that's because all onTouch events are being handled from ScrollView
Here is my layout xml (which is probably pretty bad so any tips are welcome):
<?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">
<!-- Note: that 80dp padding is:
main_padding + fab_size + 8dp = 80dp
16dp + 56dp + 8dp = 80dp
and it was the only way I could think to add padding
between my FABs
I tried to use app:layout_anchor but my 2
FABs had no padding between them... -->
<android.support.design.widget.FloatingActionButton
style="#style/RefreshFab"
android:id="#+id/fab_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="80dp"
android:layout_marginEnd="16dp"
app:fabSize="normal"
app:pressedTranslationZ="12dp"/>
<android.support.design.widget.FloatingActionButton
style="#style/SendFab"
android:id="#+id/fab_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
app:fabSize="normal"
app:elevation="6dp"
app:pressedTranslationZ="12dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Toolbar -->
<include
layout="#layout/view_toolbar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Much stuff here, text views, spinners etc.. -->
</LinearLayout>
</ScrollView>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
The problem is because each item is laid out in a CoordinatorLayout in the same order it is written in the xml. By that logic, the FloatingActionButtons are each placed on the screen and then the LinearLayout on top of them, so I would expect the click is being overriden by the LinearLayout.
Rearrange your XML to place the FloatingActionButtons last, so that they are 'on top', so to speak, of your layout. Then they will detect your click listeners just fine.
I think the problem will persist since each FloatingActionButton is wrapped inside of a FrameLayout with match_parent dimensions. I do not believe you need these FrameLayouts, but you can simply put the FloatingActionButtons inside of the CoordinatorLayout.