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
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
I have two RecyclerViews placed vertically in a LinearLayout. I need to make both of them scrollable and that is why I have put the LinearLayout inside NestedScrollView
This is the my layout file.
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/featured_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="#+id/all_topic_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Also, I am disabling nested scrolling in Java code.
disableNestedScrolling(findViewById(R.id.all_topic_list));
disableNestedScrolling(findViewById(R.id.featured_list));
My RecylerView library version is 26.1.0
This works fine perfectly, but then onBindViewHolder method is getting called for all the items in the list. Ideally it should only be called for the visible items in the list.
I think the issue is happening because I am giving wrap_content to the RecyclerView. A lot of answers on this question suggest that the issue is solved in v23.2.1, but I am already using v26.1.0. How to solve this issue?
I had exactly the same problem. RecyclerViews are not meant to be placed inside scroll containers with the same scroll direction. The view recycling only works when the height is set to MATCH_PARENT.
Depending on the complexity of the content inside of the NestedScrollView and the anticipated amount of RecyclerView items:
Ignore the problem. If there are only a few simple items, you may
not need view recycling at all.
When I hit the problem, I analysed the layouts of other popular apps: For example, WhatsApp only uses RecyclerViews (or ListViews with view recycling) in some parts of their app.
Particularly, this group settings screen with hundreds of possible items is made of multiple ListViews wrapped by a ScrollView, without any view recycling.
Replace the NestedScrollView with a single
ReyclerView with multiple item types and put all of your scrollable content inside of it. This is the way to go if you need view recycling.
Beware that you also have to convert all the other content in the NestedScrollView (headers and footers, spacing) to RecyclerView items with their own ViewHolders.
If the setup is rather simple, I would recommend you to implement it without additional libraries, following the link above.
There are a few different libraries available to solve your problem (all of them follow the second approach with a single RecyclerView), but most come with a lot of extra features which you may not need:
RendererRecyclerViewAdapter
It comes with a ViewRenderer/ViewModel interface, which works like a
"partial" RecyclerView for a single item type. You would create one
for every item type and then register them in a single adapter.
Epoxy
A library/framework create by airbnb and used heavily in their app.
They have a lot of scrollable content (similar to a web page) with a
lot of different item types. Epoxy also helps with the composition of
the different items on a page, and it handles animations when the
content or its order changes. Too much if you only need it for a single screen.
Litho
A complete UI framework created by Facebook which comes with it's own rendering engine, a replacement for xml layouts and much more. As far as I understand, it allows you to do to handle large amounts of items (like the Facebook timeline) and the view recycling is handled automatically. Like Epoxy, you would only use this if your app includes things like endless scrolling with a lot of different item types and you really need the performance.
I tried Epoxy and RendererRecyclerViewAdapter, but after all I created my own multiple item type adapter. It can be created in less than 100 lines of code.
Starting from RecyclerView:1.2.0-alpha04 we can use ConcatAdapter to solve this problem
https://developer.android.com/reference/androidx/recyclerview/widget/ConcatAdapter
I tried your problem by adding 20 items in each recyclerview, with NestedScrollView application called onBindViewHolder method 40 times. As you disabling nested scrolling in Java code i suggest to use Scrollview. By using ScrollView application called onBindViewHolder 33 times.
If you fix your recyclerView's height to specific size instead of "match-parent" it will reduce call to onBindViewHolder greatly.
<ScrollView 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:fillViewport="false">
<android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.vishal.my2.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/featured_list"
android:layout_width="match_parent"
android:layout_height="300dp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/all_topic_list"
android:layout_width="match_parent"
android:layout_height="300dp" />
</android.support.v7.widget.LinearLayoutCompat>
</ScrollView>
If Specifying hardcoded value to recyclerView's height does not meet your application requirement then you can try using ListView instead of recyclerView. pardon me if i am wrong, This was my first time answering any question.
Add this to nested scroll view android:fillViewport="false"
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.
Is there an easy way to switch between the displayed view in a ViewSwitcher in the Android Studio preview, or is the only way to swap out the XML for the sub-views one at a time?
Unfortunately, there are no XML attributes or any option on Android Studio which can help you to define the displayed view.
A similar question for the ViewFlipper was asked here (they both are direct subclasses of ViewAnimator).
However, if and only if your views are large as the screen, you could use the include tag, for example:
<ViewSwitcher
android:id="#+id/myViewSwitcher"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/first_view">
</include>
<include
layout="#layout/second_view">
</include>
</ViewSwitcher>
Then you can see your layouts in a separate XML file.
First of all if you are thinking to use ViewSwitcher, just for showing ProgressDialog then you are not doing it in a way in which it should be.
ViewSwitcher generally used to change layout of Activity. In your case ProgressDialog is not a View of your Activity rather it is just small helper which indicates some process is doing. So In short ViewSwitcher should be use somewhere where you want to alter complete screen of Activity.
In your case you can divide your layout into smaller layout files and group them using merge or include.
Create separate files for all different screens which will define UI of your Activity and group them using include.
For an example we can create small App for Introduction thing using ViewSwitcher -
First Screen - my_product.xml - this layout will define something about product.
Second Screen - about_us.xml - this layout will describe about your company.
Third Screen - thank_you.xml - to say thank you to your users.
Group them in any container View.
<ViewSwitcher
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/my_product"/>
<include
layout="#layout/about_us"/>
<include
layout="#layout/thank_you"/>
</ViewSwitcher>
ViewPager can easily solve your issues.
ViewPager (it can hold multiple views). ViewPager is kind of Array Container for View objects. You can have ViewPager rotation (like you do the array rotation) or other techniques to swap inside views. And, you can create your each inside views based on the Factory DP, so that there happens less processing (shares common resources).
They have mentioned swiping views here (Note: you just need own view swiping techniques if you don't want to use default ViewPager rotation).
Creating swipes: https://developer.android.com/training/implementing-navigation/lateral.html
ViewPager for screen slides: https://developer.android.com/training/animation/screen-slide.html
I want to use multiple ListView/GridView within same User Interface; I don't want them to be expanded to their full length and placed under ScrollView.
If you want to learn about ListView, here is a nice tutorial. About your question, here is the similar one! Your question might even be duplicate of this.
I don't think that putting multiple ListView/GridView objects inside ScrollView is a good idea.
The biggest advantage of ListView/GridView is that they reuse View's. When you scroll a ListView what the system really does is to use fixed number of views, and swaps the view settings (text, image source etc.). This is done by requesting the getView(int,View,ViewGroup) method from the list Adapter.
What you are trying to do is to force the ListView/GridView to render all it's raws, which pretty much beats the whole purpose of using ListView/GridView in the first place.
Use LinearLayout inside the ScrollView instead, and then add Views dynamically from your Activity/Fragment
Just specify dimensions to your ListView/GridView that are not all match_parent.
Also, if you want to proportionally allocate say 50% and 50% of available height to your list and grid, put them in a LinearLayout and use the layout_weight mechanism:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
... />
<GridView
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
... />
</LinearLayout>
you can set the layout to include how many listViews and gridViews as you wish. just choose a layout and set their sizes yourself. if you put them in a linearLayout, you can set a weight for each of them, to make their width/height proportional to the layout width/height.
However, do note that the more you put, the more cluttered the UI is.
Also note that Google suggests to never put listViews and gridViews inside ScrollViews (this was being talked about on the "the world of listView" lecture) .