Using holder for textview in listview - android

I'm implementing a ListView with 2 TextViews in it. The first TextView is the name of the product that I'm populating from a query. When I touch any item in the ListView a Dialog appears. When I confirm the Dialog I would like to change the second TextView text to string but whenever I do so every second Textview text changes. For example, if I have 3 items in list view and I click the first one only that item's text view should change instead of all three.
This is my base adapter code:
public class StrengthAdapter extends BaseAdapter {
private ArrayList<Strengths> list;
private LayoutInflater layoutInflater;
private static HashMap<Integer, String> selectedStrengthsMap = new HashMap<Integer, String>();
private String testing;
public StrengthAdapter(Context context, ArrayList<Strengths> list, String test) {
this.list = list;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.testing = test;
//HashMap<Integer, String> issuesStrengthsbrandNameIDMap = context
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
//viewHolder.position = position;
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
viewHolder.chip.setText(testing);
//viewHolder.position = position;
return convertView;
}
public static HashMap<Integer, String> sendSelectedStrengthMap(){
return selectedStrengthsMap;
}
static class ViewHolder {
TextView strengthCheckBox;
TextView chip;
//int position;
}
}
This is how my I set my adapter initially:
strengthListView.setAdapter(new StrengthAdapter(StrengthOfDemandsView.this, strengthsList, "TEST"));
and this is how I set my adapter after closing the dialog:
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
strengthListView.setAdapter(new StrengthAdapter(StrengthOfDemandsView.this, strengthsList, "TEST123"));
}
});

You need to handle clicks inside of your adapter and not setting adapter every time click happens. It have to look like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
//viewHolder.position = position;
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
convertView.setOnClickListener(
// show dialog here and then in positiveButton callback call
//viewHolder.chip.setText(testing);
);
return convertView;
}

First of all inflate your layout before creation of holder.
Then you need to define onclick behavior by implementing onclicklistener. I updated your getView method please implement this as follows:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder = new ViewHolder();
//viewHolder.position = position;
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
viewHolder.chip.setText(testing);
//viewHolder.position = position;
convertView.setOnClickListener(
//you can do your job here what u want to do by clicking specific row
);
return convertView;
}
Also write your functionalities in the block I mentioned above in comments.

Related

ListView Custom Adapter repeat items

Whats wrong with this adapter, when i scroll down i see repeated rows at the bottom and then when scroll up again i see also repeated rows at the top that were not exist before, and the rest of Data items does not appear
the adapter:
public class ClassesListViewAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> Data = new ArrayList<>();
public ClassesListViewAdapter(Context context, ArrayList<String> data) {
Data = data;
mContext = context;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getCount() {
return Data.size();
}
private class ViewHolder{
TextView ClassDataTV;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
holder.ClassDataTV.setText(Data.get(position));
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
return convertView;
}
}
and here how i use it:
ArrayList<String> v = new ArrayList<>();
v.add("AAAAAAA");
v.add("WWWWWwW");
v.add("VVVVVVV");
v.add("SSSSSSSSS");
v.add("QQQQQQQQQ");
v.add("YYYYYYYY");
v.add("TTTTTTT");
v.add("UUUUUUUUUU");
v.add("zzzzzzzzzzzz");
v.add("CCCCCCCCCC");
v.add("HHHHHHHHHHH");
v.add("IIIIIIIIII");
v.add("PPPPPPPPP");
mListView.setAdapter(new ClassesListViewAdapter(getActivity(), v));
Put following part of your code outside if-block and it will be fixed :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
// initialize your view here
holder.ClassDataTV.setText(Data.get(position));
return convertView;
}
The logic behind ViewHolder pattern tells that you should do it in this way. when you scroll some of reference will not created again and else block called so this cause your list not updated as you expected.

App to choose layout according to situations

