Custom adapter won't inflate rows in list view - java

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).

Related

How to recover view from View.gone. setVisibility(View.VISIBLE) not working after using 'android:visibility="gone"' in xml

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

How to count the number of checkboxes ticked which is inside a listview

I have an custom array adaptor which is handling a list view.
Each row has two checkboxes. There are five rows in total.
I want to be able to count the number of checkboxes ticked and then display this number in Stand1
So basically the project Layout is like this
Inside stand1 there is a list view and a text view.
The stand1.java calls an array adapter Called CustomArrayAdaptor.
I want to be able to count the number of checkboxes clicked and send that data back to the stand1
I am quite new to android development so if somebody can be able to push me in the right direction, it would be great.
Here is my code
Stand1.xml
<?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="match_parent">
<ListView
android:layout_width="fill_parent"
android:layout_height="446dp"
android:id="#+id/Stand1list"
android:scrollIndicators="right"
android:smoothScrollbar="true">
</ListView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Score To Databse"
android:id="#+id/sendtodb"
android:textSize="12dp"
android:clickable="true"
android:layout_below="#+id/Stand1list"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="8/10"
android:id="#+id/Score"
android:layout_marginLeft="33dp"
android:layout_marginStart="33dp"
android:layout_alignBottom="#+id/sendtodb"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="10dp" />
Row_Layout1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/textelement"
xmlns:android="http://schemas.android.com/apk/res/android"
android:textSize="30dp"
android:textStyle="bold"
android:longClickable="false" />
<CheckBox
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/Checkbox1"
android:button="#drawable/checkboxcustom"
android:layout_marginLeft="50dp" />
<CheckBox
android:button="#drawable/checkboxcustom"
android:id="#+id/Checkbox2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="50dp" />
</LinearLayout>
Stand1.java
public class Stand1 extends Fragment {
ListView mList;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.stand1,container,false);
mList = (ListView) root.findViewById(R.id.Stand1list);
return root;
}
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
populateListView();
}
private void populateListView() {
String[] pair = {"Pair 1","Pair 2","Pair 3","Pair 4","Pair 5"};
//build adapter
ArrayAdapter<String> adapter = new CustomArrayAdaptor(getActivity(),pair);
mList.setAdapter(adapter);
}
}
CustomArrayAdaptor.java
public class CustomArrayAdaptor extends ArrayAdapter<String>{
public CustomArrayAdaptor(Context context, String [] Pairs) {
super(context, R.layout.row_layout1, Pairs);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View CustomView = inflater.inflate(R.layout.row_layout1, parent, false);
String stringelement = getItem(position);
TextView Text= (TextView)CustomView.findViewById(R.id.textelement);
Text.setText(stringelement);
return CustomView;
}
}
Thanks Folks
I added a few things to your CustomArrayAdaptor and tested it, see below:
public class CustomArrayAdapter extends ArrayAdapter<String> {
int checkAccumulator;
public CustomArrayAdapter(Context context, String [] Pairs) {
super(context, R.layout.row_layout1, Pairs);
checkAccumulator = 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View customView = inflater.inflate(R.layout.row_layout1, parent, false);
String stringelement = getItem(position);
TextView Text = (TextView) customView.findViewById(R.id.textelement);
CheckBox checkBox1 = (CheckBox) customView.findViewById(R.id.Checkbox1);
CheckBox checkBox2 = (CheckBox) customView.findViewById(R.id.Checkbox2);
CompoundButton.OnCheckedChangeListener checkListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
countCheck(isChecked);
Log.i("MAIN", checkAccumulator + "");
}
};
checkBox1.setOnCheckedChangeListener(checkListener);
checkBox2.setOnCheckedChangeListener(checkListener);
Text.setText(stringelement);
return customView;
}
private void countCheck(boolean isChecked) {
checkAccumulator += isChecked ? 1 : -1 ;
}
}
Added int checkAccumulator to keep track of how many items have been clicked.
Added two CheckBox Views for the purpose of tracking checks.
Added CompoundButton.OnCheckedChangeListener that calls a new countCheck method everytime any checkBox is checked / unchecked. We pass the isChecked boolean to track whether we need to add or subtract from our checkAccumulator.
Added countCheck function that adds or subtracts 1 dependent on the boolean. Sorry for the obfuscated code, for all those who aren't used to the ? conditional it is basically saying if true add 1, else add -1.
Not sure what you wanted to do with the check count, so I added a Log.i("MAIN", checkAccumulator + ""); just so you can watch the Android Monitor to ensure that it is actually working.
Should work for you.
First of all, you should recycle your views in the adapter:
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null) {
convertView = inflater.inflate(R.layout.row_layout1, parent, false);
}
After that, I think you should save the state of each checkbox in your data source or just keep a list, the same size of your pair array, and save it there using the position you get from getView.

