Dynamic ListView in Android app - java

Is there a working example out there that demonstrates how to append additional rows in ListView dynamically?
For example:
you are pulling RSS feeds from
different domains
you then display the first 10 items
in the ListView (while you have
other threads running in the
background continue pulling feeds)
you scroll and reach the bottom of
the List and click at a button to
view more items
the ListView will then get appended
with additional 10 items, which
makes 20 items now in total.
Any advice how to accomplish this?
Nicholas

To add new item to your list dynamically you have to get adapter class from your ListActivity and simply add new elements. When you add items directly to adapter, notifyDataSetChanged is called automatically for you - and the view updates itself. You can also provide your own adapter (extending ArrayAdapter) and override the constructor taking List parameter. You can use this list just as you use adapter, but in this case you have to call adapter.notifyDataSetChanged() by yourself - to refresh the view.
Please, take a look at the example below:
public class CustomList extends ListActivity {
private LayoutInflater mInflater;
private Vector<RowData> data;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mInflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
data = new Vector<RowData>();
RowData rd = new RowData("item1", "description1");
data.add(rd);
rd = new RowData("item2", "description2");
data.add(rd);
rd = new RowData("item2", "description3");
data.add(rd);
CustomAdapter adapter = new CustomAdapter(this, R.layout.custom_row,R.id.item, data);
setListAdapter(adapter);
getListView().setTextFilterEnabled(true);
}
public void onListItemClick(ListView parent, View v, int position, long id) {
CustomAdapter adapter = (CustomAdapter) parent.getAdapter();
RowData row = adapter.getItem(position);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(row.mItem);
builder.setMessage(row.mDescription + " -> " + position );
builder.setPositiveButton("ok", null);
builder.show();
}
/**
* Data type used for custom adapter. Single item of the adapter.
*/
private class RowData {
protected String mItem;
protected String mDescription;
RowData(String item, String description){
mItem = item;
mDescription = description;
}
#Override
public String toString() {
return mItem + " " + mDescription;
}
}
private class CustomAdapter extends ArrayAdapter<RowData> {
public CustomAdapter(Context context, int resource,
int textViewResourceId, List<RowData> objects) {
super(context, resource, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
//widgets displayed by each item in your list
TextView item = null;
TextView description = null;
//data from your adapter
RowData rowData= getItem(position);
//we want to reuse already constructed row views...
if(null == convertView){
convertView = mInflater.inflate(R.layout.custom_row, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
//
holder = (ViewHolder) convertView.getTag();
item = holder.getItem();
item.setText(rowData.mItem);
description = holder.getDescription();
description.setText(rowData.mDescription);
return convertView;
}
}
/**
* Wrapper for row data.
*
*/
private class ViewHolder {
private View mRow;
private TextView description = null;
private TextView item = null;
public ViewHolder(View row) {
mRow = row;
}
public TextView getDescription() {
if(null == description){
description = (TextView) mRow.findViewById(R.id.description);
}
return description;
}
public TextView getItem() {
if(null == item){
item = (TextView) mRow.findViewById(R.id.item);
}
return item;
}
}
}
You can extend the example above and add "more" button - which just add new items to your adapter (or vector). Regards!

Related

Android - pass values from clicked item on ListView and display them on a new Actvity

I am an intern at this company and I have a task assigned to me by my team leader where I need to make an app that displays a list of items that I can add to and edit/delete the items on the list. I am following the requirements given to me on what the app needs to do.
The problem I'm having is that I need to pass values from an item when clicked on a ListView which uses a custom adapter, and have them sent to a new activity and displayed on the new activity's textviews and imageview. I have tried using putExtras() methods in the list click method and getting the values using getExtras() methods but they didn't work and I've already deleted those codes, so they are no longer there. If you need more of the classes/activities I'm using please let me know. I am using Android Studio 3.1.4
ItemListView.java
public class ItemListView extends AppCompatActivity {
DatabaseHelper myDB;
ArrayList<Item> itemList;
ListView listView;
Item item;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list_view);
listView = (ListView) findViewById(R.id.listView);
myDB = new DatabaseHelper(this);
itemList = new ArrayList<>();
Cursor data = myDB.getListContents();
int numRows = data.getCount();
if(numRows == 0){
Toast.makeText(ItemListView.this, "There is nothing in the database.", Toast.LENGTH_LONG).show();
} else {
while(data.moveToNext()){
item = new Item(data.getString(1), data.getString(2), data.getString(3));
itemList.add(item);
}
Row_ListAdapter adapter = new Row_ListAdapter(this, R.layout.list_adapter_view, itemList);
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(ItemListView.this, ViewItemClicked.class);
startActivity(intent);
}
});
}
ViewItemClicked.java
I want the values displayed onto the layout of this activity when a row is clicked.
public class ViewItemClicked extends AppCompatActivity {
ImageView image;
TextView name, desc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_item_clicked);
}
}
Other classes I used:
Row_ListAdapter.java
public class Row_ListAdapter extends ArrayAdapter<Item> {
private LayoutInflater mInflater;
private ArrayList<Item> items;
private int mViewResourceId;
ImageView image;
TextView name;
TextView description;
public Row_ListAdapter(Context context, int textViewResourceId, ArrayList<Item> items){
super(context, textViewResourceId, items);
this.items = items;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewResourceId = textViewResourceId;
}
public View getView(int position, View convertView, ViewGroup parents){
convertView = mInflater.inflate(mViewResourceId, null);
Item item = items.get(position);
if(item != null){
image = (ImageView) convertView.findViewById(R.id.iconIV);
name = (TextView) convertView.findViewById(R.id.nameTV);
description = (TextView) convertView.findViewById(R.id.descTV);
if(image != null){
image.setImageBitmap(item.getImage());
}
if(name != null){
name.setText(item.getName());
}
if(description != null){
description.setText(item.getDescription());
}
}
return convertView;
}
}
Link to GUI: https://i.stack.imgur.com/wHfgv.png
Before you pass the data, implement your Item Class with Serializable like this:
public class Item implements Serializable{
/*your class code here*/
}
Then pass the data in the listView.setOnItemClicklistener like this
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Item passItem = itemList.get(position);
Intent intent = new Intent(ItemListView.this, ViewItemClicked.class);
Bundle itemBundle = new Bundle();
itemBundle.putSerializable("dataItem",passItem)// put the data and define the key
intent.putExtras(itemBundle)
startActivity(intent);
}
});
and to open the data in the ViewItemClicked.Class
public class ViewItemClicked extends AppCompatActivity {
ImageView image;
TextView name, desc;
Item item;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
item = (Item) getIntent().getSerializableExtra("dataItem"); // use the key
setContentView(R.layout.activity_view_item_clicked);
/*now u can use the item data*/
}
}
Try the codes below:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(ItemListView.this, ViewItemClicked.class);
String name = itemList.get(position).getString(1);
String description = itemList.get(position).getString(2);
String something_else = itemList.get(position).getString(3);
intent.putExtra("name", name);
intent.putExtra("description", description);
intent.putExtra("something_else", something_else);
startActivity(intent);
}
In your Details Activity:
Intent intent = getIntent();
String name = intent.getStringExtra("name");
String description = intent.getStringExtra("description");
String something_else = intent.getStringExtra("something_else");
Now use the strings to show the values in the desired places.
as
edittext.setText(name);
WHAT FORMAT TYPE OF IMAGE YOUR ARE USING
Is it Base64 or Bitmap if it is Base64 try this code..
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(ItemListView.this, ViewItemClicked.class);
String name = list.get(position).getName();
String description = list.get(position).getDescription();
String image= list.get(position).getImage();
startActivity(intent);
}
In Your Second Activity use this code..
Intent intent = getIntent();
String name = intent.getStringExtra("name");
String description = intent.getStringExtra("description");
String image = intent.getStringExtra("image");
Convert here Base64 to Bitmap..
byte[] decodedString = Base64.decode(image, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0,
decodedString.length);
Define an interface for listening item click event
public class Row_ListAdapter extends ArrayAdapter<Item> {
private LayoutInflater mInflater;
private ArrayList<Item> items;
private int mViewResourceId;
ImageView image;
TextView name;
TextView description;
OnItemListener mListener;
public Row_ListAdapter(Context context, int textViewResourceId, ArrayList<Item> items){
super(context, textViewResourceId, items);
this.items = items;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewResourceId = textViewResourceId;
}
public View getView(int position, View convertView, ViewGroup parents){
convertView = mInflater.inflate(mViewResourceId, null);
Item item = items.get(position);
if(item != null){
image = (ImageView) convertView.findViewById(R.id.iconIV);
name = (TextView) convertView.findViewById(R.id.nameTV);
description = (TextView) convertView.findViewById(R.id.descTV);
if(image != null){
image.setImageBitmap(item.getImage());
}
if(name != null){
name.setText(item.getName());
}
if(description != null){
description.setText(item.getDescription());
}
}
convertView.setOnClickListener((v) -> {
if(mListener != null) {
mListener.onItemClick(v, item);
}
})
return convertView;
}
public void setOnItemListener(OnItemListener listener) {
mListener = listener;
}
public interface OnItemClickListener {
void onItemClick(View v, Item item);
}
}
Then, implement OnItemClickListener in the activity and set it to the adapter:
Row_ListAdapter adapter = new Row_ListAdapter(this, R.layout.list_adapter_view, itemList);
adapter.setOnItemListener("your implement");

