ListView id not valid - android

i've got a problem with an activity with root element ListView. I've followed this tutorial to load items into listview and all work. But i've tried to change the id of the listview and now, when the activity is loading, i receive this problem:
Your content must have a ListView whose id attribute is "android.R.id.list"
I retried to change id to "list" but i've got the same problem. I don't have problems in compiling but in run-time. This is the code of the activity when i load the listview.
public class StartActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
//Section inflating
adapter.addSection(getString(R.string.equationmenu), new ArrayAdapter<Object>(this,
android.R.layout.simple_list_item_1, new String[] {getString(R.string.eq1title), getString(R.string.eq2title), getString(R.string.eqfractitle)}));
setListAdapter(adapter);
}
SectionedAdapter adapter = new SectionedAdapter() {
protected View getHeaderView(String caption, int index,
View convertView, ViewGroup parent) {
TextView result = (TextView) convertView;
if (convertView == null) {
result = (TextView) getLayoutInflater().inflate(
R.layout.header, null);
}
result.setText(caption);
return (result);
}
};
}
And this is the xml of the activity:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="true" />
Anyone can help me? :)

If you extend from ListActivity you have to let the id of the ListView in your xml
(android:id="#android:id/list")
If you want to change the Id or use more than one ListView in your Activity than you have to
extend from Activity and inflate a ListView yourself..
For example like below:
ListView list1 = (ListView) findViewById(R.id.myList1);
list1.setAdapter(...);
ListView list2 = (ListView) findViewById(R.id.myList2);
list2.setAdapter(...);

Related

Choppy ProgressBar performance when used in ListView

I recently encountered an issue where the animation of an indeterminate ProgressBar used inside of a ListView row became choppy. In a nutshell, I have a ListView where each row contains a ProgressBar. The animations look great, until I scroll; from then on, at least one of the ProgressBar will have a choppy animation.
Does anyone know how to fix this problem?
View for the ListView row
<?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">
<ProgressBar
android:indeterminate="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Simple custom ArrayAdapter
public class MyAdapter extends ArrayAdapter {
List list;
public MyAdapter(Context context, List objects) {
super(context, 0, objects);
list = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = ((LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.list_row, parent, false);
}
return convertView;
}
}
OnCreate() method for the sample Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ListView listView = (ListView)findViewById(R.id.list_view);
ArrayList<Integer> data = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16,17));
MyAdapter adapter = new MyAdapter(this, data);
listView.setAdapter(adapter);
}
Bug logged (contains sample project): https://code.google.com/p/android/issues/detail?id=145569&thanks=145569&ts=1423673226
Try implementing the view holder pattern and check the performance.
Create a static ViewHolder class with a progress bar.
static class ViewHolder {
ProgressBar progress;
}
and in your getView() you get find the view holder from the view only when the convertView is null, otherwise take it from the tag holding the viewHolder. This way you are inflating a new view only when the convertView is null, otherwise you are using the views stored in your viewholder tag.
A simple tutorial can be found here.
it is happening for the first time only, if you close and reopen the app, you will not notice it.
Did you check in older versions like kitkat?
And dont create LayoutInflater in the getView(), create once in the constructor and use it in the constuctor

Dynamically adding custom row to listview

