I am working on an android app which interacts with Twitter using their search API.
Everythings works well except that when I want to show the result using a ListView, only the first result is shown.
ArrayList<TwitterJSONResults> arrayList = new ArrayList<TwitterJSONResults>(data.getResults().size());
for (int i = 0; i < data.getResults().size(); i++) {
arrayList.add(data.getResults().get(i));
}
ArrayAdapter<TwitterJSONResults> resultAdapter = new ArrayAdapter<TwitterJSONResults>(
this, android.R.layout.simple_list_item_1, arrayList);
listview.setAdapter(resultAdapter);
resultAdapter.notifyDataSetChanged();
The code snippet above show how I add the results to the adapter and set this adapter to the the listview, What am I doing wrong?
Don't put ListView inside of a ScrollView :)
You can use ListView in ScrollView.
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
}
Call this function right after you change ListView items, like that:
Utility.setListViewHeightBasedOnChildren(myListView);
Read source.
Thanks to #207 I realized that the problem in my case was because I was using NestedScrollView, so for me the solution was used
android:fillViewport="true"
Here my code:
<android.support.v4.widget.NestedScrollView
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</android.support.v4.widget.NestedScrollView>
I have had this error like you when put listview inside ScrollView. And my solution is following as:
1. Create a custom listview which is non scrollable
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
2. Use above custom class for xml file
<xx.xx.NonScrollListView
android:id="#+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</xx.xx.NonScrollListView>
It worked well on all OS-version for me.
Hope best for you.
It turns out I had everything in my java code working perfectly. the issue was that was using the listview inside a scrollview which is generally a bad idea. It led to listview ignoring
android:layout="wrap_content"
therefore the content was there, it just was not showing. After I remove the scrollview from my XML file, everything worked file.
Big thanks to 207 for the support :)
You can use a ListView inside a NestedScrollView.
The only thing you have to remember is to add android:nestedScrollingEnabled="true" in the xml layout in order to enable the scroll of NestedScrollView's children.
Put it in ListView xml layout
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
this is my answere
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/listViewRefeCalendarDay" />
</android.support.v4.widget.NestedScrollView>
Related
I have two tabs inside a ViewPager and each tab contains a RecyclerView which are basically vertical ListViews. My problem is I can't scroll RecyclerViews vertically.
<com.myapplication.MyViewPager
android:layout_below="#+id/music_tabs"
android:id="#+id/music_switcher"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_featured_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_device_music"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.myapplication.MyViewPager>
Here is MyViewPager
public class MyViewPager extends ViewPager {
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for(int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if(h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
It seems my onMeasure method was causing the problem. After deleting it, problem solved.
You can't measure size of recyclerview beforehand. As expected after deleting onMeasure it should work.
As you are using the two recycleview and there layout height is wrap content instead of use this code or define layout_height in dp:
android:layout_height="250dp"
How do I keep gridView from needing to scroll by auto adjusting it's height? I would like all items, no matter how many items I add to the gridView to remain on screen without scrolling. Is this possible?
Here is my UI so far.
<?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:background="#drawable/bg"
android:orientation="vertical">
<GridView
android:id="#+id/gv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/tv_header"
android:fadingEdge="none"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center"
android:listSelector="#00000000"
android:numColumns="auto_fit"
android:stretchMode="columnWidth" />
</LinearLayout>
I did try adding a weightSum to the root and weight to gridView but it still requires scrolling.
Update: I also tried using a custom gridview. This did not work, but here is my attempt anyway.
public class CustomGridView extends GridView {
public CustomGridView(Context context) {
super(context);
}
public CustomGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
getLayoutParams().height = getMeasuredHeight();
}
}
Thanks in advance!
I have found answer to this. You can set the height of each item in the adapter by using
view.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, resizeValue));
resizeValue is the size that you want to adjust your rows to. To get resizeValue you can pass to the adapter mResizeValue based on the calculations relative to your device screen size. Something like
resizevalue = this.getResources().getDisplayMetrics().heightPixels / (NUM_COLS);
I figured out some other ways of calculating the height of each row based on screen size and then doing something similar, however, this requires that you do these calculations after you set your adapter and then update the changes to the adapter. It seems less efficient but I will share that methodology as well.
private void resizeGridView(GridView gridView, int items, int columns) {
ViewGroup.LayoutParams params = gridView.getLayoutParams();
int oneRowHeight = gridView.getHeight();
int rows = (int) (items / columns);
params.height = oneRowHeight * rows;
gridView.setLayoutParams(params);
}
Then after you set your adapter use
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new
ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!gridViewResized) {
gridViewResized = true;
resizeGridView(gridView, numItems, numColumns);
}
}
});
I have a CustomViewPager inside an ObservableScrollView which looks like this:
It seems to measure the fragment but does not measure the height of the fragment which is off the screen. So I can't actually scroll up.
This is the code for the CustomViewPager:
public class CustomViewPager extends ViewPager {
private View view;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
View tab = getChildAt(getCurrentItem());
int width = getMeasuredWidth();
int tabHeight = tab.getMeasuredHeight();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
NOTE: If I add say + 1000 to heightMeasureSpec in super.onMeasure(widthMeasureSpec, heightMeasureSpec); then I can scroll the size of the fragment as well as any extra space. But obviously this is not a preferred solution.
Here is my XML file:
<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">
<LinearLayout
android:id="#+id/infoBox"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="240dp">
<!-- Code for other views -->
</LinearLayout>
<com.github.ksoichiro.android.observablescrollview.ObservableScrollView
android:id="#+id/scrollView"
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:layout_marginTop="266dp"
android:orientation="vertical">
<com.ui.customviewpager.CustomViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.github.ksoichiro.android.observablescrollview.ObservableScrollView>
What seems to be the issue here? It seems like I am not the only one with this issue.
I implemented some of this design from this link here
ScrollView child should not have margin for the scrollView to display properly.
It seems that the margin is not taken into account when the scrollView measure its child.
Try removing margin of LinearLayout (you can use padding to reproduce the effect).
Why dont you use ObservableScrollView inside the fragment and put the viewpager inside a TouchInterceptionFrameLayout (from the same lib), then set setTouchInterceptionViewGroup of the ObservableScrollView to be the one containing your viewpager and do the logic on the TouchInterceptionListener in your activity to either move it up and down with with animation in order to mimic a smooth scrolling effect.
I hope that is that your are looking for to achieve and hopefully it will help you.
Ps: See the guy example app and source (Link), it is a bit complex but im sure you will find something.
Hello i am not much aware of ObservableScrollView but according to your problem you are not able to find out height of fragment. After searching a lot i am able to find out tutorial to get the height of fragments.
here is the link
http://adanware.blogspot.in/2012/06/android-getting-measuring-fragment.html
Hope, this will help you.
I used custom listview . Content comes from dynamic I want to same listview height same as content.
I used wrap_content but this does not help If I remove scrollview then its work
Code. "The vertically scrolling ScrollView should not contain another vertically scrolling widget (ListView)"
<ScrollView 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"
android:background="#drawable/background_img"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/lstsemtrack"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#f2e4e4"
android:dividerHeight="1dip"
>
</ListView>
Item list
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dip"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="4" >
<TextView
android:id="#+id/txtBiology"
style="#style/sem_rowtext"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="5dip"
android:layout_weight="1"
android:text="Biology" />
<TextView
android:id="#+id/txtClass"
style="#style/sem_rowtext"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Biology - 101" />
<TextView
android:id="#+id/txtGrade"
style="#style/sem_rowtext"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Grade" />
<TextView
android:id="#+id/txtGrade"
style="#style/sem_rowtext"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Remove" />
</LinearLayout>
</LinearLayout>
output like below I want same as content no scrollview
Use this code
public class MyListView extends ListView {
public MyListView (Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView (Context context) {
super(context);
}
public MyListView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
You shouldn't put a ListView inside a ScrollView because ListView itself is a view group that displays a list of scrollable items. If you use it inside scrollview it will not receive scroll events because they all are handled by the parent ScrollView. Using a ListView to make it not scroll is extremely expensive and goes against the whole purpose of ListView. You should NOT do this. Just use a LinearLayout instead.
However, if you really want to do this you can have a look at this: How can I put a ListView into a ScrollView without it collapsing?
In your parent layout set the height to wrap_content. This should work.
Other suggestions will not work, because there is no way to determine the height of the content of the ListView until after it's drawn into the screen (unless of course you have a fixed height, then use that as your ListView's height also).
What you can do is set the ListView's height AFTER drawing the elements inside it. You can do this in onWindowFocusChanged in your activity. As an example:
public void onWindowFocusChanged(boolean hasFocus) {
// get content height
int contentHeight = listView.getChildAt(0).getHeight();
// set listview height
LayoutParams lp = listView.getLayoutParams();
lp.height = contentHeight;
listView.setLayoutParams(lp);
}
Use Own Custom ListView
Create a class CustomListView.java and extend ListView like this..
public class CustomListView extends ListView {
private android.view.ViewGroup.LayoutParams params;
private int prevCount = 0;
public CustomListView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas)
{
if (getCount() != prevCount)
{
int height = getChildAt(0).getHeight() + 1 ;
prevCount = getCount();
params = getLayoutParams();
params.height = getCount() * height;
setLayoutParams(params);
}
super.onDraw(canvas);
}
}
Then use it in xml
<yourPackageName.CustomListView
android:id="#+id/lstsemtrack"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="#f2e4e4"
android:dividerHeight="1dip">
</yourPackageName.ListView>
As noted by Permita you should not have a ListView in a Scrollview. You should use for example a LinearLayout instead.
In some cases you have already made custom adapters you want to reuse. In that case these code snippets may be useful.
Old view:
...
<ListView android:id="#+id/myListView" ... />
...
New view:
...
<LinearLayout
android:orientation="vertical"
android:id="#+id/myLinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
...
Old code: (in dialog/fragment/activity)
YourAdapter listAdapter;
...
ListView listView = (ListView)rootView.findViewById(R.id.myListView);
...
if (listView != null) {
if (listAdapter == null) {
listAdapter = new YourAdapter(...);
listView.setAdapter(listAdapter);
} else {
listAdapter.notifyDataSetChanged();
}
}
New code: (doing some "listview"-stuff ourselves, to reuse views if possible)
YourAdapter listAdapter;
...
LinearLayout linearLayout = (LinearLayout) rootView.findViewById(R.id.myLinearLayout);
...
if (linearLayout != null) {
if (listAdapter == null) listAdapter = new YourAdapter(...);
for (int pos = 0; pos < listAdapter.getCount(); pos++) {
View existingView = linearLayout.getChildAt(pos);
if (existingView != null) listAdapter.getView(pos, existingView, linearLayout);
else linearLayout.addView(listAdapter.getView(pos, null, linearLayout));
}
while (linearLayout.getChildCount() > listAdapter.getCount()) linearLayout.removeViewAt(listAdapter.getCount());
}
UPDATE:
Or just add this to your adapter and call it instead of setAdapter on the list view and and notifyDataUpdated on the adapter:
public void updateOnLinearView(ViewGroup parentView) {
// Note reusing child views if there are any
for (int pos = 0; pos < getCount(); pos++) {
View existingView = parentView.getChildAt(pos);
if (existingView != null) getView(pos, existingView, parentView);
else parentView.addView(getView(pos, null, parentView));
}
while (parentView.getChildCount() > getCount())
parentView.removeViewAt(getCount());
}
couple of things to note here..
Do not use ListView inside the ScrollView
You will need to dynamically calculate the listView items to get the height for it.
Here is a function to do that..
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if (listItem instanceof ViewGroup)
listItem.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
You will need to call the same in
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
setListViewHeightBasedOnChildren(listview)
}
try wrapping your list view with a LinearLayout and set the LinearLayout's height to wrap_content.
The problem is the "ListView" inside "ScrollView"
ListView have already an automatic scroll, so you can delete it
Use android:layout_height="match_parent", it will work I think.
To increase the listview height, I am using exbandable ListView as,
public class ExpandableListView extends ListView {
private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;
public ExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);
System.out.println("params h "+params.height+" "+params);
setLayoutParams(params);
}
super.onDraw(canvas);
}
}
layout.xml as,
<com.jems.realtimedata.ExpandableListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="25dp"
android:background="#color/list_back"
android:cacheColorHint="#00000000"
android:divider="#drawable/line"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:paddingTop="10dp"
android:scrollbars="none" />
But,last item of list not displaying properly. I used utility class also,but no change in list.Any other solution to extend the view.Please help me to solve this issues.
change line
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);
to this:
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() + 1 : 0);
this only works for a list with single-line items.
This question is already posted.So have a look at this, and you can customize it according to your need in Expandable list
This link will help you:
How to change ListView height dynamically in Android?