How to add a row in listveiw dynamically?

I'm trying to create a row in listview dynamically by giving external data.
Each row in a listview has a string data and a switch. String data taken from an Edittext externally.
I have a EditText field. I will input the data through this.
I have a button . When it is pressed, the EditText content should be added to a new row of the listview along with a Switch
While adding the new row , care should be taken to retain the previously added row.
I got the code skeleton from web. This code is manipulated by me for my requirement.
The following code adds the row dynamically but it is clearing the previously added row. Kindly help . Thanks
This is my MainActivity.java
public class MainActivity extends Activity {
Switch sw1;
private ListView listView1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
}
public void getdata(View v) {
EditText et;
String dev_name;
et = (EditText)findViewById(R.id.editText1) ;
dev_name = et.getText().toString() ;
create(dev_name, null);
}
public void create (String str, Switch sw1) {
Items Items_data[] = new Items[]
{
new Items( str,sw1)
};
ItemsAdapter adapter = new ItemsAdapter (this,R.layout.items_row, Items_data);
listView1 = (ListView)findViewById(R.id.listView1);
listView1.setAdapter(adapter);
}
}
This is my ItemsAdapter.java
public class ItemsAdapter extends ArrayAdapter<Items>{
Context context;
int layoutResourceId;
Items data[] = null;
public ItemsAdapter(Context context, int layoutResourceId, Items[] data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ItemsHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ItemsHolder();
holder.txtTitle = (TextView)row.findViewById(R.id.listtext);
holder.switch1= (Switch)row.findViewById(R.id.listswitch);
row.setTag(holder);
}
else
{
holder = (ItemsHolder)row.getTag();
}
Items item = data[position];
holder.txtTitle.setText(Items.tv);
holder.switch1.setChecked(false);
return row;
}
static class ItemsHolder
{
TextView txtTitle;
Switch switch1;
}
}
This is my Item class.
public class Items {
public static String tv;
public static Switch switc;
public Items() {
super();
}
public Items(String tv, Switch switc ) {
super();
this.tv = tv;
this.switc = switc;
}
}
You are assigning an array with one Items object that you create with the arguments passed in create(). You should try something like this:
public class MainActivity extends Activity {
private Items[] items = new Items[0]; //We're making this a field, so we can create a new array containing our new item.
...
public void create (String str, Switch sw1) {
int i = items.length+1; //plus one because we are adding one element at a time. If you'd like to add more at once, change the 1 accordingly.
Items[] tmp = new Items[i];
System.arrayCopy(items, 0, tmp, 0, items.length);
tmp[i] = new Items(str, sw1);
items = tmp; //use items like you would use Items_data
...
}
}
This adds the contents of items to tmp, and then adds our new item at the end. If you'd like your new item to be at the top of the stack, we can simply:
System.arrayCopy(items, 0, tmp, 1, items.length);
tmp[0] = new Items(str, sw1);
Change your adapter declaration. May be below code help you.
public class MainActivity extends Activity {
Switch sw1;
private ListView listView1;
ItemsAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
adapter = new ItemsAdapter (this,R.layout.items_row, Items_data);
}
public void getdata(View v) {
EditText et;
String dev_name;
et = (EditText)findViewById(R.id.editText1) ;
dev_name = et.getText().toString() ;
create(dev_name, null);
}
public void create (String str, Switch sw1) {
Items Items_data[] = new Items[]
{
new Items( str,sw1)
};
adapter = new ItemsAdapter (this,R.layout.items_row, Items_data);
listView1 = (ListView)findViewById(R.id.listView1);
listView1.setAdapter(adapter);
}
}
Check this link : Dynamically add elements to a listView Android

