how to save state of view in listview - java

In my app, I display a check list using a ListView. Every row in my check list is represented by a model, which is an object of the ChecklistenPunkt class. There are three different types of rows:
a headline
an additional text
a question
The third type has two Buttons in it which are linked by two OnClickListeners: The first Button is for a positive answer, the second one for a negative answer. When the view is build, both of them are gray, indicating that this question is not yet answered. If the left Buttonis clicked it turns green and the second one is getting a dark gray background. If the right Button is clicked it turns red and the first one is getting a dark gray background. When a Button is clicked the answering state is saved as an ChecklistenPunktStatus. This is an Enum which has three entries (okay, not okay, not answered).
Here is a little image of the Buttons in three rows, showing the different states:
Here is my adapter code:
public class ChecklisteAdapter extends ArrayAdapter<Object> {
private List<ChecklistenPunkt> list;
private SparseArray<ChecklistenPunktStatus> sparseArray;
private Context context;
public ChecklisteAdapter(Context context, List<ChecklistenPunkt> objects) {
super(context, 0);
list = objects;
sparseArray = new SparseArray<ChecklistenPunktStatus>();
for (int i = 0; i < list.size(); i++) {
sparseArray.put(i, ChecklistenPunktStatus.NICHT_SELEKTIERT);
}
this.context = context;
}
#Override
public int getCount() {
return list.size();
}
#Override
public ChecklistenPunkt getItem(int position) {
return list.get(position);
}
#Override
public int getItemViewType(int position) {
ChecklistenPunkt p = (ChecklistenPunkt) list.get(position);
return p.getTyp();
}
#Override
public int getViewTypeCount() {
return 3;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v = null;
int type = getItemViewType(position);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewHolder viewHolder = new ViewHolder();
switch (type) {
case Util.CHECKLISTE_FRAGE:
v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_frage, null);
viewHolder.nummer = (TextView) v.findViewById(R.id.check_nummer);
viewHolder.komponente = (TextView) v.findViewById(R.id.check_komponente);
viewHolder.funktion = (TextView) v.findViewById(R.id.check_funktion);
viewHolder.kriterium = (TextView) v.findViewById(R.id.check_kriterium);
viewHolder.erlaeuterung = (TextView) v.findViewById(R.id.check_erlaeuterung);
viewHolder.io = (Button) v.findViewById(R.id.button_i_o);
viewHolder.nio = (Button) v.findViewById(R.id.button_n_i_o);
viewHolder.io.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.io.setBackgroundColor(Color.GREEN);
viewHolder.io.setEnabled(false);
viewHolder.nio.setBackgroundColor(Color.GRAY);
viewHolder.nio.setEnabled(true);
sparseArray.put(position, ChecklistenPunktStatus.IN_ORDNUNG);
}
});
viewHolder.nio.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.nio.setBackgroundColor(Color.RED);
viewHolder.nio.setEnabled(false);
viewHolder.io.setBackgroundColor(Color.GRAY);
viewHolder.io.setEnabled(true);
sparseArray.put(position, ChecklistenPunktStatus.NICHT_IN_ORDNUNG);
}
});
ChecklistenPunktStatus status = sparseArray.get(position);
if (status == ChecklistenPunktStatus.IN_ORDNUNG) {
viewHolder.io.setBackgroundColor(Color.GREEN);
viewHolder.io.setEnabled(false);
viewHolder.nio.setBackgroundColor(Color.GRAY);
viewHolder.nio.setEnabled(true);
} else if (status == ChecklistenPunktStatus.NICHT_IN_ORDNUNG) {
viewHolder.nio.setBackgroundColor(Color.RED);
viewHolder.nio.setEnabled(false);
viewHolder.io.setBackgroundColor(Color.GRAY);
viewHolder.io.setEnabled(true);
} else if (status == ChecklistenPunktStatus.NICHT_SELEKTIERT) {
viewHolder.nio.setBackgroundColor(Color.parseColor("#cccccc"));
viewHolder.nio.setEnabled(true);
viewHolder.io.setBackgroundColor(Color.parseColor("#cccccc"));
viewHolder.io.setEnabled(true);
}
v.setTag(viewHolder);
break;
case Util.CHECKLISTE_UEBERSCHRIFT:
v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_head, null);
viewHolder.headline = (TextView) v.findViewById(R.id.check_headline);
viewHolder.headnummer = (TextView) v.findViewById(R.id.check_headnummer);
v.setTag(viewHolder);
break;
case Util.CHECKLISTE_ZUSATZTEXT:
v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_text, null);
viewHolder.text = (TextView) v.findViewById(R.id.check_text);
viewHolder.textnummer = (TextView) v.findViewById(R.id.check_textnummer);
v.setTag(viewHolder);
break;
default:
throw new IllegalArgumentException("ViewType " + type + " unbekannt!");
}
} else {
v = convertView;
}
ChecklistenPunkt clp = getItem(position);
ViewHolder viewHolder = (ViewHolder) v.getTag();
if (clp != null) {
switch (type) {
case Util.CHECKLISTE_FRAGE: {
viewHolder.nummer.setText(clp.getNummer());
viewHolder.komponente.setText(clp.getKomponente());
viewHolder.funktion.setText(clp.getFunktion());
viewHolder.kriterium.setText(clp.getKriterium());
viewHolder.erlaeuterung.setText(clp.getErlaeuterung());
ChecklistenPunktStatus status = sparseArray.get(position);
if (status == ChecklistenPunktStatus.IN_ORDNUNG) {
viewHolder.io.setBackgroundColor(Color.GREEN);
viewHolder.io.setEnabled(false);
viewHolder.nio.setBackgroundColor(Color.GRAY);
viewHolder.nio.setEnabled(true);
} else if (status == ChecklistenPunktStatus.NICHT_IN_ORDNUNG) {
viewHolder.nio.setBackgroundColor(Color.RED);
viewHolder.nio.setEnabled(false);
viewHolder.io.setBackgroundColor(Color.GRAY);
viewHolder.io.setEnabled(true);
} else if (status == ChecklistenPunktStatus.NICHT_SELEKTIERT) {
viewHolder.nio.setBackgroundColor(Color.parseColor("#cccccc"));
viewHolder.nio.setEnabled(true);
viewHolder.io.setBackgroundColor(Color.parseColor("#cccccc"));
viewHolder.io.setEnabled(true);
}
break;
}
case Util.CHECKLISTE_UEBERSCHRIFT: {
viewHolder.headline.setText(clp.getHeadline());
viewHolder.headnummer.setText(clp.getNummer());
break;
}
case Util.CHECKLISTE_ZUSATZTEXT: {
viewHolder.text.setText(Html.fromHtml(clp.getZusatz()));
viewHolder.textnummer.setText(clp.getNummer());
break;
}
default:
throw new IllegalArgumentException("ViewType " + type + " unbekannt!");
}
}
return v;
}
public SparseArray<ChecklistenPunktStatus> getSparseArray() {
return sparseArray;
}
static class ViewHolder {
protected TextView nummer;
protected TextView komponente;
protected TextView kriterium;
protected TextView funktion;
protected TextView erlaeuterung;
protected TextView text;
protected TextView textnummer;
protected TextView headline;
protected TextView headnummer;
protected Button io;
protected Button nio;
}
}
EDIT:
When the convertView is null, I create a new View by inflating my layout. Then I create a new ViewHolder, find the different TextViews and Buttons according to the Views viewType and put them into the ViewHolder. After that, I set this ViewHolder as the tag of the View. I distinguish according to the viewType again and set the text and Listeners of the Views inside the ViewHolder. Then I return the view.
When the convertView is not null I reuse the View. I get the ViewHolder with the getTag() method, set the text and Button state according to the model class and return the view at the end of the method.
My problem is that the answering state is correctly saved in the SparseArray, but it is not displayed correctly. When I answer a question in the first rows of my list and then scroll down, answered questions appear at the end of the list. By scrolling up and down I can mess up the answering states completely. But while this is happening, the states in the sparseArray are always correct.
Am I missing something here?

