I am populating a Listview (list.xml) with a textview (list_row.xml).
I need to add an additional textview to list_row.xml, which means I need to wrap them in a layout. However, I get a Textview ID error when I do this.
list_row.xml I need:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/nameTV"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="#FFFF00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Main.xml
public View GetView(int inPosition, View inConvertView, ViewGroup inParent)
{
View _row = inConvertView;
if (_row == null)
{
// Inflate Row
Log.d(TAG, "Starting XML Row Inflation ... ");
LayoutInflater inflater = (LayoutInflater)
cContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
_row = inflater.inflate(R.layout.list_row, inParent, false);
Log.d(TAG, "Successfully completed XML Row Inflation!");
}
// Get item
PropertiesAd _adProperty = GetItem(inPosition);
// Get reference to TextView - country_name
cAdName = (TextView) _row.findViewById(R.id.nameTV);
//Set name
cAdName.setText(_adProperty.toString());
return _row;
}
For the sake of testing, I haven't added the second textview yet. I'm just trying to get this to work with the layout wrapper.
Everything works fine without the LinearLayout. But again, I will need it to add a second textview. Suggestions?
Thanks
ArrayAdapter:
public class ArrayAdapterAd extends ArrayAdapter<PropertiesAd>
{
private static final String TAG = "AdArrayAdapter";
private Context cContext;
private TextView cAdName;
private List<PropertiesAd> cAdList = new ArrayList<PropertiesAd>();
public ArrayAdapterAd(Context inContext, int inTextViewResourceId, List<PropertiesAd> inObjects)
{
super(inContext, inTextViewResourceId, inObjects);
this.cContext = inContext;
this.cAdList = inObjects;
}
public int GetCount()
{
return this.cAdList.size();
}
public PropertiesAd GetItem(int inIndex)
{
return this.cAdList.get(inIndex);
}
public View GetView(int inPosition, View inConvertView, ViewGroup inParent)
{
View _row = inConvertView;
if (_row == null)
{
// Inflate Row
Log.d(TAG, "Starting XML Row Inflation ... ");
LayoutInflater inflater = (LayoutInflater)
cContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
_row = inflater.inflate(R.layout.ad_list, inParent, false);
Log.d(TAG, "Successfully completed XML Row Inflation!");
}
// Get item
PropertiesAd _adProperty = GetItem(inPosition);
// Get reference to TextView - country_name
cAdName = (TextView) _row.findViewById(R.id.ad_listTextView);
//Set country name
cAdName.setText(_adProperty.toString());
return _row;
}
}
Now I see your problem... you cannot do that extending the ArrayAdapter class. Instead, extend BaseAdapter.
Here is xml for a listview "list_row" with 2 textviews
<?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="wrap_content"
android:orientation="horizontal">
<TextView android:id="#+id/text1" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:id="#+id/text2" android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
I'm assuming the getView() is from an ArrayAdapter subclass? If so, what does your constructor look like? Perhaps you're passing in an id reference in stead of a layout reference? This will probably resolve fine if you're whole layout is nothing more than a single TextView, but could explain why an error occurs when wrapping it in a layout.
Also, don't forget to implement the rowwrapper/viewholder pattern to improve performance and recycle views. For an example, have a look here.
By the way, you may even suffice with one of the Android built-in layouts. There a two line list item layout defined in android.R.layout.simple_list_item_2. It may not suit your needs though, as the styling on the two elements is different. A custom layout is always the most flexible in the end. :)
Related
My issue:
In my xml file, I define android:visibility="gone" in the linear layout labelled as assess_layout_list. Then, in the onClick() of course_adapter_layout, the whole view, I set the visibility back to View.VISIBLE, which does not work, even though the Log call just before it works, the LinearLayout object called assess_list_layout is not null, and it does work when I define the visibility="invisible" in the xml file. I want it to be gone at first though, and visible after clicking as this fits the design of the app.
Here is my course_adapter_view.xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/course_adapter_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="left"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="20dp"
android:padding="15dp"
android:elevation="2dp"
android:background="#drawable/course_header_background">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="#drawable/course_color_circle"/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"/>
<TextView
android:id="#+id/course_adapter_course_code"
android:text="TextView1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_weight="0.5"/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"/>
<TextView
android:id="#+id/course_adapter_course_title"
android:text="TextView2"
android:layout_width="wrap_content"
android:layout_height="20dp"/>
</LinearLayout>
<LinearLayout
android:id="#+id/assess_list_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginRight="40dp"
android:layout_marginLeft="40dp"
android:background="#drawable/course_body_background"
android:padding="20dp"
android:visibility="gone"
>
<ListView
android:id="#+id/course_adapter_assess_list"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_marginBottom="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="More" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="New"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
Here is my CourseListAdapter.java file that I use to create each view for each course in the list of courses, minus the usual stuff:
package com.example.schoolplanner2.adapters;
public class CourseListAdapter extends ArrayAdapter<Course> {
private static final String TAG = "CourseListAdapter";
private Context context;
int mResource;
public CourseListAdapter(#NonNull Context context, int resource, #NonNull ArrayList<Course> objects) {
super(context, resource, objects);
this.context = context;
mResource = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// get info
String course_code = getItem(position).getCourseCode();
Double course_grade = getItem(position).getCurrentGrade();
// make inflater and inflate the layout
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(mResource, parent, false);
TextView tv_course_code = v.findViewById(R.id.course_adapter_course_code);
TextView tv_course_title = v.findViewById(R.id.course_adapter_course_title);
tv_course_code.setText(course_code);
tv_course_title.setText(String.valueOf(course_grade));
// add on click to each list view element
LinearLayout layout = v.findViewById(R.id.course_adapter_layout);
layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i(TAG, "List view element has been clicked " + course_code);
// expand the view to include a new fragment
LinearLayout assess_list_layout = view.findViewById(R.id.assess_list_layout);
assess_list_layout.setVisibility(View.VISIBLE);
// get the list view and add each course to the course view
ListView assessment_list_view = (ListView) view.findViewById(R.id.course_adapter_assess_list);
AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, getItem(position).getAssessmentList(), getItem(position));
assessment_list_view.setAdapter(assessAdapter);
}
});
return v;
}
}
Please let me know if there is any more information you need. Will also take suggestions on other ways of accomplishing the same thing. Thanks for your help.
~Seth.
Edit: when the assess_list_layout.setVisibility(View.VISIBLE) is outside of the onClick it does work.
Further Edit: Things I have tried so far to no avail:
moving the location of where I define the LinearLayout componenent
calling invalidate() on parent view
using runOnUiThread()
changing view to v in the line where I attempt to findViewById for assess_list_layout, they are the same thing so it does not help.
calling requestLayout() on assess_list_layout
Update: I have now managed to get the assess_list_layout section to appear when the course_adapter_layout is clicked on. The only problem now is that the view does not take up anymore space on the screen, it just turns into a scrollable view that can be scrolled up and down on to see the whole view.
Also, when I scroll to fast, it resets the view back to the way it was on bootup.
1.View Visibility not working
The Visibility is not working because the view is not rendered initially. Remove the visibility gone in the xml and handle the visibility fully in the adapter class. In the 'assess_list_layout' linerlayout height can be hardcode because inside this layout the listview height is already hardcoded. You can hardcode to 300 and check. This way will help the view to get the initial rendering.
2. Scroll issue
While scrolling the already visible 'assess_list_layout' view might be not visible. This is because we need to handle the visibility, this handling is similar to checkbox selection handling in listview. Hope the Course class is model class, in that add a another property named isSelected as boolean and set the default value to false. Please refer below the course class,
Course Class
public class Course {
private boolean isSelected = false;
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
}
please refer the below code changes in the adapter class.
public class CourseListAdapter extends ArrayAdapter<Course> {
private static final String TAG = "CourseListAdapter";
private Context context;
int mResource;
public CourseListAdapter(#NonNull Context context, int resource, #NonNull ArrayList<Course> objects) {
super(context, resource, objects);
this.context = context;
mResource = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// get info
String course_code = getItem(position).getCourseCode();
Double course_grade = getItem(position).getCurrentGrade();
// make inflater and inflate the layout
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(mResource, parent, false);
TextView tv_course_code = v.findViewById(R.id.course_adapter_course_code);
TextView tv_course_title = v.findViewById(R.id.course_adapter_course_title);
//My Change
// expand the view to include a new fragment
LinearLayout assess_list_layout = view.findViewById(R.id.assess_list_layout);
// get the list view and add each course to the course view
ListView assessment_list_view = (ListView) view.findViewById(R.id.course_adapter_assess_list);
assess_list_layout.setVisibility(View.GONE);
if (getItem().get(position).isSelected()) {
assess_list_layout.setVisibility(View.Visible);
AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, getItem(position).getAssessmentList(), getItem(position));
assessment_list_view.setAdapter(assessAdapter);
}
//My Change
tv_course_code.setText(course_code);
tv_course_title.setText(String.valueOf(course_grade));
// add on click to each list view element
LinearLayout layout = v.findViewById(R.id.course_adapter_layout);
layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i(TAG, "List view element has been clicked " + course_code);
//My Change
getItem().get(position).setSelected(true);
//My Change
assess_list_layout.setVisibility(View.VISIBLE);
AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, getItem(position).getAssessmentList(), getItem(position));
assessment_list_view.setAdapter(assessAdapter);
}
});
return v;
}
}
I have commented as My Change to find the difference in the code.
issue 1
// make inflater and inflate the layout
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(mResource, parent, false);
you don't reuse view,which leads to inflate a new view every time when called getView();As inflate() method is IO sensitive,it slow down the smoothness of scrolling ,trigger jank。
try this
// make inflater and inflate the layout
View v = null;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
v= inflater.inflate(mResource, parent, false);
} else {
v = convertView;
}
issue 2
when scorll listview ,you need reset itemview state,add a "expand" property to your Course bean ,when click item set expand = true;and then add flowing code above layout.setOnClickListener
v.findViewById(R.id.assess_list_layout).setVisibility( item.expand ? View.VISIBLE:View.GONE);
ListView assessment_list_view = (ListView) v.findViewById(R.id.course_adapter_assess_list);
if (item.expand) {
AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view,
item.getAssessmentList(), item);
assessment_list_view.setAdapter(assessAdapter);
}
issue 3
set setOnClickListener in getView() method , will create a new Clicker instance every time getView() called. use listView.setOnItemClickListener() instead
tips:
after all,you should use RecyclerView instead of ListView,which is a powerful UI widget
I'm working on an application that parses data from an external file and then creates a listview with custom adapter. The adapter inflates the individual rows from a xml layout. The row is made of two parts - the buttons part which is the same for each row and the text part, which is build dynamically from the parsed data in the source arraylist.
The problem I have is that some of the rows do not render correctly the first time around. Here is a link to an image of the desired result :
http://postimg.org/image/4dvtv8qe5/
Note the numbers between the buttons - theese represent the order of elements in source arraylist. However, when first setting the adapter to the listview, I get this result :
http://postimg.org/image/hogyy7qgh/
Several of the rows render into theese fat chunks, showing none of the textviews I added to them in the adapter. The textviews are however there - I have tried assigning IDs to them and then succesfully found them by id and returned their text.
Some of the rows render correctly the first time around. The order of the defective rows is constant between renders but changes when parsing data from a different external file.
After scrolling so that the defective row is no longer visible in the listview and scrolling back, the row in question renders correctly (that is how I got the desired result screenshot).
I can't post more than 2 links due to reputation limits but after changing the code to let the app do all the work and then set the text of the textview to "text" regardless of what it parsed, I got a similair problem. The order and quantity of defective rows changed.
It also seems like the first two rows of the listview are always defective no matter what file I parse from.
I'm running this on a Lenovo X2-EU with 4.4.2 android if that's of any help.
Thank you in advance for any aid you can give me.
Here's my custom adapter :
public class AdapterCardList extends ArrayAdapter {
private String TAG = "AdapterCardList";
private Context theContext;
private ArrayList<Card> theCards; //the source arraylist
public Hammer theHammer; //holds some data
public int number;
public AdapterCardList(Context context, int rowLayout, ArrayList<Card> cards, Hammer hammer) {
super(context, rowLayout, cards);
theCards = cards;
theContext = context;
theHammer = hammer;
number = 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView;
if ((convertView==null)){
LayoutInflater inflater = (LayoutInflater) theContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.row_of_card_list, parent, false);
}
else{
rowView = convertView;
}
LinearLayout rowLayout = (LinearLayout) rowView.findViewById(R.id.rowHorizontalTextLayout);
rowLayout.removeAllViews();
TextView quantText = (TextView) rowView.findViewById(R.id.textViewQuantity);
quantText.setText(String.valueOf(position));
int allCollLength = rowView.findViewById(R.id.rowHorizontalLayout).getWidth()-rowView.findViewById(R.id.rowHorizontalButtonsLayout).getWidth();
int oneCollLength = (int)(((float)allCollLength)/(theHammer.elementsToPrint.length+1));
Boolean toBePrinted = false;
for (int i = 0; i < theCards.get(position).returnTypesLength(); i++) {
//I parse more info than I show in listview. Here I decide if I show.
if (theHammer.elementsToPrint[x].equals(theCards.get(position).returnType(i))) {
toBePrinted = true;
x = theHammer.elementsToPrint.length;
}
else if (theHammer.primaryIdentifier.equals(theCards.get(position).returnType(i))) {
toBePrinted = true;
x = theHammer.elementsToPrint.length;
}
else {
toBePrinted=false;}
}
if (toBePrinted) {
Log.d(TAG, "Authorised to print the value of type " + theCards.get(position).returnType(i));
TextView newText = new TextView(theContext);
newText.setLayoutParams(new LinearLayout.LayoutParams(oneCollLength, LinearLayout.LayoutParams.WRAP_CONTENT));
newText.setId(i);
Log.d(TAG, "Set the id to " + newText.getId());
String textToSet = theCards.get(position).returnValue(i);
newText.setText(textToSet);
rowLayout.addView(newText);
Log.d(TAG, "Added the value :" + theCards.get(position).returnValue(i));
}
}
return rowView;
}
}
and here is my layout for a row
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/rowHorizontalLayout" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#color/green"
android:layout_centerVertical="true"
android:id="#+id/rowHorizontalButtonsLayout">
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text="-"
android:id="#+id/button2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="0"
android:id="#+id/textViewQuantity"
/>
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text="+"
android:id="#+id/button3"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/red"
android:layout_alignParentLeft="true"
android:id="#+id/rowHorizontalTextLayout"
android:layout_toStartOf="#id/rowHorizontalButtonsLayout"
android:layout_alignParentStart="false">
</LinearLayout>
When developing an android application in java, I have a mainActivity which sets up a list adapter in the following way:
private void refreshDisplay()
{
adapter = new ItemAdapter(this, R.layout.listview_item_row, myList);
setListAdapter(adapter);
}
This method refreshDisplay is called when data making up the list is changed via user input and the mainactivity is returned to after completing the edit activity.
The list itself is composed of a ListView inside the MainActivity.xml file, which loads a list_item_row_layout thus:
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</ListView>
and inside the list_item_row.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/TitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"/>
<TextView
android:id="#+id/DetailText"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:clickable="true" />
</RelativeLayout>
Inside the list adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
myHolder holder;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new itemHolder();
holder.titleText = (TextView)row.findViewById(R.id.TitleText);
holder.textDetail = (TextView)row.findViewById(R.id.DetailText);
row.setTag(holder);
}
else
{
holder = (myHolder)row.getTag();
}
myItem = data.get(position);
holder.titleText.setText(myItem.getText());
holder.textDetail.setText(myItem.getDetail());
if (holder.textDetail.getVisibility()==0) {
holder.titleText.setVisibility(8);
holder.textDetail.setVisibility(0);
}
else if (holder.titleText.getVisibility()>0) {
holder.textDetail.setVisibility(8);
holder.titleText.setVisibility(0);
}
else {
holder.titleText.setVisibility(0);
holder.textDetail.setVisibility(8);
}
return row;
}
When the list is generated it displays without problem, and even runs correctly as far as accepting the first click which is supposed to expand the TitleText into the more verbose DetailText. So the DetailText starts with a Visibility of GONE and the TitleText is set to VISIBLE. If the user clicks on the listitem then it does successfully switch to the DetailText field. But the problem arises when the same item is clicked on again - the TitleText field does not replace the detailed version. I did initially think the DetailText was not clickable - but what puzzles me now is that if one of the other list items are clicked on then the original expanded one reverts back to the title and the clicked on one expands correctly! But how can I make it so that the expanded list item can be contracted into the title text without expanding another list item? Is there some problem that means a list item that is set to VISIBLE in code cannot be then set back to GONE or INVISIBLE even?
Had to use a bit of a hack in the end since was nearing the end of my usable hair to tear out haha.
Since reverting back to all todos with titles displayed was also just the way things appeared when the activity was first created - I put the following code in where the second click happened.
There is a bit of a pause though before this diplays on my HTC One, it remains to be seen when I test it on slower phones if its an acceptable solution.
Intent intentstart = new Intent(MainActivity.this, MainActivity.class);
intentstart.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intentstart);
I have created a custom listview and a custom adapter. However, when I show the activity it appears empty (although I made sure and there are people in the array passed to the adapter).
1) Why won't it show the people list? Is there something wrong in my getView or in my onCreate function?
2) How can I make a list view that is surrounded by another view (searchbar on top list at the bottom)?
Here is the adapters getView function:
#Override
public View getView(int postion, View convertView, ViewGroup parent)
{
View rowView = convertView;
if (rowView == null)//set the convert view and the viewholder
{
LayoutInflater inflater = _context.getLayoutInflater();
rowView = inflater.inflate(_layoutResourceId, null,false);
ViewHolder viewHolder = new ViewHolder();
viewHolder._personName = (LargeTest) rowView.findViewById(R.id.personName);
viewHolder._personBirthDate = (TextView) rowView.findViewById(R.id.personBirthDate);
viewHolder._icon = (ImageView) rowView.findViewById(R.id.personPic);
rowView.setTag(viewHolder);
}
ViewHolder holder = (ViewHolder) rowView.getTag();
Person person=_persons.get(postion);//get current person for the list row
String personName = person.get_firstName()+" "+person.get_lastName();
((TextView) holder._personName).setText(personName);
String birthDate=person.get_birthDate()+";"+person.get_hebBirthDate();
holder._personBirthDate.setText(birthDate);
//TODO change icon to a real image for each Person
holder._icon.setImageResource(R.drawable.about_me);//test icon
return rowView;
}
Here is the listview onCreate function:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//TODO remove the test case
//addTestPersons();//add a test case
//setContentView(R.layout.person_list_activity);
PersonDbHelper dbHelper=new PersonDbHelper(this);
ArrayList<Person> persons =dbHelper.getAllPeopleAsPersonList();//get list to display
PersonListAdapter adapter=new PersonListAdapter(this, R.layout.person_list_row, persons);
setListAdapter(adapter);
}
And the XML for list_row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/personPic"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/about_me" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/personName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Person Name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/personBirthDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1990-2001" />
</LinearLayout>
</LinearLayout>
Implement the getCount method in the adapter:
public int getCount(){
return _persons.size();
}
For the second part, add the headerview, create an XML layout for the view that you want to show on top of listview. Inflate it and add as headerview to your listview:
LayoutInflater inflater = this.getLayoutInflater();
View headerView = inflater.inflate(R.layout.header_view, null,false);
getListView().addHeaderView(headerView,null,false);
Because of the naming of the layout, you are passing "R.layout.person_list_row" to your adapter. I assume that you are passing the layout for one item in the array on which the adapter operates on instead of passing the ListView.
The constructor needs the ListView to be passed while in its getView, the layout for the row is constructed (inflated).
I am trying to style the resulting strings in a ListView.
I have a ListView layout, and the following onCreate method for the corresponding Activity.
private List<Address> addressList;
public class AddressesActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addresses);
AddressDBHandler datasource = new AddressDBHandler(this);
datasource.open();
List<Address> values = datasource.getAllAddresses();
MyAdapter adapter = new MyAdapter(this, android.R.layout.simple_list_item_1, addressList);
setListAdapter(adapter);
}
.
.
.
The following is my xml file:
<?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="match_parent"
android:orientation="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
<TextView
android:id="#android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="51dp"
android:gravity="center"
android:textSize="20sp"
android:textStyle="bold"
android:text="#string/no_addresses" />
I was told to make the MyAdapter class as follows:
public class MyAdapter extends ArrayAdapter<Address> {
Context context;
int layoutResourceId;
public MyAdapter(Context context, int layoutResourceId, List<Address> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
StringHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new StringHolder();
holder.txtTitle = (TextView) row.findViewById(R.id.text1);
row.setTag(holder);
}
else
{
holder = (StringHolder)row.getTag();
}
Address addressItem = getItem(position);
Spanned format = Html.fromHtml("<br/><span color='red'>" + addressItem.getAddress() + "</span><br/>" + addressItem.getName() + "<br/>");
holder.txtTitle.setText(format);
return row;
}
static class StringHolder
{
TextView txtTitle;
}
My problem is in understanding :
holder.txtTitle = (TextView) row.findViewById(R.id.text1),
I am unsure what R.id.text1 is supposed to be.
I do have an additional question: Where are #android:id/empty and #android:id/list being referenced? Seems that they are default expectations from ArrayAdapter?
#android:id/empty and #android:id/list are predefined ids that are part of the android platform. ListActivities and ListFragments expect that these are present (or atleast that android:id/list is present) in the layout xml file. It means you don't have to bind these views from the xml yourself.
holder.txtTitle = (TextView) row.findViewById(R.id.text1)
The line above is basically finding a view in the xml file, and binding it to a variable for use in your activity (or in that case your list row).
The R.id.text1 is the id of the view in your layout. It's what you would set in the android:id field of your xml view.
e.g.
<TextView android:id="#+id/mytextview"
android:layout_width="match_parent"
android:layout_height="match_parent">
In the case of your code above, you don't have a custom row layout, you are using a layout that is part of the android sdk (android.R.layout.simple_list_item_1). This layout has a textview with the id android.R.id.text1.
So, if you want to customise your list row, create your own layout file. You can put 1 textview, or multiple views in the layout.
You will then need to add those views to your StringHolder class, and bind up the views like is already being done with holder.txtTitle.
Change the instantiation of the adapter to reference your custom layout:
new MyAdapter(this, R.layout.my_awesome_layout, addressList);
Edit: It would be a really good idea to have a read through this to familiarise yourself a little more with listviews.