By referring this, I created following:
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/addBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="addItems"
android:text="Add New Item" />
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
ListView list;
ArrayList<String> listItems = new ArrayList<String>();
ArrayAdapter<String> adapter;
int clickCounter = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list = (ListView) findViewById(R.id.list);
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, listItems);
list.setAdapter(adapter);
list.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String item = list.getItemAtPosition(position).toString();
Log.i("MainActivity", "Selected = " + item);
}
});
}
public void addItems(View v) {
listItems.add("Clicked : " + clickCounter++);
adapter.notifyDataSetChanged();
}
}
And it's working perfectly. But as per requirements, my each listview row won't just be a single string. Instead, it'll be collection of views consisting of imageview and textviews stored in row.xml.
Now my queries are:
What will replace adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, listItems); ? Will it be adapter = new ArrayAdapter<String>(this,R.layout.row, listItems); ??
How do I refer to imageview and textviews of each row? How do I set and get data from them? How do I recognize their click events?
Is use of Adapter must? or can I get away with it?
Any help appreciated.
But as per requirements, my each listview row won't just be a single
string. Instead, it'll be collection of views consisting of imageview
and textviews stored in row.xml.
=> The ListView you are displaying is using normal adapter. If you want your item contains multiple views like Imageview, Textview or any view, then you have to define Custom adapter class by extending either BaseAdapter or ArrayAdapter.
What will replace adapter = new
ArrayAdapter(this,android.R.layout.simple_list_item_1,
listItems); ? Will it be adapter = new
ArrayAdapter(this,R.layout.row, listItems); ??
=> Here ArrayAdapter will not work because your row xml layout may contains different views like ImageView, TextView, Button or any other widget. So I would suggest you to define your own adapter class where you have to override getView() method.
How do I refer to imageview and textviews of each row? How do I set
and get data from them? How do I recognize their click events?
=> As I said above, once you define custom adapter class, you will have to override getView() method where you can find any views of your row xml layout file, reference it and set/display whatever data you want.
Is use of Adapter must? or can I get away with it?
=> Yes its must, without adapter you won't be able to display in data-binded widgets like GridView, ListView, Spinner, Gallery, etc.
Example for defining custom adapter:
My talk on ListView
http://www.vogella.com/articles/AndroidListView/article.html
These are the basic steps:
Create a custom layout for your row (maybe with an ImageView and TextView in it). You used android.R.layout.simple_list_item_1 in your example which if you look into the Android source is just a layout with a single TextView.
Create a class that extends BaseAdapter. This will be your list adapter. You can pass the data to your adapter through the constructor or a method. Create a field where you will store the data.
Now to answer your questions:
How do I refer to imageview and textviews of each row?
How do I set and get data from them?
How do I recognize their click events?
When you extend BaseAdapter you will implement the method public View getView (int position, View convertView, ViewGroup parent). In this method you have to inflate your custom row layout to create the view. Then find the ImageView and TextView using the findViewById method. When you have the ImageView and TextView you call setText or setImageSource to set your data and setOnClickListener for the click events.
Here is code from my project
Consider your list have two text field and one ImageView as following "row.xml" file. Copy this to your res folder
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/row_q"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="Solve[{x^2==4,x+y^2==6},{x,y}]"
android:textAppearance="#android:style/TextAppearance.Small"
android:textStyle="bold|italic" />
<TextView
android:id="#+id/row_a"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/AliceBlue"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:textAppearance="#android:style/TextAppearance.Small" />
<ImageView
android:id="#+id/row_a_math"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>
<LinearLayout
android:id="#+id/graph_layout"
android:layout_width="match_parent"
android:layout_height="200dp"
android:visibility="gone" >
</LinearLayout>
Create following class in your activity to store this data
private class QuesSolnInfo {
public String ques;
public String ans;
public Bitmap ans_b;
public QuesSolnInfo(String ques, String ans, Bitmap ans_b) {
this.ques = ques;
this.ans = ans;
this.ans_b = ans_b;
}
}
//Make following as class members
OutputStringArrayAdapter _outputArrayAdapter = null;
ArrayList<QuesSolnInfo> _outputArrayList = null;
//Initialize them in onCreate Method
_outputArrayAdapter = new OutputStringArrayAdapter(getActivity(), _outputArrayList);
_outputListView.setAdapter(_outputArrayAdapter);
Definitition of ArrayAdapter
protected class OutputStringArrayAdapter extends ArrayAdapter<QuesSolnInfo> {
OutputStringArrayAdapter(Context context, ArrayList<QuesSolnInfo> stringArrayList) {
super(context, R.layout.list, stringArrayList);
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row, null);
}
TextView t_ques = (TextView) convertView.findViewById(R.id.row_q);
t_ques.setText(getItem(position).ques);
boolean debug = true;
TextView t_ans = (TextView) convertView.findViewById(R.id.row_a);
String texx = getItem(position).ans;
t_ans.setText(texx);
final ImageView w = (ImageView) convertView.findViewById(R.id.row_a_math);
w.setImageBitmap(getItem(position).ans_b);
// Show answer in webview
return convertView;
}
}
Now to add any element to your list do following
_outputArrayList.add(0, new QuesSolnInfo(string1.string2, bitmap0));
_outputArrayAdapter.notifyDataSetChanged();

