Prevent listView item ImageButton from changing state on scroll. And prevent other ImageButtons from changing...
I'm creating a DataSet_Collector kind of app where a user is displayed his conversation threads in ListView
. The user selects spam threads. Those Threads will be sent to an excel sheet. Then the rest of the threads(The non spam) are shown and the user selects those threads that he wants to send.
So far I've displayed the threads, stored in LinkedHashMap<String, String>
, in ListView
using extended SimpleAdapter
i.e ThreadsAdapter
. The Key
of the LinkedHashMap<>
is the sender and the Value
at that Key
is the thread. I have created a layout called listView_layout_item.xml
that contains two TextView
and an ImageButton
. Every item
of the ListView
is inflated with listView_layout_item.xml
in getView()
like the following.
ThreadsAdapter.java
public class ThreadsAdapter extends SimpleAdapter {
private Context context;
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
ThreadsAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String from, int to) {
super(context, data, resource, from, to);
//This 'data' is an ArrayList() of LinkedHashMap<String, String>
//first String for sender of the thread, second String for the thread
//ListView will list sender as item and thread as subitem in
//every getView() instance
this.context = context;
}
private class ViewHolder{
private ImageButton threadCheck;
private boolean isTChecked;
}
@SuppressLint("InflateParams")
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder view;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck =(ImageButton) convertView.findViewById(R.id.threadChecker);
view.isTChecked = false; // in the start of the app.
final ViewHolder finalView = view;
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(finalView.isTChecked)
finalView.threadCheck.setImageResource(R.drawable.circle_unchecked);
else
finalView.threadCheck.setImageResource(R.drawable.circle_checked);
finalView.isTChecked = !finalView.isTChecked;
}
});
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
super.getView(position, convertView, parent);
return convertView;
}
}
super.getView()
is called at the end of getView()
because I want to use the Text
and Subtext
format of SimpleAdapter
for ListView
.
With the given code
when I click on one ImageButton
of a ListView
item to change it's state, other ImageButtons
of other items in ListView
also change their state. Why?! and how do I fix it?
And when I scroll up or down, the state of any ImageButton
changes randomly. Why?! and how do I fix it?
I'm new to ListView
and ListView
adapters. The present answers don't make sense so I posted my own special problem.
android listview
add a comment |
I'm creating a DataSet_Collector kind of app where a user is displayed his conversation threads in ListView
. The user selects spam threads. Those Threads will be sent to an excel sheet. Then the rest of the threads(The non spam) are shown and the user selects those threads that he wants to send.
So far I've displayed the threads, stored in LinkedHashMap<String, String>
, in ListView
using extended SimpleAdapter
i.e ThreadsAdapter
. The Key
of the LinkedHashMap<>
is the sender and the Value
at that Key
is the thread. I have created a layout called listView_layout_item.xml
that contains two TextView
and an ImageButton
. Every item
of the ListView
is inflated with listView_layout_item.xml
in getView()
like the following.
ThreadsAdapter.java
public class ThreadsAdapter extends SimpleAdapter {
private Context context;
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
ThreadsAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String from, int to) {
super(context, data, resource, from, to);
//This 'data' is an ArrayList() of LinkedHashMap<String, String>
//first String for sender of the thread, second String for the thread
//ListView will list sender as item and thread as subitem in
//every getView() instance
this.context = context;
}
private class ViewHolder{
private ImageButton threadCheck;
private boolean isTChecked;
}
@SuppressLint("InflateParams")
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder view;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck =(ImageButton) convertView.findViewById(R.id.threadChecker);
view.isTChecked = false; // in the start of the app.
final ViewHolder finalView = view;
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(finalView.isTChecked)
finalView.threadCheck.setImageResource(R.drawable.circle_unchecked);
else
finalView.threadCheck.setImageResource(R.drawable.circle_checked);
finalView.isTChecked = !finalView.isTChecked;
}
});
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
super.getView(position, convertView, parent);
return convertView;
}
}
super.getView()
is called at the end of getView()
because I want to use the Text
and Subtext
format of SimpleAdapter
for ListView
.
With the given code
when I click on one ImageButton
of a ListView
item to change it's state, other ImageButtons
of other items in ListView
also change their state. Why?! and how do I fix it?
And when I scroll up or down, the state of any ImageButton
changes randomly. Why?! and how do I fix it?
I'm new to ListView
and ListView
adapters. The present answers don't make sense so I posted my own special problem.
android listview
add a comment |
I'm creating a DataSet_Collector kind of app where a user is displayed his conversation threads in ListView
. The user selects spam threads. Those Threads will be sent to an excel sheet. Then the rest of the threads(The non spam) are shown and the user selects those threads that he wants to send.
So far I've displayed the threads, stored in LinkedHashMap<String, String>
, in ListView
using extended SimpleAdapter
i.e ThreadsAdapter
. The Key
of the LinkedHashMap<>
is the sender and the Value
at that Key
is the thread. I have created a layout called listView_layout_item.xml
that contains two TextView
and an ImageButton
. Every item
of the ListView
is inflated with listView_layout_item.xml
in getView()
like the following.
ThreadsAdapter.java
public class ThreadsAdapter extends SimpleAdapter {
private Context context;
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
ThreadsAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String from, int to) {
super(context, data, resource, from, to);
//This 'data' is an ArrayList() of LinkedHashMap<String, String>
//first String for sender of the thread, second String for the thread
//ListView will list sender as item and thread as subitem in
//every getView() instance
this.context = context;
}
private class ViewHolder{
private ImageButton threadCheck;
private boolean isTChecked;
}
@SuppressLint("InflateParams")
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder view;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck =(ImageButton) convertView.findViewById(R.id.threadChecker);
view.isTChecked = false; // in the start of the app.
final ViewHolder finalView = view;
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(finalView.isTChecked)
finalView.threadCheck.setImageResource(R.drawable.circle_unchecked);
else
finalView.threadCheck.setImageResource(R.drawable.circle_checked);
finalView.isTChecked = !finalView.isTChecked;
}
});
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
super.getView(position, convertView, parent);
return convertView;
}
}
super.getView()
is called at the end of getView()
because I want to use the Text
and Subtext
format of SimpleAdapter
for ListView
.
With the given code
when I click on one ImageButton
of a ListView
item to change it's state, other ImageButtons
of other items in ListView
also change their state. Why?! and how do I fix it?
And when I scroll up or down, the state of any ImageButton
changes randomly. Why?! and how do I fix it?
I'm new to ListView
and ListView
adapters. The present answers don't make sense so I posted my own special problem.
android listview
I'm creating a DataSet_Collector kind of app where a user is displayed his conversation threads in ListView
. The user selects spam threads. Those Threads will be sent to an excel sheet. Then the rest of the threads(The non spam) are shown and the user selects those threads that he wants to send.
So far I've displayed the threads, stored in LinkedHashMap<String, String>
, in ListView
using extended SimpleAdapter
i.e ThreadsAdapter
. The Key
of the LinkedHashMap<>
is the sender and the Value
at that Key
is the thread. I have created a layout called listView_layout_item.xml
that contains two TextView
and an ImageButton
. Every item
of the ListView
is inflated with listView_layout_item.xml
in getView()
like the following.
ThreadsAdapter.java
public class ThreadsAdapter extends SimpleAdapter {
private Context context;
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
ThreadsAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String from, int to) {
super(context, data, resource, from, to);
//This 'data' is an ArrayList() of LinkedHashMap<String, String>
//first String for sender of the thread, second String for the thread
//ListView will list sender as item and thread as subitem in
//every getView() instance
this.context = context;
}
private class ViewHolder{
private ImageButton threadCheck;
private boolean isTChecked;
}
@SuppressLint("InflateParams")
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder view;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck =(ImageButton) convertView.findViewById(R.id.threadChecker);
view.isTChecked = false; // in the start of the app.
final ViewHolder finalView = view;
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(finalView.isTChecked)
finalView.threadCheck.setImageResource(R.drawable.circle_unchecked);
else
finalView.threadCheck.setImageResource(R.drawable.circle_checked);
finalView.isTChecked = !finalView.isTChecked;
}
});
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
super.getView(position, convertView, parent);
return convertView;
}
}
super.getView()
is called at the end of getView()
because I want to use the Text
and Subtext
format of SimpleAdapter
for ListView
.
With the given code
when I click on one ImageButton
of a ListView
item to change it's state, other ImageButtons
of other items in ListView
also change their state. Why?! and how do I fix it?
And when I scroll up or down, the state of any ImageButton
changes randomly. Why?! and how do I fix it?
I'm new to ListView
and ListView
adapters. The present answers don't make sense so I posted my own special problem.
android listview
android listview
edited Nov 24 '18 at 10:27
Nisse Engström
4,14892134
4,14892134
asked Nov 24 '18 at 9:11
AhmadAhmad
117
117
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
In ListViews, rows (ViewHolders in your case) are recycled, reused, which means that you see stuff going up and down, but it's the same set of rows over and over again.
Keeping that in mind, it is not correct to store any state in the rows because when stuff gets reused, they will use state they previously had, which on first glance appears random.
What you should do is store the isTChecked
state in your data. To that end, I would advise you to switch the LinkedHashMap
to a ArrayList
and use simple Java objects. You could have a class like this:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
Your adapter's getView
override would become something like this:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
This is in no way optimal, I just tried to make things clear with moving as little code around as possible.
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an innerclass
conversationThread
and extendedBaseAdapter
. How easy was that.
– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53456737%2fprevent-listview-item-imagebutton-from-changing-state-on-scroll-and-prevent-oth%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
In ListViews, rows (ViewHolders in your case) are recycled, reused, which means that you see stuff going up and down, but it's the same set of rows over and over again.
Keeping that in mind, it is not correct to store any state in the rows because when stuff gets reused, they will use state they previously had, which on first glance appears random.
What you should do is store the isTChecked
state in your data. To that end, I would advise you to switch the LinkedHashMap
to a ArrayList
and use simple Java objects. You could have a class like this:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
Your adapter's getView
override would become something like this:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
This is in no way optimal, I just tried to make things clear with moving as little code around as possible.
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an innerclass
conversationThread
and extendedBaseAdapter
. How easy was that.
– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
add a comment |
In ListViews, rows (ViewHolders in your case) are recycled, reused, which means that you see stuff going up and down, but it's the same set of rows over and over again.
Keeping that in mind, it is not correct to store any state in the rows because when stuff gets reused, they will use state they previously had, which on first glance appears random.
What you should do is store the isTChecked
state in your data. To that end, I would advise you to switch the LinkedHashMap
to a ArrayList
and use simple Java objects. You could have a class like this:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
Your adapter's getView
override would become something like this:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
This is in no way optimal, I just tried to make things clear with moving as little code around as possible.
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an innerclass
conversationThread
and extendedBaseAdapter
. How easy was that.
– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
add a comment |
In ListViews, rows (ViewHolders in your case) are recycled, reused, which means that you see stuff going up and down, but it's the same set of rows over and over again.
Keeping that in mind, it is not correct to store any state in the rows because when stuff gets reused, they will use state they previously had, which on first glance appears random.
What you should do is store the isTChecked
state in your data. To that end, I would advise you to switch the LinkedHashMap
to a ArrayList
and use simple Java objects. You could have a class like this:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
Your adapter's getView
override would become something like this:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
This is in no way optimal, I just tried to make things clear with moving as little code around as possible.
In ListViews, rows (ViewHolders in your case) are recycled, reused, which means that you see stuff going up and down, but it's the same set of rows over and over again.
Keeping that in mind, it is not correct to store any state in the rows because when stuff gets reused, they will use state they previously had, which on first glance appears random.
What you should do is store the isTChecked
state in your data. To that end, I would advise you to switch the LinkedHashMap
to a ArrayList
and use simple Java objects. You could have a class like this:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
Your adapter's getView
override would become something like this:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
This is in no way optimal, I just tried to make things clear with moving as little code around as possible.
edited Nov 24 '18 at 10:32
answered Nov 24 '18 at 10:27
iFanieiFanie
1718
1718
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an innerclass
conversationThread
and extendedBaseAdapter
. How easy was that.
– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
add a comment |
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an innerclass
conversationThread
and extendedBaseAdapter
. How easy was that.
– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an inner
class
conversationThread
and extended BaseAdapter
. How easy was that.– Ahmad
Nov 24 '18 at 13:32
Thanks, bro. you saved my day. The problem wasn't big, I was thinking small. So I used, like you told, an inner
class
conversationThread
and extended BaseAdapter
. How easy was that.– Ahmad
Nov 24 '18 at 13:32
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
@Ahmad please mark as correct answer if it helped :)
– iFanie
Nov 25 '18 at 14:59
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53456737%2fprevent-listview-item-imagebutton-from-changing-state-on-scroll-and-prevent-oth%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown