Android ListView Adapter how to detect an empty list? - android

I have a ListView in my Activity which takes values from an extension class of SimpleAdapter.
This one is correctly working when I add or delete some data in it.
But my problem is, when my item list is empty, I would like to replace the listView by a message like "No item inhere" or something like that.
I tried to do it, this way:
class FavAdapter extends SimpleAdapter{
Activity context;
ArrayList<HashMap<String,String>> data;
String[] items;
int[] champs;
int layout;
FavAdapter(Activity _context, ArrayList<HashMap<String,String>> _data, int _layout, String[] _items, int[] _champs){
super(_context, _data, _layout, _items, _champs );
this.data = _data;
this.context = _context;
this.items = _items;
this.layout = _layout;
this.champs = _champs;
}
public View getView(int pos, View convertView, ViewGroup parent){
//Recycling
View row = convertView;
//Else get from XML
if(row == null){
LayoutInflater infla = context.getLayoutInflater();
row = infla.inflate(layout, null);
}
//If there are data
if(data.size() > 0){
/**** Here I am correctly constructing row *****/
...
}
//Else
else{
TextView txt = new TextView(ActivityFavoris.this);
txt.setText("Not data inhere");
LinearLayout ll = (LinearLayout) row.findViewById(R.id.result_lyt_principal);
ll.addView(txt);
}
return row;
}
Problem is: my list has never a size of 0. in fact when the data is empty the adapter is not called.
Can someone explain me how I can do it by another way?
Thanks in advance.
Edit : Using your answers I succeed on that. My solution is : setContentView has to be used with findViewById(android.R.id.empty), but if like me you have two different listView in your activity, which need different empty views, you will have to find it inside different layout. This way android will automatically call the right view when the listview is empty, and nothing have to be done in the adapter when data.size is 0.
example: in Activity :
public void onCreate(Bundle b){
super.onCreate(b);
lv1 = (ListView) findViewById(R.id.listviewone);
lv2 = (ListView) findViewById(R.id.listviewtwo);
//****set listview adater***//
...
//set empty view
lv1.setEmptyView(findViewById(R.id.layoutone).findViewById(android.R.id.empty));
lv2.setEmptyView(findViewById(R.id.layouttwo).findViewById(android.R.id.empty));
}
with that xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/layoutone"
android:orientation="horizontal"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#+id/listviewone"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Pas de favoris enregistrées" />
</LinearLayout>
<LinearLayout
android:id="#+id/layouttwo"
android:orientation="horizontal"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#+id/listviewtwo"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Pas de favoris enregistrées" />
</LinearLayout>

Use the method setEmptyView which sets the view to show if the adapter is empty.

The above answer sounds fine, but for the record the reason your method doesn't appear to be called is probably because your implementation of getCount() returns something like data.size() - meaning 0. This means the ListView will never call getView at all.
Instead you could do something like this:
public int getCount() {
if (data.size()==0) {
return 1;
}
return data.size();
}
I hope that's helpful.

You are calling this adapter in some activity. there the adapter is set to any listview. Before setting the adapter to the list view you can check what is the size of arraylist. if the size is zero then you can add "No item inhere" message to the arraylist by make a hashmap

Create a listview with the 'no items found' entry by default. When the first item is added, reinit the list and remove the default entry.

Related

Two clickable item in same row of listview

How can I place 2 items in the same row in listview?
e.g
item 1 | item 2
item 3 | item 4
item 5 | item 6
and so on.
I don't have a problem with drawing them and there are a lot of various ways to draw them.
My problem: I cannot find a propper way to listen when I clicked on item 1 or item 2.
Also, I am considering to simply make 2 listview, populate them independently and rotate simultaneously, but I hope there is better way.
You should use a custom adapter for your listView. In the adapter you inflate your own layout for each row and listen for events for each view. This is an example of a custom Adapter: Custom Adapter for List View
Hope it helps you!!
for each item add this to listview row layout:
android:focusable="false"
and then in getView find each item and then assign it the appropriate click listener.
Use CustomAdapter for listview and add items in collection for example an ArrayList.
CustomAdapter adapter=new CustomAdapter(getApplicationContext(),R.id.listview_id,itemlist);
list_item.xml
<?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="horizontal"
>
<TextView android:id="#+id/item1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#000000"
/>
<TextView android:id="#+id/item2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#000000"
/>
</LinearLayout>
CustomAdapter.java
public class CustomAdapter extends CustomAdapter<String>{
//Declare variables variables here..
public CustomAdapter(Context context, int resource,
List<String> objects) {
//initialize and set constructor values here..
}
public static class ViewHolder {
TextView textitem1;
TextView textitem2
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View row = convertView;
ViewHolder holder = null;
if(null == row) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.textitem1 = (TextView) row.findViewById(R.id.item1);
holder.textitem2 = (TextView) row.findViewById(R.id.item2);
row.setTag(holder);
}
return view;
}
}
You can add as many TextViews you want. Depending on requirement, you can alter their position/height/width etc.
For listening Click event,
For each text view add android:clickable="true"
Use a CustomAdapter and set ClickListeners for each TextView in getView method.
Hope This Helps!
And i found way wich is suitable for me for 100%
Idea is to use GridView~ instead ofListView`.
<GridView
android:id="#+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:numColumns="2"
android:stretchMode="columnWidth" />
In fact I dont even need to change and single line in my original adapter. android:numColums set how much colums you want to display. You can place int there or auoto_fit.

(Android) How do i access and modify a specific element in a custom listview, seeing as it uses a custom adapter?

I have a custom list view, here is its layout.xml
<?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="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="#+id/playerToken"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/playerName"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/playerMoney"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
And here is the custom Adapter which takes an array of a Player Object which stores information like the players name, his token to represent him, and his money balance. the adapter takes that information and populates my custom list, as the layout above.
public class MyAdapter extends ArrayAdapter<Player> {
public MyAdapter(Context context, Player[] values) {
super(context, R.layout.activity_banking_layout, values);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater theInflater = LayoutInflater.from(getContext());
View theView = theInflater.inflate(R.layout.activity_banking_layout, parent, false);
Player player = getItem(position);
TextView playerNameText = (TextView) theView.findViewById(R.id.playerName);
TextView playerMoneyText = (TextView) theView.findViewById(R.id.playerMoney);
ImageView playerToken = (ImageView) theView.findViewById(R.id.playerToken);
playerNameText.setText(player.getName());
playerMoneyText.setText(Integer.toString(player.getMoney()));
int rId = theView.getResources().getIdentifier(player.getToken(), "drawable",
getContext().getPackageName());
playerToken.setImageResource(rId);
return theView;
}
}
This is just the layout showing the listView that us being adapted:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/bankListView" />
</LinearLayout>
So basically, my list is created and adapter in the onCreate method of the activity showing the list. After that my list items can open a context menu and depending on what is selected the player objects are manipulated. I want my list to reflect these changes, so i was wondering how i can access a specific part of my custom list and edit it. For example my custom list has a player icon, and to the right, the players name and below the name a money amount. Lets say i want to change the money amount of a specific player and reflect that change on the list, how do i access that specific TextView, within that specific position in that ListView ?
Since your adapter 'MyAdapter' extends ArrayAdapter, you can try using getItem(int position) which return the list item at the specified position; a Player object in your case. From there, you can modify your object's data member (amount of money) and then refresh the list to reflect your changes with notifyDataSetChanged().
In case you wanted to know the index/position of the clicked list item, then your question would be a duplicate of this one.
instead of manipulating the textview, consider the following approach:
make the Player[] array a global variable, instead of passing it to constructor,. then manipulate the Player object directly, then call
notifyDataSetChanged()
on your adapter which will automatically update your correct textview.
private Player[] values;
public void onCreate(Bundle s){
/*your onCreate things*/
MyAdapter adapter = new MyAdapter(this);
// update player 5 from array
values[4].money = newMoneyVal;
// after updating, call notifyDataSetChanged()
adapter.notifyDataSetChanged();
}
public class MyAdapter extends ArrayAdapter<Player> {
public MyAdapter(Context context) {
super(context, R.layout.activity_banking_layout, values);
}
/*rest of your adapter class*/
}
let me know if this works or if you have any questions
Yuo just have to implement a onlistitemclick listener, like this:
#Override
protected void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
l[pos].findViewById(R.id.yourTagName).setText("ChangedValue");//to be adapted
}

Android: button showing up multiple times in list view

I trying to write code to highlight the selected value of the list with "Next" button at the bottom of the layout. But for some reason, after every list item, "next" button also shows up. Can someone please help me resolve this problem?
Here is the layout file:
<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"
android:orientation="vertical"
android:id="#+id/questionLayout"
>
<TextView android:id="#+id/txtExample"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:textColor="#000000"
android:background="#FF0000"
/>
<ListView
android:id="#+id/listExample"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#CCCCCC"
android:choiceMode="singleChoice"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<Button
android:id = "#+id/next"
android:text="Next"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_gravity="center"
android:layout_weight="50"
/>
<Button
android:id = "#+id/submit"
android:text="Submit"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_weight="50"
android:layout_gravity="center"
/>
</LinearLayout>
</LinearLayout>
Java Code:
public class updateList extends Activity {
private SelectedAdapter selectedAdapter;
private ArrayList<String> list;
int correct_answer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new ArrayList<String>();
list.add("Choice One");
list.add("Choice Two");
list.add("Choice Three");
selectedAdapter = new SelectedAdapter(this,0,list);
selectedAdapter.setNotifyOnChange(true);
ListView listview = (ListView) findViewById(R.id.listExample);
listview.setAdapter(selectedAdapter);
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
// user clicked a list item, make it "selected"
selectedAdapter.setSelectedPosition(position);
}
});
}
}
Thanks in advance
SSP
Selected Adaptor class:
public class SelectedAdapter extends ArrayAdapter{
// used to keep selected position in ListView
private int selectedPos = -1; // init value for not-selected
public SelectedAdapter(Context context, int textViewResourceId,
List objects) {
super(context, textViewResourceId, objects);
}
public void setSelectedPosition(int pos){
selectedPos = pos;
// inform the view of this change
notifyDataSetChanged();
}
public int getSelectedPosition(){
return selectedPos;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
// only inflate the view if it's null
if (v == null) {
LayoutInflater vi = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.activity_main, null);
}
// get text view
TextView label = (TextView)v.findViewById(R.id.txtExample);
// change the row color based on selected state
if(selectedPos == position){
label.setBackgroundColor(Color.CYAN);
}else{
label.setBackgroundColor(Color.WHITE);
}
label.setText(this.getItem(position).toString());
/*
// to use something other than .toString()
MyClass myobj = (MyClass)this.getItem(position);
label.setText(myobj.myReturnsString());
*/
return(v);
}
}
change your listview in xml as like this
<ListView
android:id="#+id/listExample"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"//===== set maximum heighthere
android:layout_marginBottom="50dp"// === give some space at bottom so that buttons will appear
android:background="#CCCCCC"
android:choiceMode="singleChoice"
/>
But for some reason, after every list item, "next" button also shows up.
The ListView's row layout is determined by the layout you inflate in getView() or pass to your Adapter's super class if you haven't overridden getView(). Double check this layout and remove the unwanted code.
Addition
The layout for your ListView's items only needs to be one TextView since you only want to display a phrase in each. However you are currently passing your entire main layout, this creates the Buttons, an unused ListView, and everthing else in every row...
Instead use android.R.layout.simple_list_item_1 in getView(), of course you'll need to change the id you pass to findViewById() as well:
if (v == null) {
LayoutInflater vi = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(android.R.layout.simple_list_item_1, null);
}
// get text view
TextView label = (TextView)v.findViewById(android.R.id.text1);
Please watch Android's Romain Guy discuss writing an efficient adapter to speed things up.

android.widget.ArrayAdapter<T> just accept row template

I am developing an android application which contains a ListAtivity class and get it is data as follow :
ArrayAdapter<Item> ara=new MyArrayAdapter(this,_items);
setListAdapter(ara);
And I defined MyArrayAdapter :
....
public MyArrayAdapter(Activity context, List<BirthdayContact> list) {
super(context,R.layout.list_row,0,list);
//super(context, R.layout.birthday_list, list);
this.context = context;
this.list = list;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.birthday_list_row, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder._cName= (TextView) view.findViewById(R.id.contact_name);
viewHolder._cImage = (ImageView) view.findViewById(R.id.contact_image);
viewHolder._cbirthDay=(TextView)view.findViewById(R.id.contact_birthday_remained);
view.setTag(viewHolder);
}
......
But the problem with this way is that you cant only assign each row`s template and you cant have other widget on list view which are not part of list of data. I mean I want to have a say a TextView which shows messages to user, and below that I show the list of rows.
Can you help me please?
If you want a different layout than a simple ListView you have the option of setting the content view to a layout file like this:
setContentView(R.layout.layout_with_diferrent_views); // call this on the onCreate() method
where R.layout.layout_with_different_views could be a xml layout like this:
<?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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Because you extends ListActivity you must have in the layout a ListView element with the id #android:id/list. Of course you can have a more complex layout than the one above as long as you have a ListView element with the id #android:id/list
You should consider using a listHeader : lv.addHeaderView(findViewById(R.id.header));
This has to be done in your onCreate method in your activity, and you must provide a widget with the id header.
If you want other components in activity.Then better consider Normal Activity instead ListActivity.