I am making a messaging android app, but my question is, how can I make the app choose either to pick the right hand layout or left hand layout? Like we see in messaging apps like WhatsApp, if I am the sender, my Message is wrapped in a right hand layout whilst the persons messages am chatting with are wrapped in a left handed layout, How can I achieve this type of Interface or layout I should say?
Below is my code, the app simple receives data from a remote database and puts it in a listview, using a custom adapter:
// the Data being set to the adapter
private ArrayList<ListItem> getListData() {
ArrayList<ListItem> listMockData = new ArrayList<ListItem>();
String[] username = mUsername.toArray(new String[mUsername.size()]);
String[] comments = Comment.toArray(new String[Comment.size()]);
for (int i = 0; i < username.length; i++) {
ListItem newsData = new ListItem();
newsData.setUsername(username[i]);
newsData.setmComment(comments[i]);
listMockData.add(newsData);
System.gc();
}
return listMockData;
}
And my custom adapter utilizing a single view:
public class CommentAdapter extends BaseAdapter{
private ArrayList<ListItem> listData;
private LayoutInflater layoutInflater;
ViewHolder holder;
public CommentAdapter(Context context, ArrayList<ListItem> listData) {
this.listData = listData;
notifyDataSetChanged();
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.singlecomment, null);
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.usernme);
holder.message = (TextView) convertView.findViewById(R.id.postCommentBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ListItem newsItem = listData.get(position);
holder.username.setText(newsItem.getUsername());
holder.message.setText(newsItem.getmComment());
return convertView;
}
static class ViewHolder {
TextView username;
TextView message;
}
}
Assuming that your ListItem object has a field named isSender to check whether he is the sender or not.
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.singlecomment, null);
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.usernme);
holder.message = (TextView) convertView.findViewById(R.id.postCommentBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ListItem newsItem = listData.get(position);
if(newsItem.getIsSender()) {
holder.usernameRight.setText(newsItem.getUsername());
holder.messageRight.setText(newsItem.getmComment());
holder.usernameLeft.setVisibility(View.GONE); // or something like that to hide
holder.messageLeft.setText(View.GONE);
} else {
holder.usernameLeft.setText(newsItem.getUsername());
holder.messageLeft.setText(newsItem.getmComment());
holder.usernameRight.setVisibility(View.GONE);
holder.messageRight.setText(View.GONE);
}
return convertView;
}

Dynamically change custom list item background

I am creating a custom list view with favorite functionality, but I don't know how to change favorite image background on click. When I simply change the background of favorite icon than it automatically change background of another favorite image background at the time of scrolling. Please check below code :
public class CustomArrayAdapter extends BaseAdapter {
private Activity activity;
private LayoutInflater inflater = null;
ArrayList<Customlist> list;
DecimalFormat formatter = new DecimalFormat("#,##,###");
public CustomArrayAdapter(Activity a, ArrayList<Customlist> list) {
activity = a;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.list = list;
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView,
final ViewGroup parent) {
TextView txt_unit, txt_state, txt_price, term_left, customr;
TextView install_date;
final ImageView fav;
View view = convertView;
if (convertView == null)
view = inflater.inflate(R.layout.list_item, null);
customr = (TextView) view.findViewById(R.id.customr);
txt_state = (TextView) view.findViewById(R.id.txt_state);
install_date = (TextView) view.findViewById(R.id.install_date);
term_left = (TextView) view.findViewById(R.id.term_left);
txt_price = (TextView) view.findViewById(R.id.txt_price);
fav = (ImageView) view.findViewById(R.id.fav);
txt_unit = (TextView) view.findViewById(R.id.txt_unit);
fav.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// fav = (ImageView)v.findViewById(R)
fav.setBackgroundResource(R.drawable.favourite_select);
Toast.makeText(activity, "click", 1).show();
}
});
// set values
customr.setText(list.get(position).getCUSTOMER());
txt_state.setText(list.get(position).getSTATE_NAME());
install_date.setText(list.get(position).getINSTALL_DATE());
term_left.setText(list.get(position).getTREM_LEFT());
String price = formatter.format(Integer.parseInt(list.get(position)
.getRUPEES()));
return view;
}
}
First, you need to implement the adapter on ViewHolder pattern:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHoldler holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(ctx).inflate(
R.layout.frag_home_gridview_item, null, false);
holder = new ViewHoldler();
holder.iv = (ImageView) convertView
.findViewById(R.id.gridview_item_label);
holder.tv = (TextView) convertView
.findViewById(R.id.gridview_item_name);
convertView.setTag(holder);
} else {
holder = (ViewHoldler) convertView.getTag();
}
holder.tv.setText(getItem(position));
holder.iv.setImageResource(this.ids[position]);
return convertView;
}
private class ViewHoldler {
ImageView iv;
TextView tv;
}
Second, use partial refreshment mechanism to change the target View's background:
private void refreshPartially(int position){
int firstVisiblePosition = listview.getFirstVisiblePosition();
int lastVisiblePosition = listview.getLastVisiblePosition();
if(position>=firstVisiblePosition && position<=lastVisiblePosition){
View view = listview.getChildAt(position - firstVisiblePosition);
if(view.getTag() instanceof ViewHolder){
ViewHolder vh = (ViewHolder)view.getTag();
//holder.play.setBackgroundResource(resId);//Do something here.
...
}
}
}
Third, add AdapterView.OnItemClickListener to your ListView:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
refreshPartially(position);
}
});
You need to implement the adapter on ViewHolder pattern:
http://www.vogella.com/tutorials/AndroidListView/article.html

Delete a row from listview xamarin