I suppose there is something wrong with the code. When you use the same cell and when the view is not null you should reuse the same holder and not the convertView. Something like that:
ViewHolder viewHolder = new ViewHolder();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
.
.
.
}
else {
viewHolder = convertView.getTag();
}

Related

ListView adapter returns wrong items

I have a survey with 2 types of answers:
1)Open (checkbox or radio button) + (user may input text)
2)Ordinary (checkbox or radio button)
When I have a large list like 20+ elements ListView shows wrong type of answer.
I guess that the problem is with getItem(), because the type of the answer depends on it's data.
I have tried many ways to resolve the problem, could not even mention all stackoverflow links.
Maybe, somebody may help me.
public class AnswerAdapter extends ArrayAdapter<Answer> {
public interface ActionsListener {
void onCheckClicked(View v, Answer answer, int position);
void onRadioClicked(View v, Answer answer, int position);
void onOpenClicked(View v, Answer answer, int position);
}
private Display mDisplay;
private LayoutInflater mInflater;
private Context mContext;
private ActionsListener mActionsListener;
private String language;
private ArrayList<Answer> mList;
public AnswerAdapter(Context context, ArrayList<Answer> list, String language, ActionsListener actionsListener) {
super(context, R.layout.item_answer, list);
mList = list;
mInflater = LayoutInflater.from(context);
mContext = context;
mActionsListener = actionsListener;
this.language = language;
mDisplay = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
}
#Nullable
#Override
public Answer getItem(int position) {
return super.getItem(this.getPosition(mList.get(position)));
}
#Override
public View getView(final int position, final View convertView,
ViewGroup parent) {
ViewHolder holder;
View row = convertView;
if (convertView == null) {
row = mInflater.inflate(R.layout.item_answer, parent, false);
holder = new ViewHolder();
holder.answerTitle = (TextView) row.findViewById(R.id.answer_title);
holder.answerRadio = (AppCompatRadioButton) row.findViewById(R.id.answer_radio);
holder.answerCheck = (AppCompatCheckBox) row.findViewById(R.id.answer_check);
holder.answerPicture = (ImageView) row.findViewById(R.id.answer_picture);
holder.answerOpen = (EditText) row.findViewById(R.id.answer_open);
holder.answerRank = (Button) row.findViewById(R.id.answer_rank);
row.setTag(holder);
} else
holder = (ViewHolder) row.getTag();
final Answer answer = getItem(position);
final ViewHolder viewHolderFinal = holder;
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.answer_check:
mActionsListener.onCheckClicked(v, answer, position);
notifyDataSetChanged();
break;
case R.id.answer_radio:
mActionsListener.onRadioClicked(v, answer, position);
notifyDataSetChanged();
break;
case R.id.answer_title:
case R.id.answer_picture:
if (viewHolderFinal.answerCheck.isEnabled() && viewHolderFinal.answerRadio.isEnabled())
if (answer.getPolyAnswer()) {
viewHolderFinal.answerCheck.setChecked(!viewHolderFinal.answerCheck.isChecked());
onClick(viewHolderFinal.answerCheck);
} else {
viewHolderFinal.answerRadio.setChecked(true);
onClick(viewHolderFinal.answerRadio);
}
break;
case R.id.answer_open:
mActionsListener.onOpenClicked(v, answer, position);
if (viewHolderFinal.answerCheck.isEnabled() && viewHolderFinal.answerRadio.isEnabled()) {
if (answer.getPolyAnswer()) {
onClick(viewHolderFinal.answerCheck);
} else {
onClick(viewHolderFinal.answerRadio);
}
}
break;
}
}
};
holder.answerTitle.setOnClickListener(onClickListener);
holder.answerPicture.setOnClickListener(onClickListener);
holder.answerOpen.setOnClickListener(onClickListener);
holder.answerOpen.setHint(language); //language[6]
holder.answerTitle.setText(answer.getTitle());
holder.answerTitle.setTextColor(ContextCompat.getColor(mContext, R.color.colorUIWhite));
if (answer.getPolyAnswer()) {
holder.answerCheck.setVisibility(View.VISIBLE);
holder.answerCheck.setChecked(answer.getCheck());
holder.answerCheck.setEnabled(answer.getEnabled());
holder.answerCheck.setOnClickListener(onClickListener);
} else {
holder.answerRadio.setVisibility(View.VISIBLE);
holder.answerRadio.setChecked(answer.getCheck());
holder.answerRadio.setOnClickListener(onClickListener);
}
if (answer.getIsOpenAnswer()) {
holder.answerOpen.setVisibility(View.VISIBLE);
holder.answerOpen.setText(answer.getOpenAnswer());
holder.answerOpen.setTextColor(ContextCompat.getColor(mContext, R.color.colorUIWhite));
holder.answerOpen.setHintTextColor(ContextCompat.getColor(mContext, R.color.colorUIWhite));
holder.answerOpen.setError(answer.getOpenAnswerError());
}
return row;
}
private static class ViewHolder {
TextView answerTitle;
AppCompatRadioButton answerRadio;
AppCompatCheckBox answerCheck;
ImageView answerPicture;
EditText answerOpen;
Button answerRank;
}
}
Looking at your getView() method, I'd assume you also end up with situations where both your radio and check show as visible at the same time as well.
Because getView() can recycle the view (when convertView is not null), any showing elements retain their visibility.
So you should add an else to your answer.getIsOpenAnswer() where when it is not you set answerOpen's visibility to INVISIBLE or GONE (depending on your design).
In your if statement for answer.getPolyAnswer() you need to probably set answerRadio to INVISIBLE or GONE and answerCheck to INVISIBLE or GONE in your else as well.

