Adding Empty Space to End of ListView - android

I have a ListView that with alphabetical headers for each letter. I also have an index function that brings the letter headers to the top of the screen.
My problem is when I reach the end of the list setSelection is unable to bring the last few headers to the top because it will not scroll past the end of the list.
My question is this: Is there a way to add a blank space to the end of the screen dependent on screen size? I would like to scroll until the last item in the list is at the top of the listView.

The easiest way to add space is to add padding in xml and set clipToPadding:"false".
For RecyclerView
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:clipToPadding="false"/>
For ListView
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:clipToPadding="false"/>
And same goes for the ScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:clipToPadding="false"/>
This specifically adds the blank space to top and bottom but hide the space when you scroll the view.

Try the followings:
View footer = new View(getActivity());
footer.setLayoutParams( new AbsListView.LayoutParams( LayoutParams.FILL_PARENT, 100 ));
mListView.addFooterView(footer, null, false);

I'm assuming you are using an extension of BaseAdapter to populate your ListView?
There may be a built-in way to do what you are asking, but I don't know of one. If you end up creating it yourself, how about this approach:
Return list.size() + EXTRA in getCount()
Modify getItem() to return something sane if it asks for an item not in your list
Modify getView() to configure the given view as a simple horizontal padding with the same height as the rest of your views if the position index is more than your list size
You would need to fiddle around with the EXTRA constant to see what value is best.

Related

Android gridview stack from bottom

I am trying to create a gridview consisting of 15x20 textviews and I want the textviews to be populated from bottom to top. e.g getChildAt(0) will refer to the grid at bottom left. Right now it is always referencing top left grid.
I have tried
android:stackFromBottom="true"
but it isn't working. Below is my code, hope someone could give some insight what am i doing wrong. Thanks!
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/sample_main_layout">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="313dp"
android:layout_weight="0.18">
<GridLayout
android:id="#+id/map_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:columnCount="15"
android:descendantFocusability="afterDescendants"
android:gravity="center"
android:horizontalSpacing="30dp"
android:paddingLeft="20dp"
android:rowCount="20"
android:stackFromBottom="true"
android:stretchMode="columnWidth"
android:verticalSpacing="30dp">
</GridLayout>
Using some of the solution you guys suggested, I created a function that correct my index for the grid. It will reference the grid from the last position.
EDIT :
public int correctIndex(int index) {
int mul = (int) Math.floor(index /15);
int remainder = index%15;
remainder = 15-remainder;
int correctedIndex = 300-(mul*15+remainder);
return correctedIndex;
}
You don't need to fill the GridView in reverse order.. You just need to read it in reverse order.
Instead of:
gridView.getChildAt(position);
Use:
gridView.getChildAt(gridView.getChildCount() - position - 1);
Of course, you should replace by the variable that you are using position - 1
android:stackFromBottom="true" doesn't mean your items will be placed in the opposite order.
It just means that if there is extra gap due to fewer items, space will be left in the top.
To place the items in opposite order, you will need to use override the getItem(int position) method to return item in reverse order in the adapter of the GridView.
To make android:stackFromBottom="true" work you must be using <GridView> instead of <GridLayout>.
I could be wrong but if you load in something like an array for the data in the grid view, then you can just reverse the array before loading it, or do what #W0rmH0lesaid above

Move layout up when layout above shrinks in height

Hi I have a fragment with two RecyclerViews in it, one above the other.
The first is a list of items for the user to take an action on and the second is where the items will be populated once the action is taken. So when an item is removed from the top list it is added to the bottom list.
The issue I am having is when I remove an item from the top RecyclerView all the remaining items in the top RecyclerView move up to fill in the space left by the removed item, but this leaves a gap between the top and bottom RecyclerViews.
How can I move the bottom recyclerview up to fill in the gap created once an item is removed from the top RecyclerView
Here is my layout xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_alignParentTop="true"
android:id="#+id/pending_tasks"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:layout_below="#id/pending_tasks"
android:id="#+id/completed_tasks"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
I have tried calling invalidate() on the bottom RecyclerView but that has not worked. Any help would be appreciated, thanks!
It's impossible to update layout size once it's been displayed on the screen. If you modify the content of your RecyclerView you can't just simply refresh the layout to shrink it.
I would suggest using single RecyclerView and storing lower bound of the first list in some variable. Then simply update it accordingly to modifications in your first list.
Another solution which may help you:
Change Relative layout width and height dynamically