How can I setText to a TextView in every single row of my ListView

Hi guys I am new to Android and also to stackoverflow, Greetings and thanks for the help.
I have 2 Xml files for the same activity. One that contains a ListView and the second as my custom layout for an ArrayAdapter that populates a ListView which is also included on my first layout:
<include android:id="#+id/lv" layout="#layout/lv_row" />
ListView Custom Layout (lv_row.xml):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/icon"
android:src="#drawable/ic_launcher"/>
<TextView
android:layout_toRightOf="#+id/icon"
android:layout_width="fill_parent"
android:layout_height="38dp"
android:textSize="30sp"
android:id="#+id/label"/>
<TextView
android:layout_toRightOf="#+id/icon"
android:layout_below="#+id/label"
android:layout_width="fill_parent"
android:layout_height="12dp"
android:gravity="bottom"
android:id="#+id/label2"
android:textSize="12sp"/>
</RelativeLayout>
This is my adapter:
final ArrayAdapter<String> Array = new ArrayAdapter<String>(this,R.layout.lv_row,R.id.label,myList);
I save strings one by one into "myList" and display them on my ListView, what I want to do is to enumerate the elements on my list view by using idNum.setText(iterating_variable.toString())... but it won't work because idNum always get the value that was set on the XML file.
This is the code I use to link the second XML with my Java code
lv = (RelativeLayout) findViewById(R.id.lv);
idNum = (TextView) lv.findViewById(R.id.label2);
Thanks again for your help.
create custom Adapter and setText() in getView() method of adapter
like
class CustomAdapter extends BaseAdapter {
private ArrayList<String> mList;
private LayoutInflater mInflater;
public CustomAdapter(ArrayList<String> list) {
mList = list;
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mList.size() ;
}
#Override
public Object getItem(int position) {
return mList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = mInflater.inflate(R.layout.lv_row, null);
((TextView) convertView.findViewById(R.id.label2)).setText(mList.get(position));
return convertView;
}
}
and set on ListView

accessing a specific view from onclick listener inside getView of customer adapter