Get parent layout from custom Adapter

Could anybody explain me, how to realize?
I have an activity with listview and footer with some elements(textview).
Listview built with custom adapter. Each listview item has few elements. And my question: how can i change textview in footer, from custom adapter, when i clicking on some listview's element?
Thx a lot!
/**** My adapter ****/
public class MyListAdapter extends ArrayAdapter<Product> implements UndoAdapter {
private final Context mContext;
private HashMap<Product, Integer> mIdMap = new HashMap<Product, Integer>();
ArrayList<Product> products = new ArrayList<Product>();
final int INVALID_ID = -1;
LayoutInflater lInflater;
String imagePath;
public MyListAdapter(Context context, int textViewResourceId, List<Product> prod) {
//super(context, textViewResourceId, prod);
super(prod);
lInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContext = context;
for (int i = 0; i < prod.size(); i++) {
//add(prod.get(i));
mIdMap.put(prod.get(i),i);
}
}
#Override
public long getItemId(final int position) {
//return getItem(position).hashCode();
Product item = (Product) getItem(position);
return mIdMap.get(item);
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder holder = null;;
Product p = getItem(position);
if (convertView == null) {
convertView = lInflater.inflate(R.layout.item, null);
//convertView.setBackgroundResource(R.drawable.rounded_corners);
int currentTheme = Utils.getCurrentTheme(convertView.getContext());
switch (currentTheme) {
case 0:
convertView.setBackgroundResource(R.drawable.rounded_corners);
break;
case 1:
convertView.setBackgroundResource(R.drawable.border);
break;
default:
convertView.setBackgroundResource(R.drawable.rounded_corners);
break;
}
holder = new ViewHolder();
holder.tvDescr = (TextView) convertView.findViewById(R.id.tvDescr);
holder.list_image = (ImageView) convertView.findViewById(R.id.list_image);
holder.products_amount = (TextView) convertView.findViewById(R.id.amountDigits);
holder.products_price = (TextView) convertView.findViewById(R.id.priceDigits);
holder.ivImage = (ImageView) convertView.findViewById(R.id.ivImage);
holder.unit = (TextView) convertView.findViewById(R.id.unit);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(p.getProductImageBitmap() != null && p.getProductImageBitmap() != "") {
Log.d("PATH -- ", p.getProductImageBitmap());
ImageLoader imageLoader = ImageLoader.getInstance();
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheInMemory(true)
.resetViewBeforeLoading(true)
.showImageForEmptyUri(R.drawable.ic_launcher)
.showImageOnFail(R.drawable.ic_launcher)
/*.showImageOnLoading(R.id.progress_circular)*/
.build();
imageLoader.displayImage(p.getProductImageBitmap(), holder.list_image, options);
} else {
holder.list_image.setImageResource(R.drawable.ic_launcher);
}
holder.tvDescr.setText(p.getProductName());
holder.ivImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String deletedItem = getItem(position).getProductName();
MyListAdapter.this.remove(getItem(position));
if (MyListAdapter.this.getCount() > 0) {
Toast.makeText(mContext, deletedItem + " " + mContext.getString(R.string.deleted_item), Toast.LENGTH_SHORT).show();
MyListAdapter.this.notifyDataSetChanged();
} else {
Toast.makeText(mContext,mContext.getString(R.string.sklerolist_empty), Toast.LENGTH_SHORT).show();
}
}
});
//Функционал для большой картинки продукта
//открывается новое активити с большой картинкой
holder.list_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
imagePath = getItem(position).getProductImageBitmap();
if(imagePath != null && imagePath != "") {
Pattern normalPrice = Pattern.compile("^file");
Matcher m2 = normalPrice.matcher(imagePath);
if (m2.find()) {
Intent myIntent = new Intent(view.getContext(), ViewImage.class).putExtra("imagePath", imagePath);
view.getContext().startActivity(myIntent);
}
}
}
});
holder.products_price.setText(fmt(p.getProductPrice()));
holder.products_amount.setText(fmt(p.getProductAmount()));
holder.unit.setText(p.getProductUnit());
return convertView;
}
public static String fmt(double d){
if(d == (long) d)
return String.format("%d",(long)d);
else
return String.format("%s",d);
}
static class ViewHolder {
ImageView list_image;
TextView tvDescr;
TextView products_amount;
TextView products_price;
TextView unit;
ImageView ivImage;
ProgressBar circleProgress;
}
#NonNull
#Override
public View getUndoView(final int position, final View convertView, #NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
//view = LayoutInflater.from(mContext).inflate(R.layout.undo_row, parent, false);
view = lInflater.inflate(R.layout.undo_row, parent, false);
}
return view;
}
#NonNull
#Override
public View getUndoClickView(#NonNull final View view) {
return view.findViewById(R.id.undo_row_undobutton);
}
public View getHeaderView(final int position, final View convertView, final ViewGroup parent) {
TextView view = (TextView) convertView;
//View view = convertView;
if (view == null) {
//view = (TextView) LayoutInflater.from(mContext).inflate(R.layout.list_header, parent, false);
//view = lInflater.inflate(R.layout.list_header, parent, false);
}
//view.setText(mContext.getString(R.string.header, getHeaderId(position)));
return view;
}
public long getHeaderId(final int position) {
return position / 10;
}
}
Your ListView has a listener for the click events on list elements.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Do something when a list item is clicked
}
But if you want to pas something else back from the adapter to the Activity or the Fragment that contains that ListView and Adapter, you should create a simple interface and set it as listener to your adapter. After that, set click events on your rows from within the adapter, and notify the Activity or Fragment using your own interface.
For example you have the interface defined like this
public interface OnItemClickedCustomAdapter {
public void onClick(ItemPosition position);
}
and in your Adapter class you will have a private member
private OnItemClickedCustomAdapter mListener;
and a method used to set the listener
public void setOnItemClickedCustomAdapter(OnItemClickedCustomAdapter listener){
this.mListener = listener;
}
From your Activity or Fragment where your ListView is defined, and your adapter is set, you will be able to call setOnItemClickedCustomAdapter with this as parameter, and there you go. Your activity will now listen for your events. To trigger an event, just call mListener.onClick() from your custom adapter. You can pass back data you need back to the Activity or Fragment, and from there you have access to your Header or Footer directly, and you can change the text on them.