Minus paddingTop on Android ListView, is it possible?

I have top margin of 30dp inside some of my list view items (including always the first one). However I don't want this top margin on my first list view item.
I have tried offsetting this by adding the following to the ListView
android:paddingTop="-30dp"
However, it doesn't seem to have any effect and the first list view item is still 30dp below the top edge of the list view.
Is there a way of getting minus top padding to work on an Android ListView?
XML
<ListView
android:choiceMode="singleChoice"
android:divider="#null"
android:dividerHeight="0dp"
android:paddingTop="-30dp"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
Then some of the list view items content is as follows:
<LinearLayout
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"/
android:layout_marginTop="30dp">
<!--other content here-->
</LinearLayout>
The first list view item always uses the above template and im trying to offset that 30dp top margin.
Try setting android:layout_marginBottom="30dp" in your linear layout, so that you'll have the top of list without any margin but between list items still with margin. Does it look like what you want? Because minus padding is normally possible but in your case its overridden by the margin in list items.

Android: Data list scrolling along with other components

I'm trying to show a list of data in an android activity. Normally anyone would do that with a simple ListView which I have used many times before. But now I'm having an application with a fixed header and footer, with the middle part (the content) scrolling underneath both the header and the footer. In the middle section I would like to add other components both above and below the list of data, but the entire part must be scrollable. I tried adding components (like a button, textview etc) to a listview but the lay-out builder in Eclipse won't let me do that.
So I started using a ScrollView where you can easily add any component you like. But I am not allowed to add a ListView to a ScrollView, which I can understand as it would create a strange effect (as both are able to scroll).
Next I wanted to use a TableLayout to dynamically add TableRows, but on multiple websites it is said to be slow and 'not the way to do it'. I also couldn't find an elegant way to add the seperator between each item. With a ListView that would all be done very easily.
The following image probably explaines at best the effect I want: http://tinyurl.com/bvkec5d
The table with the 'Table Data' header can possibly have a lot of items and thus can become very large in length. What I don't want is that the table has a fixed size and the items are scrollable within that table. I actually want the table to grow in size and the ScrollView containing the table should therefore be growing as well. I also want the infobox above the table to scroll along (as with any other components which might be added later).
What is the best way to achieve this effect?
You can use a simple vertical LinearLayout (or a RelativeLayout) that contains your static header and footer, and use a ListView between them. You can set header and footer views on the ListView to add the scrollable header and footer content. For simplicity of example here's the LinearLayout way:
<LinearLayout android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent">
<!--static header content... can be any kind of view-->
<TextView
android:layout_width="match_parent"
android:layout_weight="0"
android:layout_height="wrap_content"/>
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<!--static footer content... can be any kind of view-->
<TextView
android:layout_width="match_parent"
android:layout_weight="0"
android:layout_height="wrap_content"/>
</LinearLayout>
And in code, you can say:
ListView theList = (ListView)findViewById(R.id.list);
// example of creating header and footer views from inflation or by instantiation in code
View myHeaderView = getLayoutInflater().inflate(R.layout.myHeaderLayout,theList,false);
View myFooterView = new TextView(this, some layout params);
theList.addHeaderView(myHeaderView);
theList.addFooterView(myFooterView);
ListView.addHeaderView and ListView.addFooterView should enable you to add other static views (whose content could be updated dynamically) to the top or bottom of a ListView:
public void addHeaderView (View v)
Since: API Level 1 Add a fixed view to appear at the top of the list.
If addHeaderView is called more than once, the views will appear in
the order they were added. Views added using this call can take focus
if they want.
NOTE: Call this before calling setAdapter. This is so ListView can
wrap the supplied cursor with one that will also account for header
and footer views.

Limit number of rows of listview