How to update list in android

i have a list in android. and it has 30 records currently.
but on my activity i am only showing 5 records... after 5 records it shows me a button
"Display All Data"
when i click on that button, then it should display all 30 records and update the activity List. Please tell me how can i update. like we do in AJAX in web technology. i hope u guys understand what i am trying to say?
Refresh the Activity without refreshing the whole activity. Please Reply Friends.
waiting for positive response.
You should just simply add the newly arrived items to your list of data (the already listed 5 items), and call notifyDatasetChanged() on your ListAdapter implementation.
Update
Here I share a sample activity which contains a list and a TextView at the bottom (inflated from stepping_list.xml), where the list initially contains 5 items, and at the bottom a button. When pressing the button, other 25 values get loaded into the list, and the button disappears.
For this we need the main layout, res/layout/stepping_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<TextView android:id="#+id/footer"
android:layout_width="fill_parent" android:layout_height="60dp"
android:background="#drawable/box"
android:text="Lazy loading list in steps" android:textStyle="bold"
android:gravity="center_vertical|center_horizontal"
android:layout_alignParentBottom="true" />
<ListView android:id="#+id/list"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_alignParentTop="true" android:layout_above="#id/footer" />
</RelativeLayout>
For the Load more data button to always appear after the last item of the initial list (even if need to scroll to it), I put it into the list's item renderer layout. This way the list will have two item renderers.
The common renderer res/layout/row.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView" android:layout_alignParentRight="true"
android:layout_width="fill_parent" android:layout_height="60dp"
android:gravity="center_vertical|right" android:paddingRight="10dp"
android:textSize="35dp"
android:textColor="#2B78E4" />
is a simple TextView, and the renderer for the last item (of the initial list)
res/layout/row_with_button.xml:
<?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">
<TextView android:id="#+id/textView"
android:layout_alignParentRight="true"
android:layout_width="fill_parent" android:layout_height="60dp"
android:gravity="center_vertical|right" android:paddingRight="10dp"
android:layout_weight="1" android:textColor="#2B78E4"
android:textSize="35dp" />
<Button android:id="#+id/loadbtn"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="1" android:text="Load more data"
android:onClick="loadMoreData" />
</LinearLayout>
Finally the Activity class that connects these layouts:
SteppingListActivity.java:
public class SteppingListActivity extends Activity
{
private MyAdapter adapter;
private ArrayList<Integer> values;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.stepping_list);
//initialize the list of data which will populate the list
//TODO: You need to retrieve this data from the server, but I use
// here simple int values.
values = new ArrayList<Integer>();
for (int i = 0; i < 5; i++)
{
values.add((i % 2 == 0) ? i * 3 : i + 3);
}
//initialize the adapter, and attach it to the ListView:
adapter = new MyAdapter();
final ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(adapter);
}
/**
* The onClick function of the last itemrenderer's button
* #param button the button clicked.
*/
public void loadMoreData(View button)
{
//Just put some more data into the values ArrayList:
//TODO: You need to retrieve these data from the server, as well!
for (int i = 5; i < 30; i++)
{
values.add((i % 2 == 0) ? i * 3 : i + 3);
}
//notify the ListAdapter about the changes:
adapter.notifyDataSetChanged();
}
/**
* The custom ListAdapter class used to populate the ListView
*/
private class MyAdapter extends BaseAdapter
{
private LayoutInflater inflater;
public MyAdapter()
{
inflater = LayoutInflater.from(SteppingListActivity.this);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
//check if the current item to show is the last item of the
// initial list, and if so, inflate the proper renderer for it:
if ((position == 4) && (values.size() == 5))
convertView = inflater.inflate(
R.layout.row_with_button, parent, false);
else if ((convertView == null) ||
(convertView.findViewById(R.id.loadbtn) != null))
convertView = inflater.inflate(R.layout.row, parent, false);
//set the value of the TextView
((TextView) convertView.findViewById(
R.id.textView)).setText(values.get(position)+ ".50 €");
return convertView;
}
#Override
public int getCount()
{
return values.size();
}
#Override
public Object getItem(int position)
{
return values.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
}
}
I hope you got the idea :)

Categories

Resources