while scrolling, ListView Listview item changes the position.Why?

When i am scrolling ListView position of the item changes.My ListView contain 2 Button and 2 TextView. These 2 Button are initially invisible. when user Long click on item i just set the visibility.Its working but when i scroll the ListView ,it changes the position.Why?
I am setting this visibility and invisibility code inside of my adapter class..
here is my code :::
#Override
public View getView(int position, View convertView, ViewGroup parent) {
holder = new ViewHolder();
if (convertView == null) {
convertView = lInflater.inflate(R.layout.message_row, null);
holder.messageDeleteButton = (Button) convertView
.findViewById(R.id.delete_button);
holder.messageTextView = (TextView) convertView
.findViewById(R.id.message);
holder.timeTextView = (TextView) convertView
.findViewById(R.id.time);
holder.copyMessageButton = (ImageButton) convertView
.findViewById(R.id.copy_bt);
holder.messageDeleteButton
.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
System.out.println("Delete clicked");
}
});
convertView.setTag(R.layout.message_row, holder);
} else {
holder = (ViewHolder) convertView.getTag(R.layout.message_row);
}
convertView.setTag(position);
holder.messageDeleteButton.setTag(position);
if (mMessageData.get(position).isVisible())
holder.messageDeleteButton.setVisibility(View.VISIBLE);
else
holder.messageDeleteButton.setVisibility(View.GONE);
holder.messageTextView.setText(mMessageData.get(position)
.getMessage_text());
holder.messageTextView.setTypeface(Typeface.createFromAsset(
mContext.getAssets(), "Existence-Light.ttf"));
holder.timeTextView.setText(mMessageData.get(position)
.getMessage_date());
holder.timeTextView.setTypeface(Typeface.createFromAsset(
mContext.getAssets(), "Existence-Light.ttf"));
convertView.setOnTouchListener(mOnTouchListener);
convertView.setOnClickListener(mOnClickListener);
// convertView.setOnLongClickListener(mLongClick);
return convertView;
}
This is my OnTouchListiner code it will working fine.But when i scroll the ListView the buttons positions will changed..
class MyTouchListener implements OnTouchListener {
#SuppressWarnings("deprecation")
private final GestureDetector gestureDetector = new GestureDetector(
new GestureListener());
#Override
public boolean onTouch(View v, MotionEvent event) {
int touch = 0;
ViewHolder holder = (ViewHolder) v.getTag(R.layout.message_row);
animation = new Animater();
int action = event.getAction();
int position = (Integer) v.getTag();
pos = position;
view = v;
switch (action) {
case MotionEvent.ACTION_DOWN:
action_down_x = (int) event.getX();
Log.d("action", "ACTION_DOWN - ");
touch = 0;
break;
case MotionEvent.ACTION_MOVE:
Log.d("action", "ACTION_MOVE - ");
action_up_x = (int) event.getX();
difference = action_down_x - action_up_x;
calcuateDifference(holder, position);
touch = 1;
break;
case MotionEvent.ACTION_UP:
Log.d("action", "ACTION_UP - ");
// calcuateDifference(holder, position);
action_down_x = 0;
action_up_x = 0;
difference = 0;
// touch = 2;
break;
}
return gestureDetector.onTouchEvent(event);
}
public GestureDetector getGestureDetector() {
return gestureDetector;
}
}
In this gestuer class when i tap on ListView just display one more Button.This also be changed the position
public class GestureListener extends SimpleOnGestureListener{
#SuppressLint("NewApi")
#Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
super.onLongPress(e);
final ViewHolder hold = (ViewHolder) view.getTag(R.layout.message_row);
hold.copyMessageButton.setVisibility(View.VISIBLE);
hold.copyMessageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
System.out.println("hello you click me..");
});
}
}
What is the wrong on my code..Any one please help me...
Android ListView use Adapters to recycle views that's why ListView position changes while scrolling to conserve memory.See the Google I/O presentation given by Romain Guy to understand how adapters work. http://www.youtube.com/watch?v=N6YdwzAvwOA
Also check the below links,
http://strangevikas.wordpress.com/tag/how-adapter-works-in-android-android-and-adapters/
http://www.edureka.in/blog/what-are-adapters-in-android/
You just need to do some modification in your code like:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = new ViewHolder();
if (convertView == null) {
convertView = lInflater.inflate(R.layout.message_row, null);
holder.messageDeleteButton = (Button) convertView
.findViewById(R.id.delete_button);
holder.messageTextView = (TextView) convertView
.findViewById(R.id.message);
holder.timeTextView = (TextView) convertView
.findViewById(R.id.time);
holder.copyMessageButton = (ImageButton) convertView
.findViewById(R.id.copy_bt);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.messageDeleteButton.setTag(mMessageData.get(position));
holder.messageDeleteButton
.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
// message data can be retrieved here like
MessageData mData = (MessageData) v.getTag();
System.out.println("Delete clicked");
}
});
if (mMessageData.get(position).isVisible())
holder.messageDeleteButton.setVisibility(View.VISIBLE);
else
holder.messageDeleteButton.setVisibility(View.GONE);
holder.messageTextView.setText(mMessageData.get(position)
.getMessage_text());
holder.messageTextView.setTypeface(Typeface.createFromAsset(
mContext.getAssets(), "Existence-Light.ttf"));
holder.timeTextView.setText(mMessageData.get(position)
.getMessage_date());
holder.timeTextView.setTypeface(Typeface.createFromAsset(
mContext.getAssets(), "Existence-Light.ttf"));
return convertView;
}

