I'm creating an app for a bus station, to give the schedule. For that i'm using a custom listview. Here it is:
class custom_adapter extends ArrayAdapter<String>{
public custom_adapter(Context context, ArrayList<String> horarios) {
super(context, R.layout.costum_listview ,horarios);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater horarioInflater = LayoutInflater.from(getContext());
View costumView = horarioInflater.inflate(R.layout.costum_listview, parent, false);
String singleHorario = getItem(position);
TextView hora = (TextView) costumView.findViewById(R.id.Hora);
TextView nota = (TextView) costumView.findViewById(R.id.Nota);
hora.setText(singleHorario);
nota.setText(" ");
return costumView;
}
}
Now as you can see I have just 2 texViews yet, the "hora" is to show the timers of the bus, the "nota" is for some notes, like someday the bus don't go or something like that. And my problem is exactly on that "nota" textview. I have dozens of arrayList's passing to this custom ListView, and so dozens and dozens of timers, and there are some timers that I need to put a note and other that I don't. So, can I had another argument to this custom ListView, like a boolean or something, so I can do a if / else in that code to put a note on each one. What do I need to change in order to do that ? I've been trying, but didn't quite managed to do that.
Instead of using a String as the argument for your ArrayAdapter, create a custom class and use that instead.
That way you can pass all the information you want into the adapter and show it however you like.
public class custom_adapter extends ArrayAdapter<MyClass>{
public custom_adapter(Context context, ArrayList<MyClass> horarios) {
super(context, R.layout.costum_listview ,horarios);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater horarioInflater = LayoutInflater.from(getContext());
View costumView = horarioInflater.inflate(R.layout.costum_listview, parent, false);
MyClass singleHorario = getItem(position);
TextView hora = (TextView) costumView.findViewById(R.id.Hora);
TextView nota = (TextView) costumView.findViewById(R.id.Nota);
hora.setText(singleHorario.hora);
nota.setText(singleHorario.nota);
return costumView;
}
And the new class
public class MyClass {
public String hora;
public String nota;
}
How about making a class for holding two values 'hora' and 'nota', and with, lets say, boolean isNotaAvailable() method. Then in getView() you just make something like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater horarioInflater = LayoutInflater.from(getContext());
View costumView = horarioInflater.inflate(R.layout.costum_listview, parent, false);
YourClassName singleHorario = getItem(position);
TextView hora = (TextView) costumView.findViewById(R.id.Hora);
TextView nota = (TextView) costumView.findViewById(R.id.Nota);
// set hora text
hora.setText(singleHorario);
// check if nota is available, if true - set nota text
if(singleHorario.isNotaAvailable()) {
nota.setText(singleHorario.getNota())}
else nota.setVisibility(View.GONE);
return costumView;
}
It's just an idea, tell me if it helps :)
Just extend BaseAdapter, so you can define the data structure.
class custom_adapter extends BaseAdapter
change ArrayList<String> horarios to ArrayList<Data> horarios
And the Data can be
public class Data{
private String hora;
private String nota;
private boolean shouldShowNota;
//write getter and setter here
}
at last, read the data in getView
Data data = getItem(position);
if (data.getShouldShowNota) {
nota.setText(data.getNote);
}
hora.setText(data.getHora);
Related
I have a listView of custom views. Each view contains an editText. I'm trying to add listeners to the editText variables which I create in the getView(). The problem is that when I create the listeners it doesn't let me use the editText variable unless I make it final, but if I make it final, I guess I'm going to have problems when the row gets reused. This is a simple example of what my problem is:
private class MyAdapter extends ArrayAdapter<Date>{
public MyAdapter(Context context, int resource, int textViewResourceId,
List<Date> objects) {
super(context, resource, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.listview_cell_single, parent, false);
}else{
row = convertView;
}
EditText et = (EditText) row.findViewById(R.id.editText_single);
et.setText("" + position);
et.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus){
et.setText("You edited row: " + position);
//Error: et must be final, position must be final
}
}
});
You should declare this EditText et as a class variable in MyAdapter. As
private class MyAdapter extends ArrayAdapter<Date>{
EditText et;
}
And then initiate it in getView(); method.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//do your stuff
........
et=(EditText) row.findViewById(R.id.editText_single);
}
This is a contract between scopes, i.e. the stack versus the heap. The reference created on the stack must be final to declare that the reference will not (and cannot) be changed since the reference is basically bound by the anonymous class (OnFocusChangeListener) using it.
The reference will not be reused since each stack will get its own copy of the reference to the EditText object.
I am trying to make a custom style for android spinner, however there are several problems.
I have noticed in many examples, they pass array to getCustomView method. I am wondering whether I can pass a list instead of an array.
Second problem is why they have declared variable and initialized in class variable scope?
They have declared arrays like this.
String []data1={"Brainbitz:java","Brainbitz:Android","Brainbitz:Embedded Systems","Brainbitz:PHP"};
in class variable scope. But when I try to do for the list I get an error. why?
Third is,
If we can pass list to getCustomView how do I do that? Here is the link to the tutorial tutorial
I am considering this source code.
public View getCustomView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.spinner, parent, false);
TextView label=(TextView)row.findViewById(R.id.textView1);
label.setText(list3.get(position));
// TextView sub=(TextView)row.findViewById(R.id.textView2);
// sub.setText(data2[position]);
//
// ImageView icon=(ImageView)row.findViewById(R.id.imageView1);
// icon.setImageResource(images[position]);
return row;
}
In above code I don't know the syntax to pass position to list3 list type reference.
Please be kind enough to explain this.
First of All,
You are using default ArrayAdapter Class..
new ArrayAdapter<String>();
Which Uses String class for data bind. If you want to make an ArrayAdapter with a ArrayList or List you have to make a Custom Adapter by extending ArrayAdapter<Custom_Class> or BaseAdapter.
The ArrayAdapter class can handle any Java object as input. It maps the data of this input to a TextView in the layout.
ArrayAdapter uses the toString() method of the data input object to determine the String which should be displayed.
Look at How to use ArrayAdapter<myClass> and this Tutorial
Update:
public class MyAdapter extends ArrayAdapter<String>
{
private List<String> listString = new ArrayList<String>();
public MyAdapter(Context context, int textViewResourceId,
List<String> objects) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
listString = objects;
}
public View getCustomView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.spinner, parent, false);
TextView label=(TextView)row.findViewById(R.id.textView1);
label.setText(listString.get(position)); // How to use listString
.
.
.
Here is the corrected solution,
public class MyAdapter extends ArrayAdapter<String>
{
public MyAdapter(Context context, int textViewResourceId,List<String> objects) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
}
#Override
public View getDropDownView(int position, View convertView,ViewGroup parent) {
return getCustomView(position, convertView, parent);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return getCustomView(position, convertView, parent);
}
public View getCustomView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.spinner, parent, false);
TextView label=(TextView)row.findViewById(R.id.textView1);
label.setText(list3.get(position));
// TextView sub=(TextView)row.findViewById(R.id.textView2);
// sub.setText(data2[position]);
//
// ImageView icon=(ImageView)row.findViewById(R.id.imageView1);
// icon.setImageResource(images[position]);
return row;
}
}
Basiclly, I had done 1 mistake, one is I hadnt initalised constructor correctly.
I would like to display two values in an drop down view of my spinner.
Currently, it only has a city name, but I would also like to add a small distance field to it.
MyCity<MyCityDistance> dataAdapter;
dataAdapter = new MyCity(this, R.layout.mycityrow, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
I have all the code for custom data adapter, exapanding my view and holder etc.
However, the item which gets show doesn't display both the city and its distance from my current location.
It only shows what is overridden in toString() method of MyCityDistance class.
I even tried setting
dataAdapter.setDropDownViewResource(R.layout.mycityrow);
but, no success. It throws an error.
04-02 11:05:22.600: E/AndroidRuntime(367): java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView
04-02 11:05:22.600: E/AndroidRuntime(367): at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:347)
04-02 11:05:22.600: E/AndroidRuntime(367): at android.widget.ArrayAdapter.getDropDownView(ArrayAdapter.java:376)
04-02 11:05:22.600: E/AndroidRuntime(367): at android.widget.Spinner$DropDownAdapter.getDropDownView(Spinner.java:332)
What is a good example of creating your own custom setDropDownViewResource()?
Even if I comment out the setDropDownViewResource() line, I get the same error.
Note: The only effect mycityrow current is that the first element of Spinner is show as per the layout of mycityrow. However, when I click open the drop down, that layout is lost. I want the same layout during drop down selection too.
Note the below example uses the inbuilt android.R.layout.simple_list_item_2, Unfortunately the text color will probably be the same as the background. You can simply solve this by creating your own custom view and use it in the adapter instead.
Let me know if i should explain any part of it.
public class MainActivity extends Activity {
class City {
public City(String city, int d) {
this.city = city;
this.distance = String.valueOf(d);
}
String city;
String distance;
}
class CityAdapter extends ArrayAdapter<City> {
public CityAdapter(Context context, List<City> objects) {
super(context, android.R.layout.simple_list_item_2, objects);
}
#Override //don't override if you don't want the default spinner to be a two line view
public View getView(int position, View convertView, ViewGroup parent) {
return initView(position, convertView);
}
#Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
return initView(position, convertView);
}
private View initView(int position, View convertView) {
if(convertView == null)
convertView = View.inflate(getContext(),
android.R.layout.simple_list_item_2,
null);
TextView tvText1 = (TextView)convertView.findViewById(android.R.id.text1);
TextView tvText2 = (TextView)convertView.findViewById(android.R.id.text2);
tvText1.setText(getItem(position).city);
tvText2.setText(getItem(position).distance);
return convertView;
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Spinner spinner = (Spinner)findViewById(R.id.spinner1);
List<City> list = new ArrayList<MainActivity.City>();
for(int i = 0; i < 10; i++)
list.add(new City(String.format("City %d", i + 1), (i + 1) * 1000));
spinner.setAdapter(new CityAdapter(this, list));
}
}
Try commenting the line dataAdapter.setDropDownViewResource() and the adapter will try to use the mycityow layout file for the drop down as well. Works in simple cases.
I want to have an access to another XML file in an inner class but I can't get a reference to the other XML components, this an inner class code:
class ItemsClass extends ArrayAdapter<String>
{
public ItemsClass ()
{
super(ListActivity.this, R.layout.itemslist);
}
public View getView (final int position, View convertview, ViewGroup parent)
{
//setContentView(R.layout.itemslist);
final String s = this.getItem(position);
LayoutInflater inflater= getLayoutInflater();
View row= inflater.inflate(R.layout.itemslist, parent, false);
// get ref to each component in itemList.xml
TextView itemName= (TextView) row.findViewById(R.id.textView1);// here i can't access to the TextView in itemslist.xml
}
}
View row= inflator.inflate(R.layout.itemslist, null);
read this
http://www.vogella.de/articles/AndroidListView/article.html
I am not sure why you are trying to using the same xml for both the main activity & the row component.I think you need to reiterate your code,check about the neccesity of the usage of the constructor here.Cheers.
I am new to Android, so this may seem like a basic question. But what I got is a very simple class called SingleItem, which has an integer and a String and a getter and setter for each. In my application, I got an ArrayList which holds a collection of SingleItem objects. I also have a layout with a ListView widget.
What I am trying to do is populate the ListView with my String value in SingleItem, but when a user selects an item from the ListView, I need the integer ID from that SingleItem value. How do I do this in Android development?
If you are using your own adapter to populate the list then in the getView() function when building the view to return you can call setTag() on the view you are returning and store the entire "SingleItem" object. Then in the onClickListener of the views you return you can retrieve your info using the getTag() method of the view that has been clicked.
EDIT:
Specified which onClickListener I am referring to
here is a bunch of pseudo code: create your own adapter. This will give the flexibility to do all kinds of things but important to you here is displaying only the relevant fields from your custom class and make more complicated listviews. a decent tutorial is here: http://developerlife.com/tutorials/?p=327
You will have to handle the other overrides of baseadapter but the key is assigning the value of singleItem.getString()
public class SingleItemAdapter extends BaseAdapter{
private ArrayList<SingleItem> m_items= new ArrayList<SingleItem>();
private Context mContext;
public SingleItemAdapter (Context c,ArrayList<SingleItem> items) {
mContext = c;
m_items= items;
}
.
.
.
#Override
public Object getItem(int arg0) {
return m_items.get(arg0);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.singleitemview, null);
}
SingleItem i=(SingleItem) getITem(position)
if(v!=null){
TextView tv=(TextView) v.findViewById(R.id.yourListItemView);
tv.setText(i.getStringValue());
}
}
}
After defining your custom adapter, you can then assign it to the listview and assign a listener to the OnItemSelectedListener. since this returns the position, you can tie that back to the position in your ArrayList of SingleItems.
.
.
.
SingleItemAdapter sia=new SingleItemAdapter(this,yourArray);
yourArrayList.setAdapter(sia);
yourArrayList.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View v, int position, long row) {
SingleItem si= yourArray.getItem(position);
//do something with si.getValue();
}
.
.
.
});