I am working as OEM developer where we are using common GUI library for all Applications. In our application we are extending that GUI library which carry ScrollView as base layout for my application. Now my team is planning to use constrain layout in Application. Can we use constrain layout inside Scroll View?
I converted linear layout into constrain layout using Android Design tool. But
scrolling is not working.
<ScrollView
style="#style/Body_ScrollView"
android:id="#+id/no_sim_layout">
<LinearLayout style="#style/Body.LinearLayout.No_Sim">
<-- All other child views are going here-->
</LinearLayout>
</ScrollView>
Want to convert into
<ScrollView
style="#style/Body_ScrollView"
android:id="#+id/no_sim_layout">
<ConstrainLayout style="#style/Body.LinearLayout.No_Sim">
<-- All other child views are going here-->
</ConstrainLayout>
</ScrollView>
Yes, definitely the Constraint-layout first understand this:
Intention of ConstraintLayout is to optimize and flatten the view hierarchy of your layouts by applying some rules to each view to avoid nesting.Which recommends of Relative-layout rules.
More-ever it provide dynamic view alignment property as constraints, baseline, chaining of views and many other which provide seamless flatten hierarchy. If we used Constraint in Scrollview, we dont need to manage each view property like weighing in LinearLayout and many others. It much more simple and directly obtained benefits from provided dependencies.
<ConstrintLayout>
<ScrollView>
<ConstrintLayout>
//Single ParentConstrain else child
</ConstrintLayout>
</ScrollView>
</ConstrintLayout>
If goes by other way, this make your complex XML code more hard to understand and is heavy to build UI based on weighing and position calculated at run time on machine.
Constraint are directly benefit from input dependencies.
<ConstrintLayout>
<ScrollView>
<LinearLayout>
//Many different view to manage view
</LinearLayout>
</ScrollView>
</ConstrintLayout>
Related
I've the following use case -
<ScrollView> // parent
<ContentView/> // content
</ScrollView>
I do not have any access to the parent ScrollView because the library only allows setting the content view. And it doesn't provide any API or reference to modify the attributes of the parent ScrollView. And the content of ContentView is arbitrary in a way that it can take recycler-view, list-view and any other views with scrolling effects.
Because I do not have access to the parent ScrollView, I can't change its property / attributes anyhow. This causes the issue will ill-behaved scrolling. This specially shows the problem when
<ScrollView>
<ContentView>
<LinearLayout orientation=horizonal>
<RecyclerView/>
<RecyclerView/>
</LinearLayout>
<ContentView>
<ScrollView
And this causes two recycler-views to scroll together, while I want individual recycler-view scroll independently.
I was thinking of a solution that I can build a container-view and the children of container-view are agnostic of its ScrollView parent. So that my recycler-views have no knowledge of its parent ScrollView.
Is there any way to implement such solution? Have you ever encountered such an issue and how did you fix it?
I'd like to create a Layout like this.
What is the best way to perform this?
There are several ways to do it, first and common step is define border around parent layout and define margin for child layouts. after that in second step you can use one of the following to achieve this.
you can use Linearayouts with orientation vertical and then by using weightsum and weights you can achieve this.
another approach is by using Relative. in relative layout you can provide other views position relating to other layout component position.
third approach is by using Constraint layouts, provide constraints and you will achieve this.
You can use this code to make that design:
<?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:weightSum="2"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#android:color/black"
android:layout_weight="0.4"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.6"></RelativeLayout>
</LinearLayout>
You can change values of layout_weight to change the rate.
Some of the ways to achieve this layout and a few a performance cautions with these are stated below:-
1.With a linear layouts using the weights parameters will cause a performance hit, as the it would cause the views to be measured twice before being layout.And we has a deeper heirarchy with linear layouts which again causes slow rendering.
With relative layouts , even though we get a flat heirarachy but the views are measured twice before drawn, again a nested relative layout (relative layout with in another relative layout) will cause the rendering time to increase as now, the view would be measured 4 times.
3.It would be better to use constraint layout to get the better performance with flater view heirarachy.
4.You might also want to consider using fragments if the inner layout has a menu structure causing changes in first child , with frame layout as the root parent.
A few links to understand about the performance benefits:-
Android Layout Tricks #1
Understanding the performance benefits of ConstraintLayout
tl;dr: How to achieve the layout shown in the screenshot below? Placing ListView to a ScrollView is apparently not recommended, but is there actually any other way to achieve it?
The whole question: I want to have multiple CardViews in my app, and one (or more) of them will have either RecyclerView or ListView in it (it doesn't really matter to me which one of those). The whole view is supposed to be scrollable - not only the ListViews in their parent CardViews. I basically need to achieve similar layout as the Play Store app has.
The first option I tried was this (the code is obviously simplified):
<LinearLayout android:orientation="vertical">
<CardView>
<!-- Some content of the first card. -->
</CardView>
<CardView>
<ListView/>
</CardView>
</LinearLayout>
The result was not what I wanted, the ListView was only scrollable in its parent CardView but the whole view wasn't scrollable like it is in the Play Store app. So now I wrapped it all in a ScrollView:
<ScrollView
android:fillViewport="true"
android:isScrollContainer="true">
<LinearLayout orientation="vertical">
<CardView>
<!-- Some content of the first card. -->
</CardView>
<CardView>
<ListView/>
</CardView>
</LinearLayout>
</ScrollView>
And I programmatically set the height of the bottom card to fit the ListView's height (number of elements in the ListView * height of one list item element). Now the whole view is scrollable, and the bottom card's height is the same as the height of the ListView, so the ListView isn't scrollable inside the CardView which is exactly what I wanted.
Now the actual problem: I got it working as described above, but I know this particular issue (ListView in a ScrollView) has been asked about many times before and the answer has always been the same - don't put neither RecyclerView nor ListView in a ScrollView because it causes performance problems. Well, so what's the correct approach then? How did Google do it in the Play Store app? I tried decompiling the Play Store app with APKTool but there weren't any layout files (maybe I did something wrong). Is my approach correct? My ListView will only display a few items (I guess it will be at most 20 items) - will it cause some performance issues in this case?
I wouldn't ask about this if all the answers wouldn't always mention that we shouldn't put ListView in a ScrollView. Is there any other way how to achieve the layout described by the screenshot above?
The first thing to address is why you're "not supposed to" use wrap_content on a ListView or a RecyclerView and put it in a scrollable container: it defeats the entire view-recycling purpose of these components.
What makes a ListView or RecyclerView better than a LinearLayout inside a ScrollView is that the system only needs to create enough views to display everying that fits inside the visible area. When you "scroll" the visible area, the views that disappear off one end can be re-used for the views that scroll into view from the other end. When you make your list/recycler wrap_content, this recycling is impossible, so you might as well just manually add your views to a LinearLayout instead.
That being said, RecyclerView does support using wrap_content... it just means you won't get view recycling. If this performance hit doesn't cause you problems, there's no objectively evil code here.
The only way to know for sure if the performance penalty is problematic or not is to just try it, test it, measure it, and decide for yourself. With 20 items, I suspect you have nothing to worry about.
The next thing to think about is the fact that Google has tons of resources and manpower and can afford to be extremely clever. Perhaps the Play Store app is as you say, with some sort of scrollable parent container that holds cards, each of which have some sort of adapter view within. But it's equally possible that they're doing something completely different, like using a single RecyclerView and "faking" the appearance of cards by using an ItemDecoration. Or perhaps they are using some sort of custom view subclass that the public doesn't have access to.
As for how you could recreate something similar, I suspect a hierarchy like this will work just fine:
<NestedScrollView>
<LinearLayout>
<CardView>
<RecyclerView/>
</CardView>
<CardView>
<RecyclerView/>
</CardView>
<CardView>
<RecyclerView/>
</CardView>
</LinearLayout>
</NestedScrollView>
I would recommend you to use Sectioned RecyclerView for this purpose. Every single item layout would have a cardView in it instead of creating a cardView as a parent.
Refer to this library: https://github.com/luizgrp/SectionedRecyclerViewAdapter
Suppose you have a FrameLayout containing 10 LinearLayouts, where only one is visible per time.
Each LinearLayout is a complex view, containing Button, EditText, TextView, etc.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/alice
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<!-- complex stuff -->
</LinearLayout>
<!-- many more linear layouts... -->
<LinearLayout
android:id="#+id/juliett
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<!-- last complex stuff -->
</LinearLayout>
</FrameLayout>
Thus:
Changing the LinearLayout visibility, in order to show another item, would be a huge performance issue?
Given it is an issue, why using ViewFlipper does not slow down the app performance?
It's bad practice because the code easily become a mess. Ignoring that and focusing only on performance, when you set the visibility to GONE, the view isn't measured (it's different from INVISIBLE). The view occupies a little bit of memory, though. Depending on what you're doing, consider using ViewGroup.removeView().
It's hard to say without a benchmark, but theoretically it shouldn't have performance issues.
This is not a good way to implement because each time you need to show another view, other views must be gone. So that, you are going to write duplicated lines of codes for it. Viewswitcher is better choice. So what about performance then? View switcher is going to measure all children views which make only draw inside of itself. This trick makes view switcher faster because it does not need to recalculate dimensions for itself unless you disable it to use heterogeneous children views.
İf your views are homogeneous, the best way is implement a custom view and giving a class to changing state. For example, you set Alice object to your custom view to show Alice's properties and changing it programmaticly up to your business logic.
Good luck
Emre
Seriously, you need to consider fragment for above situation.
why to inflate un-necessary views.
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.