Android OnClickListener to update text within same ListView row

I am making a list view that contains (amongst a few other things) 2 ImageViews and a TextView. The two ImageViews are plus and minus icons, when they are pressed, they need to update the number inside the TextView. They also need to trigger code that will update the sum of the TextViews, below the ListView.
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.basket_item, null);
holder.plus = (ImageView) convertView.findViewById(R.id.count_add);
holder.minus = (ImageView) convertView.findViewById(R.id.count_minus);
holder.counter = (TextView) convertView.findViewById(R.id.text_counter);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.id = position;
holder.counter.setId(position);
holder.counter.setText(count[position]);
holder.plus.setId(position);
holder.plus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int id = v.getId();
if (count[id] < 999) {
count[id]++;
totalcount++;
}
}
});
holder.minus.setId(position);
holder.minus.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int id = v.getId();
if (count[id] > 1) {
count[id]--;
totalCount--;
}
}
});
return convertView;
}
}
class ViewHolder {
ImageView plus;
ImageView minus;
TextView counter;
int id;
}
I believe, to update the counter in the TextView, I need to somehow get my 'holder' inside the OnClickListner, however, as it is not declared as final, I can't.
Is there an easier way to do this, or am I missing a trick here?
Try implement the notifyDataSetChanged() that calls the getView once again. And after that invalidate the textView. But I am not fully sure about the need to call invalidate() here.
public void onClick(View v) {
int id = v.getId();
if (count[id] > 1) {
count[id]--;
totalCount--;
notifyDataSetChanged();
holder.counter.invalidate();
}
}
});
I am not sure about it.I hope it do. Try to paste this line under the Onclick method itself.
"holder.counter.setText('YOUR TEXT totalcount');"

