I want to achieve Fig-1 but I am stuck with Fig-2 and not able to see full gridview as a header of Listview.
As you can see the gridview is not showing fully and hiding behind Listview in Fig-2
Gridview xml :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="#+id/gridview"
android:numColumns="2"
android:stretchMode="columnWidth"
android:cacheColorHint="#ffffffff"
android:gravity="center"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
Listview xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" >
<ListView
android:id="#+id/listview"
android:scrollbars="vertical"
android:background="#fff"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</RelativeLayout>
Fragment code :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view=inflater.inflate(R.layout.fragmentpage_layout, null);
listView=(ListView)view.findViewById(R.id.listview);
header=inflater.inflate(R.layout.gridview_layout,null);
gridView=(GridView)header.findViewById(R.id.gridview);
listView.addHeaderView(header);
gridViewAdapter=new CustomGridViewAdapter(getActivity(),images,toptexts, bottomtexts);
listViewAdapter=new CustomListViewAdapter(getActivity(),images,toptexts,bottomtexts);
gridView.setAdapter(gridViewAdapter);
listView.setAdapter(listViewAdapter);
return view;
}
Thanks In Advance.
Hey Guys I got my Answer using Gridview as a Header of Listview.
I just Calculated the Divider Height for Gridview using below method and it worked perfectly as I wanted.
public static void setDynamicHeightGridView(GridView mListView,String oddeven) {
ListAdapter mListAdapter = mListView.getAdapter();
if (mListAdapter == null) {
return;
}
int height = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(mListView.getWidth(), View.MeasureSpec.UNSPECIFIED);
for(int i = 0; i < mListAdapter.getCount(); i++){
View listItem = mListAdapter.getView(i, null, mListView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
height += listItem.getMeasuredHeight();
itemHeight=listItem.getMeasuredHeight()/3;
}
ViewGroup.LayoutParams params = mListView.getLayoutParams();
if(oddeven.equals("odd")){
if(mListAdapter.getCount()>=5){
int count=((mListAdapter.getCount()-5)/2) + 1;
params.height = ((height - (height / 3)) - (itemHeight * count)) + 20 + (count * 5);
}else{
params.height = height - (height / 3) + 20;
}
}else if(oddeven.equals("even")) {
params.height = height/2 + 20;
}
mListView.setLayoutParams(params);
mListView.requestLayout();
}
Edited :
Finally the Exact Answer :
For Even number of views set :
params.height = height/2 + 20;
For Odd number of Views set :
params.height = ((height - (height / 3)) - (itemHeight * count)) + 20 + (count * 5);
where :
I have used 5 as the number for comparision
bcoz after this value of Adapters Count the variation in the space between
gridview and listview is increasing with fixed values.
For the space before 5 is handled in the else part.
itemHeight is the incremental value with which the space is increasing
20 is the margin space between gridview and listview
(count x 5) is the value for managing the margin as the elements increases.
bcoz it was giving me double the space for Gridview height above Listview for Even number of views
and Gridview + half it's height space for Odd number of views
Hope It Helps :)
Try this way , Taking your Grid and List in single layout and using android:weightSum to differentiate so that it will be applicable in all devices ,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="3dp"
android:weightSum="2">
<GridView
android:id="#+id/gridview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:cacheColorHint="#ffffffff"
android:gravity="center"
android:numColumns="2"
android:stretchMode="columnWidth" />
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#fff"
android:scrollbars="vertical" />
</LinearLayout>
Fragment code :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view=inflater.inflate(R.layout.fragmentpage_layout, null);
listView=(ListView)view.findViewById(R.id.listview);
gridView=(GridView)header.findViewById(R.id.gridview);
//your code
gridView.setAdapter(gridViewAdapter);
listView.setAdapter(listViewAdapter);
return view;
}
OR
If you want the whole gridview to be displayed fully first and below it should be the listview and when you scroll the gridview should go upwards and the listview should follow it behind as in Fig-1
Checkout this Awesome-MaterialDesign library with simple explaination.As shown in below figure
try adding android:layout_marginTop="some_value" in the RelativeLayout of the ListView
When you want to inflate your GridLayout also reference your listView With something like this :
header = LayoutInflater.from(getActivity()).inflate(R.layout.your_header, mListView, false);
And one more things : pass your relativeLayout instead of your GrideLayout as header.
Related
Here I'm new to android development. Don't mind if something isn't clear.
I did enough research on this issue, before marking this as duplicate please update the solution.
Here I'm adding an image with arrangement of layouts what I want to implement here.
Here the listView is being shown as only 1 item. If I scroll, all the items will be scrolled in the shown in this height.
Here my xml structure is
<LinearLayout>(parent)
<ScrollView>
<LinearLayout>
<LinearLayout>
weight: __
-----------
</LinearLayout>
<ListView>
h:match_parent
w:wrap_content
weight:__
</ListView>
<LinearLayout>
weight:__
--------------
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
I'm getting numbers of data sets from DB and have to show those sets in middle of the both LinearLayouts. For now I'm using ListView but seems impossible to use here as my expectation.
Please suggest whether I can I perform in ListView here or how can I use numbers of LinearLayout blocks for each dataset?
Update
This is what I expect as shown in the pic.
Try this
<LinearLayout>(parent)
<NestedScrollView>
<LinearLayout>
<LinearLayout>
w:wrap_content
h:wrap_content
</LinearLayout>
<ListView>
w:match_p__arent
h:match_p__arent
weight:1
NestedScroll:true
</ListView>
<LinearLayout>
w:match_p__arent
h:match_p__arent
weight:1
</LinearLayout>
</LinearLayout>
</NestedScrollView>
</LinearLayout>
You need this method for your ListView
public static void setListViewHeightBasedOnItems(ListView target_Listview, int limit) // LIMIT 0 FOR SHOWING ALLL CONTENTS
{
if (limit == 0) {
ListAdapter listAdapter = target_Listview.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
// if(itemPos < 4)
// {
View item = listAdapter.getView(itemPos, null, target_Listview);
item.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Log.e("" + itemPos, "" + item.getMeasuredHeight());
totalItemsHeight += item.getMeasuredHeight();
// }
}
// Get total height of all item dividers.
int totalDividersHeight = target_Listview.getDividerHeight() * (numberOfItems - 1);
// Set list height.
ViewGroup.LayoutParams params = target_Listview.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight;
target_Listview.setLayoutParams(params);
target_Listview.requestLayout();
// return true;
}
else {
}
}
else {
ListAdapter listAdapter = target_Listview.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
if (itemPos < limit) {
View item = listAdapter.getView(itemPos, null, target_Listview);
item.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Log.e("" + itemPos, "" + item.getMeasuredHeight());
totalItemsHeight += item.getMeasuredHeight();
}
}
// Get total height of all item dividers.
int totalDividersHeight = target_Listview.getDividerHeight() * (numberOfItems - 1);
// Set list height.
ViewGroup.LayoutParams params = target_Listview.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight;
target_Listview.setLayoutParams(params);
target_Listview.requestLayout();
}
}
}
After setting adapter on ListView Just call the method and Pass your ListView in the parameters with your list size as second parameter.
One Suggestion from my side : You should use RecyclerView Instead of listview . Just need to write one line for that after setting up everything(adapter etc)
recyclerView.HasFixedSize();
Hope my answer will help.
Might need more clarification on what exactly it is you're trying to accomplish.
If the ListView is supposed to be longer and to scroll through more items on the list, I might recommend using the RecyclerView. Its a little bit more setup, but allows for a lot more complex layouts to be created based off the concept.
There are a lot of great references to learn the ways of RecyclerView if you want to search further:
this one might help you setup the solution to your problem
How to create RecyclerView with multiple view type?
Android Developer website tutorial for RecyclerView
https://developer.android.com/guide/topics/ui/layout/recyclerview.html
Post from Code Path that helped me supplement all of it together.
https://guides.codepath.com/android/using-the-recyclerview
try this way
<LinearLayout>
<LinearLayout>
<LinearLayout>
weight: __
-----------
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView>
h:match_parent
w:wrap_content
weight:__
</ListView>
</ScrollView>
<LinearLayout>
weight:__
--------------
</LinearLayout>
</LinearLayout>
I have tried in my Android studio and mine is working i am able to scroll view .mine is little bit deffrent then you.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorAccent">
<LinearLayout
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/colorAccent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:text="#string/hello" />
</LinearLayout>
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#color/black_overlay"
android:layout_below="#+id/first" />
<LinearLayout
android:id="#+id/second"
android:layout_width="match_parent"
android:layout_height="550dp"
android:background="#color/colorAccent"
android:layout_below="#+id/listview"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:text="#string/hello" />
</LinearLayout>
</RelativeLayout>
</ScrollView>
I have an activity which contains text and a fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context="bla.HomeActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="A Text"
android:id="#+id/home_text_view"/>
<fragment
android:name="bla.CalendarAgendaFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cf"
tools:layout="#layout/fragment_calendar_agenda" />
</LinearLayout>
</ScrollView>
</LinearLayout>
The fragment only contains a ListView which is filled dynamically:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/calendar_agenda_listview"
android:layout_gravity="center_horizontal" />
</LinearLayout>
The onCreateView method of the fragment looks like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_calendar_agenda, container, false);
agenda_dates = new ArrayList<CalendarDate>();
agenda_dates.add(new CalendarDate("10.10.2015", "Kuchen backen"));
agenda_dates.add(new CalendarDate("10.10.2015", "Fenster putzen"));
list = (ListView) v.findViewById(R.id.calendar_agenda_listview);
adapter = new AgendaAdapter(getActivity(), R.layout.calendar_agenda_listview_item, agenda_dates);
list.setAdapter(adapter);
return v;
}
The code works and both CalendarDates are added to the fragment.
The problem is that the fragment is only about 40dp high and so only the first ListView item is shown. I can only see the second item by inline scrolling inside of the list view. How can I set the fragment's hight according to it's content?
You can set the height programatically, as seen here
Function:
public static boolean setListViewHeightBasedOnItems(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems, itemPos++) {
View item = listAdapter.getView(itemPos, null, listView);
item.measure(0, 0);
totalItemsHeight += item.getMeasuredHeight();
}
// Get total height of all item dividers.
int totalDividersHeight = listView.getDividerHeight() *
(numberOfItems - 1);
// Set list height.
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight;
listView.setLayoutParams(params);
listView.requestLayout();
return true;
} else {
return false;
}
}
The problem is that the ListView doesn't work correctly with wrap_content.
See this question about it:
Android: wrap_content is not working with ListView
You should change the size of your ListView programmatically, as Rafael suggested.
I have a horizontal scroll view containing a linear layout.
Something like this:
<HorizontalScrollView
android:fillViewport="true"
android:id="#+id/product_hsv"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:measureAllChildren="false"
android:scrollbars="none">
<LinearLayout
android:id="#+id/product_container_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal" />
</HorizontalScrollView>
What I want to do is to add n number of the same layout to display
product collection in a Horizontal scroll view.
The picture below will give you an idea of what I have done so far.
For this, I have added product collection view to R.id.product_container_layout.
String[] productCollectionArr = new String[]{"Shirt", "Jewellary", "Moto X Play", "Ellis Flat"};
for (int i = 0; i < productCollectionArr.length; i++) {
LinearLayout parentLayout = (LinearLayout) findViewById(R.id.product_container_layout);
View child = getLayoutInflater().inflate(R.layout.item_product, null);//child.xml
parentLayout.addView(child);
}
for (int i = 0; i < productCollectionArr.length; i++) {
LinearLayout eachProductLayout = (LinearLayout) findViewById(R.id.product_container_layout);
((TextView) eachProductLayout.findViewById(R.id.product_name_tv)).setText(productCollectionArr[i]);
}
But the problem is passing values. Since each view added to product_container_layout has the same ids. Therefore only first element gets the value from the product collection array.
What I can do is generate view id for each view and its element and map these ids to certain name so that I could access them by id.
Is this the correct methodology or should I do something else?.
You need to add this first :
<HorizontalScrollView
android:id="#+id/galleryImages"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/chim_image_view_divider"
android:layout_marginTop="#dimen/twenty"
android:focusable="false"
android:layout_centerInParent="true"
android:focusableInTouchMode="false"
android:scrollbars="none" >
<LinearLayout
android:id="#+id/Images_scroller_view_linear_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
</LinearLayout>
</HorizontalScrollView>
ImageScrollerViewLinearLayout = (LinearLayout) findViewById(R.id.Images_scroller_view_linear_layout);
ImageScrollerViewLinearLayout.removeAllViews();
- addImagesTo list:
void addImages() {
ImageScrollerViewLinearLayout.removeAllViews();
int i = 0;
final float scale = this.getResources().getDisplayMetrics().density;
int pixels = 0;
if (myImagesList != null && myImagesList.size() > 0) {
for (i = 0; i < myImagesList.size(); i++) {
ImageView imageView = new ImageView(this);
pixels = (int) (60 * scale + 0.5f);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(pixels, pixels);
params.setMargins(5, 0, 0, 0);
imageView.setLayoutParams(params);
imageView.setScaleType(ScaleType.CENTER_CROP);
imageView.setOnClickListener(new SelectNewSingleImageClickListener());
imageView.setImageResource(myImagesList.get(i));
ImageScrollerViewLinearLayout.addView(imageView, i);
}
}
}
So, you need to populate your view before adding to container or save links to all items. It will looks like this:
LinearLayout parentLayout=(LinearLayout)findViewById(R.id.linearLayout1);
for (int i = 0; i < items.size(); i ++) {
View child = getLayoutInflater().inflate(R.layout.item_grid, null);//child.xml
((TextView) child.findViewById(R.id.name)).setText(items.get(i).getName(); // where R.id.name is a textView in your child.xml layout.
parentLayout.addView(child);
}
after all, you can access to your elements by index, if you want to change it:
parentLayout.getChildAt(index)
But if you have a lot of items, it's not good idea. In this case you will not recycle your views and will consume a lot of memory.
I suggest to use recyclerview from support library.
add code in xml file
<org.lucasr.twowayview.TwoWayView
android:id="#+id/lvItems"
style="#style/TwoWayView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="#+id/linearLayout3"
android:cacheColorHint="#android:color/transparent"
android:divider="#android:color/transparent"
android:drawSelectorOnTop="false"
android:padding="10dp" >
</org.lucasr.twowayview.TwoWayView>
You can use **DevSmart** library for horizontal listview which is similar to **ListView**.
https://github.com/dinocore1/DevsmartLib-Android
Basically I need to have some content that is dynamically available through an adapter to populate the header of my expandableListView, this must be possible but it's been a really hard time finding any resources on this issue.
Here is a representation of what I'm looking to do.
Yes, but you'll need to override onGlobalLayout(), and set a height for the listView in the header e.g.
final ExpandableListView lExpView = (ExpandableListView) view.findViewById(R.id.expandable_list);
View viewHdr = getActivity().getLayoutInflater().inflate(R.layout.pager_header, lExpView, false);
final ListView lView = (ListView) viewHdr.findViewById(R.id.item_hdr_list);
...
lView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
if (lView.getVisibility() == View.VISIBLE) adjustTotalHeightOfListView(lView, lExpView);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
lExpView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
else
lExpView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
Where adjustTotalHeightOfListView() is a method of your own devising that can calculate and set the height of your listView, while contained in the header of the expandable list view. If the individual items in the listView can be more than one Text line in height (wider than the expandable list views width and you have WRAP_CONTENT set) this get's a bit complex, as the actual width of the containing ExpandableListView won't be available till it's rendered, but we need at least a guess before to allow this to happen. So you'll want some code that looks a bit like (not tested):
if (listView == null) return;
ListAdapter mAdapter = listView.getAdapter();
if (mAdapter == null) return;
int totalHeight = listView.getPaddingBottom() + listView.getPaddingTop();
int viewWidth = ( parent == null || parent.getWidth() <= 0 )
? listView.getWidth()
: parent.getWidth();
....
for (int i = 0; i < mAdapter.getCount(); i++) {
View mView = mAdapter.getView(i, null, listView);
mView.measure(
View.MeasureSpec.makeMeasureSpec(viewWidth, (viewWidth > 0)
? View.MeasureSpec.AT_MOST
: View.MeasureSpec.UNSPECIFIED
),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
);
totalHeight += mView.getMeasuredHeight() + listView.getDividerHeight();
}
....
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight;
listView.setLayoutParams(params);
listView.requestLayout();
Note: The ? View.MeasureSpec.AT_MOST : View.MeasureSpec.UNSPECIFIED hack in the measure() statement, essentially it's there to cope with a call being made before the parent view has been expanded / had a width set. If a width has been set don't exceed it, so if WRAP_CONTENT is specified and the width is greater than the parent the height will be adjusted, else assume you can be as wide as the content.
Where: pager_header.xml
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ListView
android:id="#+id/item_hdr_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
</GridLayout>
and the main layout contains:
<?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:orientation="vertical"
android:gravity="center">
<ExpandableListView
android:id="#+id/expandable_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:paddingBottom="10dp" />
</LinearLayout>
I encountered a problem when embedding a ListView inside a ScrollView, or at least that's where I guess the problem comes from. The ListView element is a fairly simple one:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/general_background_list_middle"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingRight="0dp"
android:paddingLeft="0dp">
<ImageView
android:id="#+id/chat_friends_avatar"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_marginLeft="7dp"
android:layout_marginRight="8dp"
android:paddingRight="0dp"
android:paddingLeft="0dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/friends_icon_avatar_default"/>
<TextView
android:id="#+id/chat_message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/chat_friends_avatar"
android:layout_alignParentTop="true"
android:layout_marginRight="35dp"
android:maxLines="10"
android:textSize="12dp"/>
<TextView
android:id="#+id/chat_friend_name"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
style="#style/SubText"
android:layout_toRightOf="#id/chat_friends_avatar"
android:layout_below="#id/chat_message_text" />
<TextView
android:id="#+id/chat_message_time"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="3dp"
style="#style/SubText"
android:layout_alignParentRight="true"
android:layout_below="#id/chat_message_text" />
</RelativeLayout>
However, when I embed a list of such elements in a ScrollView, in between some other elements, the rows are not fully displayed, they are clipped (see image below) if the text is wrapped. The ListView is instantiated as follows in the ScrollView:
<ListView
android:id="#+id/info_chat_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:cacheColorHint="#color/frame_background_color"
android:clickable="false"
android:divider="#null"
android:footerDividersEnabled="false"
android:focusable="false" >
</ListView>
If the height of the ListView is set to "wrap_content" only the first element is shown. That's why I'm using a method to calculate the height of the rows of the list:
private int getCommentsListHeight() {
if (mChatAdapter != null && mChatAdapter.getCount() != 0) {
if (mChatList != null) {// && mCommentsListItemHeight == 0) {
mCommentsListItemHeight = 0;
for (int i = 0; i < mChatAdapter.getCount(); i++) {
// Get view item height
View viewItem = mChatAdapter
.getView(i, new View(OnAirActivity.this), mChatList);
viewItem.measure(0, 0);
Logger.d(LOGTAG, "View " + i + " measured height = " + viewItem.getMeasuredHeight());
mCommentsListItemHeight += viewItem.getMeasuredHeight();
}
}
//return mChatAdapter.getCount() * mCommentsListItemHeight;
return mCommentsListItemHeight;
} else {
return 0;
}
}
Unfortunately, in case when the text inside the TextView is wrapped, even over several lines, the height of the row element returned by the getMeasuredHeight() method is constant. Also the getLineCount() called on the TextView inside the row element returns 1 even if the text is wrapped.
On the other hand, if this ListView is embedded in a LinearLayout, everything works fine and the full list is displayed with no clipping.
Do you have any suggestions as to what might be wrong here? I really don't like the idea of manually measuring the height of the list elements and it apparently doesn't work but why can't android nicely stretch the ListView inside the ScrollView to fit it all in there?
Clipped list:
Use this method created by https://stackoverflow.com/users/205192/dougw
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
It's a BAD practice to encapsulate ListView within a ScrollView because ListView itself contains scrolling capabilities. You should implement a solution that does not contain such hierarchy of views and I hope it will do the magic :)
Here resource of main layout with ScrollView:
<ScrollView android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="#+id/parentLayout"/>
</ScrollView>
Here the code to insert items:
parentLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = comments.size() - 1; i >= 0; i--) {
CommentInfo comment = comments.get(i);
View view = inflater.inflate(your_resource_id, null, false);
TextView commentsContent =(TextView)view.findViewById(R.id.commentContent);
if (commentsContent != null) {
String data = String.format("%s (by %s, %s)", comment.getCommentText(), comment.getUserName(),
commentsContent.setTextSize(st.getTextSize());
commentsContent.setText(data);
}
parentLayout.addView(view, 0);
}
I had the same problem in my project.You need to create simple LinearLayout inside ScrollView. After that you need create new View with your listview item xml using LayoutInflater. After creation put all data in new View and add to LinearLayout as child view:
linearLayot.addView(newView, position_you_need).
Hope it would help you!
I took the recommendation of not using a ListView element inside a ScrollView to heart and decided to use a slightly brute force method to achieve what I need. Since there is a constant number of up to five list rows that need to be displayed I removed the ListView instantiation from the xml file and replaced it with five instances of rows:
<include android:id="#+id/info_comment_1" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_2" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_3" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_4" layout="#layout/chat_single_message" />
<include android:id="#+id/info_comment_5" layout="#layout/chat_single_message" />
In the Activity class I declare five placeholders for these views:
private RelativeLayout mChatMessages[] = new RelativeLayout[COMMENTS_NUMBER];
and initialize them with:
mChatMessages[0] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_1);
mChatMessages[1] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_2);
mChatMessages[2] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_3);
mChatMessages[3] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_4);
mChatMessages[4] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_5);
Then, whenever a new message is received I use the ChatAdapter (the same I used for the ListView previously) and call its getView() method:
protected void updateChatMessages() {
int msgCount = mChatAdapter.getCount();
for (int i = 0; i < COMMENTS_NUMBER; i++) {
if (msgCount <= i) {
mChatMessages[i].setVisibility(View.GONE);
} else {
mChatMessages[i] = (RelativeLayout) mChatAdapter.getView(i, mChatMessages[i], null);
mChatMessages[i].setVisibility(View.VISIBLE);
}
}
}
I don't inflate the pariculat views ever again since the only thing that changes is the content of each row, not the layout. This means there is no performance penalty here.
This is basically a manual implementation of a ListView with a limited maximum number of elements. This time, however, ScrollView is able to fit them nicely and nothing gets clipped.
For a dynamic number of rows the approach suggested by Layko could be employed with the views being instantiated programatically and added to the LinearLayout inside the ScrollView.
I can see the ListView is inside a ViewPager; one other simple approach to resolving this issue is to add
app:layout_behavior="#string/appbar_scrolling_view_behavior" to the ViewPager in your layout xml as seen below.
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
To prevent the same behavior at the bottom of the list, you can also add android:layout_marginBottom="?attr/actionBarSize" to the ViewPager like so
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginBottom="?attr/actionBarSize"/>
This is coming late, but I hope it helps any other person.
try it..
after create all view add bellow line for ScrollView location on screen (x,y)
ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);
scrollView.smoothScrollTo(0,0);// top location zero index
I had a similar problem. I have a
RelativeLayout
listView
includeLayout
where I include some bottom nav beneath the listView with this
<include
android:id="#+id/includeLayout"
layout="#layout/bottom_nav_bar"
and my listView was clipped - not taking the full height available between the header and bottom nav. I tried various xml settings suggested in this and other threads, but what worked for me was to add
android:layout_alignBottom="#+id/includeLayout"
to my listView. That seemed to pull the listView down to the top of the bottom nav, so that the listView is now using the full available height (and it scrolls as needed).
This works for me
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/activity_vertical_margin">
<TextView
android:id="#+id/tv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="17sp"
android:text="#string/text_list_devices" />
<ListView
android:id="#+id/lv_paired"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:cacheColorHint="#00000000"
android:layout_above="#+id/signup_t"
android:layout_below="#id/tv_status"
/>
<Button
android:id="#+id/signup_t"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="#android:color/white"
android:layout_alignParentBottom="true"
android:text="Print All Records"
android:typeface="sans"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:textSize="24sp"
android:background="#drawable/selector_for_button"
android:textStyle="bold" />
</RelativeLayout>
This is BAD practice. But there are some situations we can not avoid using that. For example dynamic e-commerce layouts we may put multiple lists or recycle views but you don't want to scroll inside a single item height (if accidentally wanted!!). I faced this kind of problem. I fixed using a simple way. I don't tell this is the correct way but it may help some.
!! I used to recycle the view.
(01) Create an Interface to return view height.
public interface AfterViewLoadListener {
void onViewHeightMeasured(int height, String mode);
}
(02) implement with your activity
public class *Activity extends AppCompatActivity implements AfterViewLoadListener{
/** your codes **/
final SimpleListRecycleAdapter order_adapter = new SimpleListRecycleAdapter(this,"ORDER");
}
#Override
public void onViewHeightMeasured(int height, String mode) {
if(mode.equals("ORDER") && height > 0){
recycleView.setMinimumHeight(height);
}
}
(03) inside the recycle view custom adapter
AfterViewLoadListener viewLoadListener = null;
public SimpleListRecycleAdapter(AfterViewLoadListener listener, String mode) {
if(listener instanceof AfterViewLoadListener){
viewLoadListener = listener;
}
this.mode = mode;
}
(04) override the onViewAttachedToWindow method
#Override
public void onViewAttachedToWindow(#NonNull SimpleListViewHolder holder) {
super.onViewAttachedToWindow(holder);
View view = holder.itemView;
view.measure(0, 0);
this.viewMinHeight = view.getMeasuredHeight();
if(!firstFlag){
firstFlag = true;
viewLoadListener.onViewHeightMeasured(this.viewMinHeight*filtered.length(),mode);
}
}
(05) That's it. It worked for me.