Get Selected value from Spinner inside ListView Android

I have a ListView of Spinners I'm trying to get the selected values out of. Some of the Spinners have the first selection automatically selected if there is only 1 item in the list, so I feel
setOnItemSelectedListener
won't necessarily work? Either way, I'm unsure how to code this scenario. Even if I had the listener coded correctly, How do I use it in my class to work with the adapter?
CustomAdapter
public class CustomPLNViewAdapter extends BaseAdapter{
private static ArrayList<ArrayList<String>> partLotNumbersArrayList;
private static ArrayList<String> partNames;
private LayoutInflater mInflater;
private Context myContext;
public CustomPLNViewAdapter(Context context, ArrayList<ArrayList<String>> results, ArrayList<String> parts){
partLotNumbersArrayList = results;
partNames = parts;
mInflater = LayoutInflater.from(context);
myContext = context;
}
#Override
public int getCount() {
return partLotNumbersArrayList.size();
}
#Override
public Object getItem(int position) {
return partLotNumbersArrayList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.view_assembly_parts, null);
holder = new ViewHolder();
holder.txtName = (TextView) convertView.findViewById(R.id.partName);
holder.spinner = (Spinner) convertView.findViewById(R.id.LotNumbers);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtName.setText(partNames.get(position));
ArrayAdapter<String> adp1=new ArrayAdapter<String>(myContext, android.R.layout.simple_list_item_1, partLotNumbersArrayList.get(position));
adp1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//set the adapter to the spinnner
holder.spinner.setAdapter(adp1);
//if there is only one other part besides "" then set that as default part
if(partLotNumbersArrayList.get(position).size() == 2){
holder.spinner.setSelection(1);
}
return convertView;
}
static class ViewHolder {
TextView txtName;
Spinner spinner;
}
}
Where I am calling the code. Obviously I get an error here because an ArrayList cannot be cast to Spinner, but I'm unsure how to get the View of the Adapter and then the subsequent spinner?
// save button click event
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Log.d("lv count", Integer.toString(lv.getCount()));
//iterate through listview,
for(int i = 0; i < lv.getCount(); i++){
Spinner temp = (Spinner) lv.getItemAtPosition(i);
Log.d("lv isItemCheck", temp.getSelectedItem().toString());
}
//check to make sure all items have been selected
if(!checkAllParts()){
Toast.makeText(getApplicationContext(), "Please Select All List Items", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getApplicationContext(), "All items have been selected", Toast.LENGTH_SHORT).show();
}
//go back to previous intent, return 100 that saving succeeded
//close intent
}
});