ListView Viewholder checkbox state

I've some problems with my ListView custom adapter (and its newly implemented viewHolder). I have a ListView with a checkbox for each item (nothing new here). The problem is, if there is more than 9 items in my list, when I check the first checkbox, the tenth will be automatically checked (same for the second with the eleventh) just like if there were one listener for both item (and I beleive it's the case in some way).
I read about the position issue with listView, view recycling and the ViewHolder way to solve it here: How can I make my ArrayAdapter follow the ViewHolder pattern?
But I probably made something wrong because it's not working...
public class PresenceListAdapter extends SimpleAdapter {
private LayoutInflater inflater;
private List<Integer> ids;
private List<String> statuts;
public PresenceListAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to, List<Integer> ids, List<String> statuts)
{
super (context, data, resource, from, to);
inflater = LayoutInflater.from (context);
this.ids = ids;
this.statuts= statuts;
}
#Override
public Object getItem (int position)
{
return super.getItem (position);
}
#Override
public View getView (int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = inflater.inflate (R.layout.list_text_checkbox, null);
holder = new ViewHolder();
holder.btn = (Button) convertView.findViewById(R.id.btnRetard);
holder.check = (CheckBox) convertView.findViewById(R.id.checkPresent);
if (statuts.get(position).equals("P")) {
Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_online);
holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null );
holder.btn.setEnabled(true);
holder.check.setChecked(true);
}
else if(statuts.get(position).equals("R"))
{
Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_away);
holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null );
holder.btn.setEnabled(true);
holder.check.setChecked(true);
}
else
{
Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_invisible);
holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null );
holder.check.setChecked(false);
}
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
int id = ids.get(position);
if(id != 0)
{
holder.check.setTag(id);
holder.btn.setTag(id);
}
return super.getView (position, convertView, parent);
}
static class ViewHolder {
Button btn;
CheckBox check;
}
And my listener:
public void changerPresent(View v) {
CheckBox checkPresent = (CheckBox) v;
int idPersonne = (Integer) checkPresent.getTag();
View parent = (View)v.getParent();
Button btn = (Button) parent.findViewById(R.id.btnRetard);
if(checkPresent.isChecked()) {
gestion.updatePresence(idPersonne, idSeance, "P");
btn.setEnabled(true);
setBtnRetardPresent(btn);
}
else
{
gestion.updatePresence(idPersonne, idSeance, "A");
btn.setEnabled(false);
setBtnRetardAbsent(btn);
}
}
I would appreciate any help at this point, I'm working on this for hours now.
Thank you very much.
Here's how I made it work:
First, you need a separate array for your checked state. It has to be the same size as your adapter's getCount().
Then on your getView, your checkbox's setOnCheckedChangedListener MUST PRECEED your checkbox.setChecked statements.
example:
holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isChecked[position] = isChecked;
}
});
holder.checkBox.setChecked(isChecked[position]);
You should set CheckedBox state outside the initialization of ViewHolder, like the following code:
if (convertView == null) {
viewHolder = new ViewHolder();
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkedBox.setChecked();
BTW: use SparseBooleanArray instead of two list to store CheckedBox state.
The problem is because of the fact that listview recycles it views
so in getView() method
if (convertView == null)
{
........
}
else
{
holder = (ViewHolder) convertView.getTag();
}
// Uncheck needed boxes here... You need to implement your logic
if( 'position' is checked earlier)
holder.check.setChecked(true);
else
holder.check.setChecked(false);
You need to write the code to manage the state of view if the convert is not null, because it is a already used view which may be having checked check boxes.

Categories

Resources