I am adding custom views to a custom ArrayAdapter. The xml layout I am using looks like this
<LinearLayout>
<HorizontalScrollView>
<LinearLayout>
<TextView></TextView>
<TextView></TextView>
<TextView></TextView>
<TextView></TextView>
</LinearLayout>
</HorizontalScrollView>
<LinearLayout>
I then set the adapter for my AlertDialog.Builder as my custom ArrayAdapter and also supply the OnClickListener. My dialog shows fine and I am able to scroll the list vertically as well as scroll each view horizontally. However, when I click on any of the views it never fires the OnClickListener.
I have tried setting the top most LinearLayouts descendantFocusability="blocksDescendants" but that has no effect. Is there anyway to do this within the AlertDialog? I have tried even creating a custom Dialog that implements OnGestureListener but none of the gesture events ever get called either.
I'm not sure if I'm able to reproduce the same problem you're describing, though I can reproduce something similar. Perhaps if you were to post a more complete and working code example, it could help to replicate your problem.
At any rate, the solution might be to not register the child components to have onClickListeners, because when they have onClickListeners, the parents then don't receive the click events.
Related
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
I am developing an app on Android with this form :
<ScrollView>
<RelativeLayout>
<TextView/>
<RelativeLayout>
....
</RelativeLayout>
<gridLayout>
7 CheckBoxes
1 ImageButton
</gridLayout>
<LinearLayout>
many TextViews
</LinearLayout>
</RelativeLayout>
</ScrollView>
The ImageButton inside the gridLayout controls when some of the checkBoxes disappear (VISIBILITY->GONE) and when it's pressed (the ImageButton) the LinearLayout, which is just below it (the gridLayout), overlaps the gridLayout before it takes its final form. See the images below :
[1]: https://i.stack.imgur.com/K6aSc.png This is before the disappearance.
[2]: https://i.stack.imgur.com/nHqpj.png This happens during the disappearance.
EDIT: The problem happens because the View.GONEtakes some time to be performed visually, but the gridLayoutunderstands that it happens immediately, so it reserves the "empty" space right away. Only think I can figure out, is to set the View.INVISIBLE instead and resize the gridLayout manually. Is there a better way?
EDIT2 The problem is caused by animateLayoutChanges="true". Due to the animations, it take some time for the checkBoxes to disappear. Is there a way to force the linearLayout to "wait" for the effect of the animation to end?
Any ideas?
You can add a listener to your animation changes of animateLayoutChanges="true" and move the LinearLayout when the animation ends. More information in this thread - Listner
Also, you can try a combination of setAlpha(0) and setEnabled(false) on your checkboxes in which case gridLayout won't adjust the views again.
Hey Hey currently I am developing an application that contains a form, with some edittext fields, some checkboxes and a switch at the end. The layout looks like this:
<RelativeLayout>
<ScrollView>
<LinearLayout>
<LinearLayout>
<TextView></TextView>
<Checkbox></Checkbox>
</LinearLayout>
<LineraLayout>
<TextView></TextView>
<EditText></EditText>
</LinearLayout>
<LinearLayout>
<TextView></TextView>
<Switch></Switch>
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
So now, if I click the switch, the switch looses its focus and the scrollview scrolls to the first form element, the checkbox. I already tried to use the descendantFocusability attribute with "blocksDescendants" in the upper LinearLayout of the Switch, but it doesn't work.
Anyone got an idea how to solve this issue?
Okay, I was able to fix the problem by myself. I'm posting my solution, so that it could be helpful for other people who might have the same problem.
In my code there was a specific function, which calls the setVisibility(View.Visible) method for all my form elements (this is used in my project to display possible dependend form elements, that should only show up, when the user clicks on a checkbox or sth else).
If I click on the switch or a checkbox my code calls the setVisibility-Method for all the form elements, also for the Edittext. This requests the focus and so the scrollview scroll this element to the middle/focus of the screen.
I solved the problem by not calling the setVisibility method for objects, that are already visible.
Hopefully this could be helpful for someone else ;-)
I want to scroll the background in android. I have a scrollview which has many views. I need to implement a way wherein i need to scroll only the background while adding the views. I came across many forums but none of them are very clear. Please give an idea or references to implement it. To give more idea for what i am looking for is, Just consider a bike game wherein the background road image moves while riding the bike. I just need similar implementation while scrolling the screen.
Maybe you could do like this:
RelativeLayout as the parent
ScrollView with your image set as background
Then the other views, but outside of the ScrollView and inside of the RelativeLayout.
EDIT:
<RelativeLayout
android:id="#+id/relParent"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<OtherViews />
<ScrollView
android:id="#+id/scrlParent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/yourbackground">
</ScrollView>
</RelativeLayout>
I think that something like this might work. You see, the RelativeLayout is the parent. Then comes your other views, on the top of your ScrollView. Then, after your other views tag, comes the ScrollView, with only a background. I'm not sure if a background tag would work, so maybe you should remove the android:background="#drawable/yourbackground" and put an ImageView inside of the ScrollView.
I have a layout requirement like below,
Textview
TextView
ListView
Edit Text
Button
Since listview cannot fit in landscape, I want to have list view onwards (ie. listview, edittext and button) to be a scroll view.
I know listview cannot be used inside a scrollview, but is there a way to do that ?
Any working example will be appreciated.
99% of android developers think we should not use ListView inside a ScrollView because both are scrollbale views and only parent can be scrollable, so it wraps the ListView.
Its 100% correct. But we have to use tricks to avoid this and to achieve our requirements.
I found one trick in web, which is setting the height of ListView based on the list items. Just check the link below, you will get an example code to calculate the height of ListView to fit inside a ScollView.
Android ListView height calculation to fit in ScrollView
The problem with this code is the list view will be filled entire screen if more children are available.
You have to use below template to achieve solution to your requirement.
<ScrollView >
<LinearLayout vertical>
<TextView />
<TextView />
<ListView />
<EditText />
<Button />
</LinearLayout>
</ScrollView>
I saw one video on youtube, Android ListView inside a ScrollView which is showing we can limit the height of listview, can be scrollable and used inside a ScrollView. I don't know how the programmer achieved that.
I am also thinking to produce same result by avoiding above example code. I hope it may help you temporarily. Please let me know if you got solution.
The better solution for this kind of layout is that You should use relative layout and fix ur EditText and Button at the bottom of ur screen like i have in my list view(see the image below) so that you wont need to add ScrollView in ur layout.
Just do this
<ScrollView>
<LinearLayout>
<ListView>
</LinearLayout>
</ScrollView>
Then add your
EditText
Button
Sort of a round about way to do what you want to do without a scroll view.
Write a custom adapter for your ListView
Assume you have an array of n elements that you want to populate the ListView with and then the EditText and the Button. So number of elements will be n+2
In the getView for the position n+1 return a view which has an EditText box instead of the normal list item
For the n+2 position return a Button.
Don't try to wrap around a ListView with a ScrollView, you will need up with lot of issues.
Note: I have not tested this, not even sure if it will work. Do let me know if it works. :)