How do i send data to my custom adapter

After several tries to get a custom adapter working I am almost there. Now I have one problem left: get data in the adapter. This is what I do.
I have a CustomListAdapter class for the adapter, a sqLiteHelper class to CRUD data and a mainActivity class. In the mainActivity i load the customlist like this:
ListView list;
CustomListAdapter adapter;
public MainActivity CustomListView = null;
public ArrayList<Players> CustomListViewValuesArr = new ArrayList<Players>();
//button handlers newmatch_players_home
public void addSpelerNu(View button) {
Log.d("WedstrijdID buiten de create", ""+wedstrijdId);
Log.d("id return team thuis", ""+thuisTeamId);
//thuisteam
final EditText shirtNummer = (EditText) findViewById(R.id.shirtThuis);
String nummerShirt = shirtNummer.getText().toString();
int shirtSpeler = Integer.parseInt(nummerShirt);
final EditText spelerNaam = (EditText) findViewById(R.id.naamThuis);
String naamSpeler = spelerNaam.getText().toString();
Integer wedstrijdSpelerId = (int) (long) wedstrijdId;
SqLiteHelper db = new SqLiteHelper(this);
db.addSpeler(new Players(shirtSpeler, naamSpeler, thuisTeamId, wedstrijdSpelerId));
Log.d("Toevoegen speler THUIS", ">> BEGIN");
Log.d("Toevoegen speler", "Shirt = "+nummerShirt+" Naam = "+naamSpeler +" Team ="+thuisTeamId+" Wedstrijd ="+wedstrijdSpelerId);
Log.d("Toevoegen speler", ">> EIND");
shirtNummer.setText(null);
spelerNaam.setText(null);
CustomListView = this;
/******** Take some data in Arraylist ( CustomListViewValuesArr ) ***********/
ArrayList <Players> CustomListViewValuesArr = new ArrayList<Players>();
Resources res =getResources();
list= ( ListView )findViewById( R.id.listHome );
/**************** Create Custom Adapter *********/
adapter=new CustomListAdapter( CustomListView, CustomListViewValuesArr);
list.setAdapter( adapter );
}
This works except for the data. The data I want to use is in my sqlitehelper
public ArrayList<Players> getPlayersForTeam(int teamNumber,int matchNumber) {
ArrayList<Players> speler = new ArrayList<Players>();
String query = "SELECT * FROM " + TABLE_SPELERS + " WHERE team=? AND wedstrijd =?";
SQLiteDatabase db = this.getWritableDatabase();
String[] selectionArgs = new String[] { Integer.toString(teamNumber), Integer.toString(matchNumber) };
Cursor cursor = db.rawQuery(query, selectionArgs);
Players spelers = null;
if (cursor.moveToFirst()) {
do {
spelers = new Players();
spelers.setIdSpeler(Integer.parseInt(cursor.getString(0)));
spelers.setShirt(Integer.parseInt(cursor.getString(1)));
spelers.setSpeler(cursor.getString(2));
spelers.setTeam(Integer.parseInt(cursor.getString(3)));
spelers.setSpelerWedstrijd(Integer.parseInt(cursor.getString(4)));
speler.add(spelers);
} while (cursor.moveToNext());
}
Log.d("Alle spelers in DB for team:" + teamNumber, speler.toString());
// return wedstrijden
return speler;
}
If I load this data like this
List <Players> list = new ArrayList<Players>();
list=db.getPlayersForTeam(thuisTeamId,wedstrijdSpelerId);
I will see the log.d in logcat. But I just can't get that data into my CustomListViewValuesArr.
What should I do?
This is the customListAdapter class
package com.jd.wedstrijdkaart;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class CustomListAdapter extends BaseAdapter {
/*********** Declare Used Variables *********/
private Activity activity;
private ArrayList data;
private static LayoutInflater inflater=null;
Players tempValues=null;
int i=0;
/************* CustomAdapter Constructor
* #return *****************/
public CustomListAdapter(Activity a, ArrayList d) {
/********** Take passed values **********/
activity = a;
data=d;
/*********** Layout inflator to call external xml layout () ***********/
inflater = ( LayoutInflater )activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/******** What is the size of Passed Arraylist Size ************/
public int getCount() {
if(data.size()<=0)
return 1;
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
/********* Create a holder Class to contain inflated xml file elements *********/
public static class ViewHolder{
public TextView shirt;
public TextView name;
}
/****** Depends upon data size called for each row , Create each ListView row *****/
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder;
if(convertView==null){
/****** Inflate tabitem.xml file for each row ( Defined below ) *******/
vi = inflater.inflate(R.layout.adapter_players, null);
/****** View Holder Object to contain tabitem.xml file elements ******/
holder = new ViewHolder();
holder.shirt = (TextView) vi.findViewById(R.id.shirt);
holder.name=(TextView)vi.findViewById(R.id.name);
/************ Set holder with LayoutInflater ************/
vi.setTag( holder );
}
else
holder=(ViewHolder)vi.getTag();
if(data.size()<=0)
{
holder.name.setText("No Data");
}
else
{
/***** Get each Model object from Arraylist ********/
tempValues = null;
tempValues = ( Players ) data.get( position );
/************ Set Model values in Holder elements ***********/
holder.shirt.setText( tempValues.getShirt() );
holder.name.setText( tempValues.getSpeler() );
}
return vi;
}
}
In onCreate() you do this:
ArrayList <Players> CustomListViewValuesArr = new ArrayList<Players>();
...
adapter=new CustomListAdapter( CustomListView, CustomListViewValuesArr);
You are initializing your adapter with an empty list of items (CustomListViewValuesArr is empty).
You have 2 choices:
You can get the data from your database and pass it to the adapter when you initialize it.
You can initialize the adapter with an empty array and then later pass the data to the adapter. To do that you'll need to provide a setter method in the adapter, something like this:
public void setData(ArrayList d) {
data = d;
// Tell the views that the data has changed so they can refresh
notifyDataSetChanged();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
is totally wrong. Here is where you should return the objects at the specified position in your ArrayList.
Typically, when building custom adapters you want to pass your ArrayList into the constructor for your CustomListAdapter. It is relatively straight forward.
// Create a reference to your custom adapter as a Class Member and arraylist
CustomListAdapter mAdapter = null;
ArrayList<MyObjects> mArrayList = null;
// Initialize the adapter somewhere in onCreate
// After you have retrieved the data out of sql and created your custom object
mArrayList = new ArrayList<MyObjects>();
// Fill your array list with data
// ******* THIS IS WHERE YOU WANT TO RETRIEVE THE ITEM FROM SQLITE
// Then Each time your get a new cursor object
// You should create a new MyObject object and add it to the ArrayList
// Intialize the custom list adapter using the context, and your array list
mAdpater = new CustomListAdapter(getBaseContext(), mArrayList);
// Set ListView adapter
listView.setAdapter(mAdapter);
Then Create the Custom Adapter And use the constructor to pass the data
// Custom Adapter Class
public class CustomListAdapter extends BaseAdapter {
private ArrayList<MyObjects> mObjects = null;
private LayoutInflater mInflater = null;
// Private class to hold information about the row content UI Items
private class RowContent{
// Reference the UI Widgets for each row
TextView mTextView;
// etc.
}
// Constructor
public CustomListAdapter(Context context, ArrayList<MyObject> objects){
this.mInflater = LayoutInflater.from(context);
this.mObjects = objects;
}
// --------------------------------------------------
// BaseAdapter Overrides
// --------------------------------------------------
// Returns the count of your arrayList
#Override
public int getCount() {
int count = 0;
if(mObjects!=null && mObjects.length() >= 1){
count = mObjects.length();
}
return count;
}
// Returns object at position
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mOjbects[position];
}
// returns position
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
// This is where all the magic happens
// Creates a new row for each item in your arraylist
#Override
public View getView(int position, View convertView, ViewGroup parent) {
RowContent theRow;
// If ConvertVIew is null
if(convertView == null){
// Create a reference to the class holding the UI Elements
theRow= new RowContent ();
// set the view using your XML layout for a custom list item
convertView = mInflater.inflate(R.layout.custom_list_item, null);
// reference the UI widgets in the XML by their ID's
theRow.mTextView = (TextView) convertView.findViewById(R.id.textView);
// set the Tag for the View
convertView.setTag(theRow);
}else{
// If there is already an item, recycle it
theRow= (RowContent) convertView.getTag();
}
// Set the Text or arrays For UI Widgets
theRow.mtextView.setText(mObjects.get(position).text);
// return the view
return convertView;
}
}

Spinner with empty default selected item

I'm trying to create a spinner with default empty selected item, but it displays the first item from the choices of spinner. If I add null value to my string, which is the source of choices in spinner, then after opening spinner that empty row is displayed. How should I do it? Here's code I'm using:
String[] ch = {"Session1", "Session2", "Session3"};
Spinner sp = (Spinner)findViewById(R.id.spinner1);
TextView sess_name = findViewById(R.id.sessname);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,ch);
sp.setAdapter(adapter);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener({
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
int index = arg0.getSelectedItemPosition();
sess_name.setText(ch[index]);
Toast.makeText(getBaseContext(), "You have selected item : " + ch[index], Toast.LENGTH_SHORT).show();
}
Barak's solution have a problem. When you select the first item, Spinner won't call OnItemSelectedListener's onItemSelected() and refresh the empty content because the previous position and selection position both is 0.
First put a empty string at the begin of your string array:
String[] test = {" ", "one", "two", "three"};
Second build adapter, don't modify getView(), modify getDropDownView(). Set the empty View's height to 1px.
public class MyArrayAdapter extends ArrayAdapter<String> {
private static final int ITEM_HEIGHT = ViewGroup.LayoutParams.WRAP_CONTENT;
private int textViewResourceId;
public MyArrayAdapter(Context context,
int textViewResourceId,
String[] objects) {
super(context, textViewResourceId, objects);
this.textViewResourceId = textViewResourceId;
}
#Override
public View getDropDownView(int position, View convertView, #NonNull ViewGroup parent) {
TextView textView;
if (convertView == null) {
textView = (TextView) LayoutInflater.from(getContext())
.inflate(textViewResourceId, parent, false);
} else {
textView = (TextView) convertView;
}
textView.setText(getItem(position));
if (position == 0) {
ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
layoutParams.height = 1;
textView.setLayoutParams(layoutParams);
} else {
ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
layoutParams.height = ITEM_HEIGHT;
textView.setLayoutParams(layoutParams);
}
return textView;
}
}
I'm a little late to the party, but here is what I did to solve this.
If the user cancels out of selecting an initial item the spinner will retain the initial empty state. Once an initial item has been selected it works as 'normal'
Works on 2.3.3+, I have not tested on 2.2 and below
First, create an adapter class...
public class EmptyFirstItemAdapter extends ArrayAdapter<String>{
//Track the removal of the empty item
private boolean emptyRemoved = false;
/** Adjust the constructor(s) to fit your purposes. */
public EmptyFirstitemAdapter(Context context, List<String> objects) {
super(context, android.R.layout.simple_spinner_item, objects);
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}
#Override
public int getCount() {
//Adjust the count based on the removal of the empty item
if(emptyRemoved){
return super.getCount();
}
return super.getCount()-1;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if(!emptyRemoved){
// Remove the empty item the first time the dropdown is displayed.
emptyRemoved = true;
// Set to false to prevent auto-selecting the first item after removal.
setNotifyOnChange(false);
remove(getItem(0));
// Set it back to true for future changes.
setNotifyOnChange(true);
}
return super.getDropDownView(position, convertView, parent);
}
#Override
public long getItemId(int position) {
// Adjust the id after removal to keep the id's the same as pre-removal.
if(emptyRemoved){
return position +1;
}
return position;
}
}
Here is the string array I used in strings.xml
<string-array name="my_items">
<item></item>
<item>Item 1</item>
<item>Item 2</item>
</string-array>
Next, add an OnItemSelectedListener to your Spinner...
mSpinner = (Spinner) mRootView.findViewById(R.id.spinner);
String[] opts = getResources().getStringArray(R.array.my_items);
//DO NOT set the entries in XML OR use an array directly, the adapter will get an immutable List.
List<String> vals = new ArrayList<String>(Arrays.asList(opts));
final EmptyFirstitemAdapter adapter = new EmptyFirstitemAdapter(getActivity(), vals);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
//Track that we have updated after removing the empty item
private boolean mInitialized = false;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(!mInitialized && position == 0 && id == 1){
// User selected the 1st item after the 'empty' item was initially removed,
// update the data set to compensate for the removed item.
mInitialized = true;
adapter.notifyDataSetChanged();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// Nothing to do
}
});
It may not be a 'perfect' solution, but I hope it helps someone.
After some thinking, I believe I've come up with a method to achieve your goal. It involves creating a
custom adapter and setting/maintaining a flag to determine if an item from the spinner has been selected.
Using this method you do not need to create/use false data (your empty string).
Basically, the adapters getView method sets the text for the closed spinner. So if you override that
and set a conditional in there, you can have a blank field on startup and after you make a selection have
it appear in the closed spinner box. The only thing is you need to remember to set the flag whenever you
need to see the value in the closed spinner.
I've created a small example program (code below).
Note that I only added the single constructor I needed for my example. You can implement all the standard
ArrayAdapter constructors or only the one(s) you need.
SpinnerTest.java
public class SpinnerTestActivity extends Activity {
private String[] planets = { "Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune" };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Spinner spinner = (Spinner) findViewById(R.id.spinner);
CustomAdapter adapter = new CustomAdapter(this, // Use our custom adapter
android.R.layout.simple_spinner_item, planets);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
CustomAdapter.flag = true; // Set adapter flag that something
has been chosen
}
});
}
}
CustomAdapter.java
public class CustomAdapter extends ArrayAdapter {
private Context context;
private int textViewResourceId;
private String[] objects;
public static boolean flag = false;
public CustomAdapter(Context context, int textViewResourceId,
String[] objects) {
super(context, textViewResourceId, objects);
this.context = context;
this.textViewResourceId = textViewResourceId;
this.objects = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = View.inflate(context, textViewResourceId, null);
if (flag != false) {
TextView tv = (TextView) convertView;
tv.setText(objects[position]);
}
return convertView;
}
}
Here is what I use. It properly handles null (empty) selection in a generic manner. It works with any model class T, as long as class T properly implements toString(), to display the text shown in the spinner, and equals(), so that items may be selected by reference rather than by positional index.
package com.10xdev.android.components;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* A spinner where no selection is possible, and other enhancements.
* requires model class to properly implement Object.equals, with semantic comparaison (such as id comparaison)
* and a proper toString(), whose result will be displayed in the spinner
*
* #author tony.benbrahim
*/
public class EnhancedSpinner<T> extends Spinner {
private final EnhanceArraySpinnerAdapter<T> spinnerAdapter;
private final List<T> items = new ArrayList<>();
private T selected = null;
public EnhancedSpinner(final Context context, final AttributeSet attributeSet) {
super(context, attributeSet);
spinnerAdapter = new EnhanceArraySpinnerAdapter<>(context, items);
setAdapter(spinnerAdapter);
}
/**
* sets the items to be displayed
*
* #param items
*/
public void setItems(final List<T> items) {
this.items.clear();
//very iffy, but works because of type erasure
this.items.add((T) "");
this.items.addAll(items);
spinnerAdapter.notifyDataSetChanged();
updateSelected();
}
/**
* set the selected item. this may be called before or after setting items
*
* #param item the item to select, or null to clear the selection
*/
public void setSelected(final T item) {
this.selected = item;
updateSelected();
}
/**
* gets the selected item, or null if no item is selected
*
* #return
*/
#Override
public T getSelectedItem() {
return getSelectedItemPosition() != 0 ? (T) super.getSelectedItem() : null;
}
/**
* set the error message for the select
*
* #param errorMessage
*/
public void setError(final String errorMessage) {
final TextView errorText = (TextView) getSelectedView();
errorText.setError("error");
errorText.setTextColor(Color.RED);
errorText.setText(errorMessage);
}
private void updateSelected() {
if (selected == null) {
setSelection(0);
} else {
for (int i = 1; i < items.size(); ++i) {
if (selected.equals(items.get(i))) {
setSelection(i);
break;
}
}
}
}
private class EnhanceArraySpinnerAdapter<T> extends ArrayAdapter<T> {
private final LayoutInflater inflater;
public EnhanceArraySpinnerAdapter(final Context context, final List<T> objects) {
super(context, android.R.layout.simple_spinner_item, objects);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getDropDownView(final int position, final View convertView, final ViewGroup parent) {
final TextView textView = convertView != null ? (TextView) convertView
: (TextView) inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
final Object item = getItem(position);
textView.setText(item.toString());
final ViewGroup.LayoutParams layoutParams = textView.getLayoutParams();
layoutParams.height = position == 0 ? 1 : LayoutParams.WRAP_CONTENT;
textView.setLayoutParams(layoutParams);
return textView;
}
}
}
You have to put the first element of the spinner empty, or with an string indicating that nothing is selected like the following:
String[] ch= {"","Session1", "Session2", "Session3"};
or
String[] ch= {"Nothing selected", "Session1", "Session2", "Session3"};
hope to help

Categories

Resources