I have a activity in which there are some buttons and a listview.each rows of the listview has a delete button which i'm intend to delete the row whenever the user click the delete button.
i'm using a custom adapter so here is my getview method:
public override View GetView(int position, View convertView, ViewGroup parent)
{
convertView = menuActivity.LayoutInflater.Inflate(Resource.Layout.OrderItemLayout, null);
ImageButton btn = convertView.FindViewById<ImageButton>(Resource.Id.btn_del);
btn.Tag = position;
btn.Click += btn_Click;
return convertView;
}
void btn_Click(object sender, EventArgs e)
{
_lstOrder.RemoveAt((int)((sender as ImageButton)).Tag);
NotifyDataSetChanged();
}
but the problem is that when i click the delete button the listview doesn't refresh so the row that was deleted is still there but it will gone if i go back and then come to the activity again.
how can I solve this problem so after i delete a row the listview refresh?
thank you
Creating a common arraylist
ArrayList<GeterSetterClass> comn_arylist = new ArrayList<GeterSetterClass>();
Customized addapter setting
custdet_adapter adapter = new custdet_adapter(this,comn_arylist);
listview.setAdapter(adapter);
listview.invalidateViews();
Customized Adapter class
public static class custdet_adapter extends BaseAdapter {
private ArrayList<GeterSetterClass> cust_arrayList;
private LayoutInflater l_Inflater;
public custdet_adapter(Context context,
ArrayList<GeterSetterClass> list_details) {
cust_arrayList = list_details;
l_Inflater = LayoutInflater.from(context);
}
public int getCount() {
return cust_arrayList.size();
}
public Object getItem(int position) {
return cust_arrayList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView,
ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = l_Inflater.inflate(R.layout.layoutname_struct,null);
holder = new ViewHolder();
holder.txt_custname = (TextView) convertView
.findViewById(R.id.textView1);
holder.txt_mobno = (TextView) convertView
.findViewById(R.id.textView2);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txt_custname.setText(cust_arrayList.get(position).getName());
holder.txt_mobno.setText(cust_arrayList.get(position).getunitcd());
holder.txt_custname.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
comn_arylist.remove(position);
listview.invalidateViews();
}
});
return convertView;
}
class ViewHolder {
TextView txt_custname;
TextView txt_mobno;
}
}

List items position repeating in getview