I am developing an application that needs to pair with other devices through Bluetooth. I was having trouble in order to show the list of paired devices in correct manner. I had also viewed the example in the android api (Bluetooth Chat), but i was having the same problem.
The list of paired devices are to big and then hides a search button that are at the bottom of the list.
My xml code is very the same of the example:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView android:id="#+id/listpaired_devices"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/title_paired_devices"
android:visibility="gone"
android:background="#666"
android:textColor="#fff"
android:paddingLeft="5dp"
/>
<ListView android:id="#+id/paired_devices"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stackFromBottom="true"
android:layout_weight="1"
/>
<TextView android:id="#+id/list_new_devices"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/title_other_devices"
android:visibility="gone"
/>
<ListView android:id="#+id/new_devices"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stackFromBottom="true"
android:layout_weight="2"
/>
<Button android:id="#+id/btscan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/btscan"
/>
</LinearLayout>
But and i can't show the search button at the bottom.
Here my screen:
My Screen
You could see a bit of the button at the bottom of the dialog window.
It's possible to limit the number of rows shown at the listview ? Can anyone tell me how i can fix this problem
Firstly some points about your code:
layout_weight is only meaningful if an object has no size in a certain dimension, that is you set layout_height or layout_width to 0, so this has no effect on your code.
Setting the height of a ListView to wrap_content is pretty meaningless, and even if it works it's bad practice. Use either 'fill_parent' or a definite height.
The button is hidden because, as per the point above, the ListViews you have created have no predefined size so take up as much space as they can, pushing the button off the screen.
So let's think about what you really have there - it's just a single list with a button at the bottom (yes you may have headers or multiple sources of data in there but we'll get onto that).
The following layout will give you a ListView at the top and a Button at the bottom. The ListView will take up any space not being used by the Button. Notice how the Button is defined before the ListView in the layout - this causes Android to calculate how much height the button takes up before considering the ListView. It then gives the ListView the rest of the height available.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:id="#+id/btscan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/btscan"
/>
<ListView android:id="#+id/all_devices"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/btscan"
android:stackFromBottom="true"
/>
</RelativeLayout>
So that's the layout. Now lets consider the actual content of your list: you have a header, followed by a list of paired devices, followed by another header and then a list of new devices.
You can create this using a single Adapter - Commonsware provides a very good implementation called MergeAdapter but you could code your own. MergeAdapter doesn't directly let you a view (e.g. for the headers) but thankfully Commonsware also provides the SackOfViewsAdapter which allows you to add views to it, and then you can add the SackOfViewsAdapter to the MergeAdapter.
Here is some pseudo-code which should accomplish what is outlined above.
// This is the adapter we will use for our list with ListView.setAdapter
MergeAdapter listAdapter = new MergeAdapter();
// The first header - you'll need to inflate the actual View (myHeaderView1) from some resource
// using LayoutInflater
List<View> firstHeaderViews = new List<View();
firstHeaderViews.add(myHeaderView1);
SackOfViewsAdapter firstHeaderAdapter = new SackOfViewsAdapter(firstHeaderViews)
// Second header
List<View> secondHeaderViews = new List<View();
secondHeaderViews.add(myHeaderView2);
SackOfViewsAdapter secondHeaderAdapter = new SackOfViewsAdapter(secondHeaderViews);
// Now to add everything to the MergeAdapter
// First goes the first header
listAdapter.addAdapter(firstHeaderAdapter);
// Now your first list
listAdapter.addAdapter(firstListAdapter);
// Now your second header
listAdapter.addAdapter(secondHeaderAdapter);
// Now your second list
listAdapter.addAdapter(secondListAdapter);
// Now set the adapter to the list
myList.setAdapter(listAdapter)
The layout produced should look something like this. Note I extended the list to show how it behaves with a list longer than the screen; the button still remains visible. The red box marks the bounds of the screen.
You can limit the number of rows shown at the list view, but not sure if that will really help you in what you want to achieve, because you're hiding information from the user that might be important to him. You can limit the number of rows by limiting the number of items you pass to the listview adapter, or you can set the visibility to 'gone' in the getView method when the list view reaches a certain position (you can check the 'position' parameter of getView()).
However, I would suggest you use only one list view (add a separator for the 'new/other devices' title into the view for a list item, but hide it by default, and then, as already suggested by suri, use headers and footers for the listview (to place the scan button).

Categories

Resources