I want the onclick method to communicate with the other views in my layout. I am getting a NullPointerException when attempting to do so. I think I may be doing it wrong.
My getView method is below:
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolder holder;
final int p =position;
if (v == null) {
LayoutInflater vi = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.menuitemrow, null);
holder = new ViewHolder();
holder.image = (ImageView) v.findViewById(R.id.MIR_itemImage);holder.image.setTag(position);
holder.itemName = (TextView)v.findViewById(R.id.MIR_itemName);holder.itemName.setTag(position);
holder.itemPrice = (TextView)v.findViewById(R.id.MIR_itemPrice);holder.itemPrice.setTag(position);
holder.itemOther = (TextView)v.findViewById(R.id.MIR_itemOther);holder.itemOther.setTag(position);
holder.details = (Button) v.findViewById(R.id.MIR_detailsbtn);holder.details.setTag(position);
holder.qAdd = (Button) v.findViewById(R.id.MIR_qaddbtn);holder.qAdd.setTag(position);
v.setTag(holder);
} else
holder = (ViewHolder) v.getTag();
MenuItemDetail mid = _data.get(position);
holder.image.setImageResource(mid.icon);
holder.itemName.setText(mid.itemName);
holder.itemPrice.setText("Price: $"+mid.itemPrice);
holder.itemOther.setText(mid.itemOther);
//set click listeners
holder.details.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
m =_data.get(p);
s = m.getItemName();
Toast.makeText(_c, "clicked details"+p+" "+s, Toast.LENGTH_SHORT).show();
}
});
holder.qAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(_c, "clicked quick add "+p, Toast.LENGTH_SHORT).show();
TextView btnUpdate = (TextView) v.findViewById(R.id.CBV_textview2);
//btnUpdate.setTag(1);
//btnUpdate.setText(btnUpdate.getTag().toString());
btnUpdate.setText("b");
}
});
return v;
}
as you can see I am just assigning a number to the getTag just to pass it to the setText method. I have tried it commenting out the set and get, using just a String.
the problematic line is btnUpdate.setText("b");
Any ideas?
to summarize I am trying to access a TextView of a custom Button inside of a custom ListView from its customer adapter's getView method.
UPDATE for comment:
This is a Custom Listview being displayed with other buttons. I want the listview item (a button that is part of the custom ListView) when it is click to update the textview of a custom button I created that is displayed in the same acitivity as the custom list view.
The Layout is below:
<?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" >
<Button
android:id="#+id/MI_backbutton"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_weight="1"
android:text="#string/back_list_categories"
android:textSize="#dimen/FontSize8" />
<ListView
android:id="#+id/menuList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="20" >
</ListView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_marginBottom="5dp"
android:layout_weight="1" >
<Button
android:id="#+id/button2"
style="#android:style/Widget.Button"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_weight="1"
android:text="#string/generalbutton" />
<include
android:id="#+id/MI_checkorder"
style="android:buttonStyle"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_marginTop="5dp"
android:layout_weight="1"
layout="#layout/custombtnview"
android:background="#style/AppTheme"
android:clickable="true"
android:focusable="true" />
</LinearLayout>
In the view I am referencing to get the Textview, the textview is not there. What is in that view is the MI_checkorder. I was thinking maybe this is why I am getting the NullPointerException for my btnUpdate. the textveiw CBV_textview2 is part of the view I created as a button(MI_checkorder).
I now have the button but I am unable to get the change to show on the UI. Here is the code I added:
public void onClick(View v) {
Toast.makeText(_c, "clicked quick add "+p, Toast.LENGTH_SHORT).show();
TextView btnUpdate = (TextView) inflateToEdit(_c, v).findViewById(R.id.CBV_textview2);
//btnUpdate.setTag(1);
//btnUpdate.setText(btnUpdate.getTag().toString());
btnUpdate.setText("b");
}
and this is the method I created in the custom adapter class.
public View inflateToEdit(Context c, View view){
View vw = view;
LayoutInflater vi = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return vi.inflate(R.layout.custombtnview, null);
}
It is updating the button's text but it is not showing on the UI. I do not think i can update the UI from this point in the code. I think I need to do it from the activity.
That's because findViewById called on a view looks for the child view of the given view.
findViewById doc
"Look for a child view with the given id. If this view has the given id, return this view."
From what I can see, CBV_textview2 is contained in the layout of the activity.
So, what you can do is to pass the activity to the adapter's constructor (I see you already have a _c member variable which I suppose is a Context, OR directly pass the CBV_textview2 itself (calling findViewById in the containing activty).
In both cases, you need to call the activity's findViewById which
"Finds a view that was identified by the id attribute from the XML that was processed in onCreate(Bundle)."
public class YourAdapter extends ArrayAdapter<String> {
private final Context context;
// blahblahblah
private final TextView mYourTextView;
public YourAdapter(Context context, String[] values, TextView btnUpdate) {
super(context, R.layout.rowlayout, values);
this.context = context;
this.values = values;
mYourTextView = btnUpdate;
}
....
#Override
public void onClick(View v) {
Toast.makeText(_c, "clicked quick add "+p, Toast.LENGTH_SHORT).show();
//mYourTextView.setTag(1);
//mYourTextView.setText(btnUpdate.getTag().toString());
mYourTextView.setText("b");
}
In your activity you should be able to get the TextView before calling the constructor.

Android - Multiple textviews in Listview

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. :)

Categories