I am creating a custom list view using baseadapter.i have 10 list item in my list.my problem is that afetr 6 items ,the first 4 are repeating.i just printed position values in getview.it gives 0,1,2,3,4,5,6,7,8,9,0,1,2,3.My code is below.
thanx in advance
public class ProductListAdapter extends BaseAdapter implements OnClickListener{
/*
* developer :sanu
* date :10-4-2013
* time :3.34 pm
*/
public View row;
private String[] productName;
private String[] producttype;
private String[] priceRangeFrom;
private String[] priceRangeTo;
private String[] productImage;
private Activity activity;
private static LayoutInflater inflater=null;
static String posClicked;
ViewHolder holder;
Integer height1;
Integer width1;
Typeface tf;
Integer FirmaCount;
public ImageLoader imageLoader;
public ProductListAdapter(Activity a,String[] name,String[] type,String[] price_from,String[] price_to,String[] image,Typeface tf) {
activity = a;
productName = name;
producttype = type;
priceRangeFrom = price_from;
priceRangeTo = price_to;
productImage = image;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return productName.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public int getViewTypeCount (int position)
{
return position;
}
public static class ViewHolder{
public TextView nameProduct;
public TextView typeProduct;
public TextView priceRangeProduct;
public ImageView productImage;
public ImageView plusImage;
public RelativeLayout mainLayout;
public int position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = inflater.inflate(R.layout.product_list_details,parent, false);
holder=new ViewHolder();
holder.nameProduct =(TextView)convertView.findViewById(R.id.name);
holder.typeProduct =(TextView)convertView.findViewById(R.id.product);
holder.priceRangeProduct =(TextView)convertView.findViewById(R.id.pricerange);
holder.productImage =(ImageView)convertView.findViewById(R.id.image);
holder.plusImage =(ImageView)convertView.findViewById(R.id.dot);
holder.mainLayout = (RelativeLayout)convertView.findViewById(R.id.mainlayout);
holder.nameProduct.setText(productName[position]);
if(producttype[position].length()>18)
{
holder.typeProduct.setText(producttype[position].substring(0,18)+"...");
}
else
{
holder.typeProduct.setText(producttype[position]);
}
holder.priceRangeProduct.setText(priceRangeFrom[position].substring(0,priceRangeFrom[position].length()-2)+" To "+priceRangeTo[position].substring(0, priceRangeTo[position].length()-2));
imageLoader.DisplayImage(productImage[position], holder.productImage);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
holder.plusImage.setTag(Integer.toString(position));
holder.plusImage.setOnClickListener(this);
holder.mainLayout.setTag(Integer.toString(position));
holder.mainLayout.setOnClickListener(this);
return convertView;
}
This sounds like a case of View re-cyclcing. Android will pass a pre-populated view to the getView method. It does so to minimize object creation. When an existing row-view is scrolled off screen, Android might try to recycle that view to display a row that is now on-screen. You need to account for the fact that this view may have been used to display data for another row (which is now off screen).
You have the following line
holder.typeProduct.setText
within the following conditional:
if(convertView == null){
Move that line outside of the conditional, and all should be well.
It's like EJK said. You are not recycling your view correctly. Change your code to this and notice where I put the setText calls
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = inflater.inflate(R.layout.product_list_details,parent, false);
holder=new ViewHolder();
holder.nameProduct =(TextView)convertView.findViewById(R.id.name);
holder.typeProduct =(TextView)convertView.findViewById(R.id.product);
holder.priceRangeProduct =(TextView)convertView.findViewById(R.id.pricerange);
holder.productImage =(ImageView)convertView.findViewById(R.id.image);
holder.plusImage =(ImageView)convertView.findViewById(R.id.dot);
holder.mainLayout = (RelativeLayout)convertView.findViewById(R.id.mainlayout);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
holder.plusImage.setTag(Integer.toString(position));
holder.plusImage.setOnClickListener(this);
holder.mainLayout.setTag(Integer.toString(position));
holder.mainLayout.setOnClickListener(this);
//setText functions are here
holder.nameProduct.setText(productName[position]);
if(producttype[position].length()>18)
{
holder.typeProduct.setText(producttype[position].substring(0,18)+"...");
}
else
{
holder.typeProduct.setText(producttype[position]);
}
holder.priceRangeProduct.setText(priceRangeFrom[position].substring(0,priceRangeFrom[position].length()-2)+" To "+priceRangeTo[position].substring(0, priceRangeTo[position].length()-2));
imageLoader.DisplayImage(productImage[position], holder.productImage);
return convertView;
}
Change your getView to
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = inflater.inflate(R.layout.product_list_details,parent, false);
holder=new ViewHolder();
holder.nameProduct =(TextView)convertView.findViewById(R.id.name);
holder.typeProduct =(TextView)convertView.findViewById(R.id.product);
holder.priceRangeProduct =(TextView)convertView.findViewById(R.id.pricerange);
holder.productImage =(ImageView)convertView.findViewById(R.id.image);
holder.plusImage =(ImageView)convertView.findViewById(R.id.dot);
holder.mainLayout = (RelativeLayout)convertView.findViewById(R.id.mainlayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.nameProduct.setText(productName[position]);
if(producttype[position].length()>18)
{
holder.typeProduct.setText(producttype[position].substring(0,18)+"...");
}
else
{
holder.typeProduct.setText(producttype[position]);
}
holder.priceRangeProduct.setText(priceRangeFrom[position].substring(0,priceRangeFrom[position].length()-2)+" To "+priceRangeTo[position].substring(0, priceRangeTo[position].length()-2));
imageLoader.DisplayImage(productImage[position], holder.productImage);
holder.plusImage.setTag(Integer.toString(position));
holder.plusImage.setOnClickListener(this);
holder.mainLayout.setTag(Integer.toString(position));
holder.mainLayout.setOnClickListener(this);
return convertView;
}
Also check this
How ListView's recycling mechanism works
Change getView()
Declare ViewHolder before if (convertView == null)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.product_list_details,
parent, false);
holder = new ViewHolder();
holder.nameProduct = (TextView) convertView.findViewById(R.id.name);
holder.typeProduct = (TextView) convertView
.findViewById(R.id.product);
holder.priceRangeProduct = (TextView) convertView
.findViewById(R.id.pricerange);
holder.productImage = (ImageView) convertView
.findViewById(R.id.image);
holder.plusImage = (ImageView) convertView.findViewById(R.id.dot);
holder.mainLayout = (RelativeLayout) convertView
.findViewById(R.id.mainlayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.nameProduct.setText(productName[position]);
if (producttype[position].length() > 18) {
holder.typeProduct.setText(producttype[position].substring(0, 18)
+ "...");
} else {
holder.typeProduct.setText(producttype[position]);
}
holder.priceRangeProduct.setText(priceRangeFrom[position].substring(0,
priceRangeFrom[position].length() - 2)
+ " To "
+ priceRangeTo[position].substring(0,
priceRangeTo[position].length() - 2));
imageLoader.DisplayImage(productImage[position], holder.productImage);
holder.plusImage.setTag(Integer.toString(position));
holder.plusImage.setOnClickListener(this);
holder.mainLayout.setTag(Integer.toString(position));
holder.mainLayout.setOnClickListener(this);
return convertView;
}

Categories

Resources