Android ListView in Fragment

I am trying to create a list of items which contains an image and some description for the image in each individual. After which, the list will be place in a fragment inside the application. Can anyone guide me to create it? I am not too sure how can I do it without the ListActivity.
It seems like your Fragment should subclass ListFragment (not ListActivity). onCreateView() from ListFragment will return a ListView you can then populate.
Here's more information on populating lists from the developer guide: Hello, ListView
Here's a code snippet to help you display ListView in a fragment.:
public class MessagesFragment extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_messages, container,
false);
String[] values = new String[] { "Message1", "Message2", "Message3" };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
return rootView;
}
}
And, this is how the xml would look like:
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
If you do not use 'list' as ID or do not include a ListView into your layout, the application crashes once you try to display the activity or the fragment.
Reference: http://www.vogella.com/tutorials/AndroidListView/article.html#listfragments

Can I make one ListView item have a different Text Color?

I have the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="#+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:textColor="#android:color/white"
android:dividerHeight="1px"
android:listSelector="#drawable/highlight_sel"
/>
</LinearLayout>
And the code:
private ListView lv1;
private String lv_arr[]={"Item 1","Item 2","Item 3","Item 4"};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newsmenu);
lv1=(ListView)findViewById(R.id.ListView01);
// By using setAdpater method in listview we an add string array in list.
lv1.setAdapter(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
lv_arr));
}
I want the text color of Item 2 (or 1 or 3 or 4) to appear dynamically as red (denoting a new item) or white (default). Is there a way to do this?
I already have a selector present, which is why I used ListView. I've search the Internet and this site, and I have not seen this question broached.
So is it possible?
Yes everything is possible. you need to write your own adapter implementation basically overriding the getView Method in the adapter. search google and stack you will find many tutorials on how to write an adapter.
Writing a special adapter to override getView in simple adapter is the way to change the text color alternating on the lines of your choice in a listview. I took the example which has been repeated many times on this website and added a way to change the text color. position mod length to select the color position can be replaced with any scheme you like. The text view "business" can be the first line of your layout like mine--or use the android.R.id.text1.
public class SpecialAdapter extends SimpleAdapter {
private int[] colors = new int[] { 0x30FF0000, 0x300000FF };
public SpecialAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
int colorPos = position % colors.length;
//view.setBackgroundColor(colors[colorPos]); //old example
TextView tv1 = (TextView)view.findViewById(R.id.business); //new
tv1.setTextColor(colors[colorPos]); //new
return view;
}
}
Just use SpecialAdapter instead of SimpleAdapter in your app.
Here's an example of a getView method. Note that it's using a viewholder for efficiency. If you want to know more about that, let me know.
public View getView(int position, View convertView, ViewGroup parent) {
tempDeal = exampleBoxArrayList.get(position);
ViewHolder holder;
if (convertView == null) {
convertView = inflator.inflate(R.layout.list_item_example_box, null);
holder = new ViewHolder();
holder.divider = (RelativeLayout) convertView.findViewById(R.id.example_box_divider);
holder.merchantName = (TextView) convertView.findViewById(R.id.example_box_merchant_name);
holder.expireDate = (TextView) convertView.findViewById(R.id.example_box_expire_date);
holder.description = (TextView) convertView.findViewById(R.id.example_box_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (tempDeal.isDivider()) {
holder.divider.setVisibility(View.VISIBLE);
} else {
holder.divider.setVisibility(View.GONE);
}
holder.merchantName.setText(tempDeal.getMerchantName());
holder.expireDate.setText(tempDeal.getExpiryDateString());
holder.description.setText(tempDeal.getPriceOption().getDescription());
return convertView;
}
As you can see, I call the isDivider() method on my custom object (this method looks at a boolean set on data load). This method is used to turn the visibility of part of the layout on or off.
Alternatively, you could load a completely new layout based on this same concept.

Android ListView with delete button

I am trying to bind a list view to a List. This works ok when I create an activity that extends ListActivity and I have a text view in my layout file (i.e. the activity is binding to the default listview in the activity). However, what I would like to do is have a ListView that contains an image button (to further perform the deeltion of the row) and the text view to illustrate the name of the item being bound.
Can anyone point me in the direction that would show how to do this that contains:
The layout file
The activity class
I have played around and cant seem to get it to work, as soon as I add a ListView / image button to the layout file my code crashes. I've also found a few examples through google, but none seem to work!
You can get List functionality even if you do not extend ListActivity, but also via extending Activity. To achieve that, you need layout file with explicitly named ListView element, as illustrated below.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Details_RelativeLayout01">
<ImageView android:layout_centerHorizontal="true"
android:layout_alignParentTop="true" android:id="#+id/Details_ImageView01"
android:layout_marginTop="10dip" android:layout_width="60dip"
android:layout_height="60dip"></ImageView>
<ListView android:layout_width="fill_parent"
android:drawSelectorOnTop="false" android:clipChildren="true"
android:fitsSystemWindows="true" android:layout_height="fill_parent"
android:layout_below="#+id/Details_ImageView01" android:id="#+id/Details_ListView01">
</ListView>
</RelativeLayout>
Here I have list of results below some image. In your Activity class you must extend ArrayAdapter. Also, you need to define the look of one list row. In example below it is done in the R.layout.one_result_details_row.
public class ListOfDetails extends Activity {
private DetailsListAdapter mDetailsListAdapter;
private Vector<String> mDetailsTimeStringsList;
private Vector<String> mDetailsDateStringsList;
private ListView mDetailsListView;
private int mSelectedPosition;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.detailed_results_list);
ListView mDetailsListView = (ListView) findViewById(R.id.Details_ListView01);
ImageView mSelectedPuzzleIcon = (ImageView) findViewById(R.id.Details_ImageView01);
mDetailsListAdapter = new DetailsListAdapter();
mDetailsListView.setAdapter(mDetailsListAdapter);
mDetailsTimeStringsList = new Vector<String>();
mDetailsDateStringsList = new Vector<String>();
updateTheList();
}
class DetailsListAdapter extends ArrayAdapter<String> {
DetailsListAdapter() {
super(ListOfDetails.this, R.layout.one_result_details_row);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = null;
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.one_result_details_row, parent, false);
TextView result = (TextView) row.findViewById(R.id.Details_Row_TextView01);
TextView date = (TextView) row.findViewById(R.id.Details_Row_TextView02);
Button deleteButton = (Button) row.findViewById(R.id.Details_Button01);
deleteButton.setOnClickListener(
new Button.OnClickListener() {
#Override
public void onClick(View v) {
confirmDelete();
}
}
);
return(row);
}
}
}
Delete button onClickListener() calls some function to confirm deletion. Of course, it has to be done in respect to the current position in the list.
This code snippet is just illustration, but I hope it will be useful to solve your issue.
Found this in the end which was the most complete example:
http://techdroid.kbeanie.com/2009/07/custom-listview-for-android.html

Categories

Resources