ListView subobject clickable confilct
You need to understand how listview recycle mechanism works
How ListView's recycling mechanism works
Use a Model Class. Assume you already have the below
public class FeedItem {
String title,content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
In getView
holder.accept.setText(listData.get(position).getContent());
holder.accept.setTag(position);
holder.accept.setOnClickListener(mClickListener);
Then
private OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
int pos = (Integer) v.getTag();
FeedItem newsItem = (FeedItem) listData.get(pos);
newsItem.setContent("Accepted");
CustomListadapter.this.notifyDataSetChanged();
}
};
Exaplanation :
You use a model class which has getters and setters.
You setTag
to the button with position. In onClick you get the tag ie position and change the content accordingly. You refresh listview by calling notifyDataSetChanged
on the adapter.
For the benefit of others here's a example
public class MainActivity extends Activity {
ArrayList<Holder> list = new ArrayList<Holder>();
ListView lv;
CustomListAdapter cus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.listView1);
for(int i=0;i<10;i++)
{
Holder h = new Holder();
h.setTitle("Title"+i);
h.setContent("Content"+i);
h.setColor(Color.BLACK);
list.add(h);
}
cus = new CustomListAdapter(this,list);
lv.setAdapter(cus);
}
}
Model class Holder
public class Holder {
String title,content;
int color;
public int getColor() {
return color;
public void setColor(int color) {
this.color = color;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
CustomListAdapter
public class CustomListAdapter extends BaseAdapter{
LayoutInflater inflater;
ArrayList<Holder> list;
public CustomListAdapter(MainActivity mainActivity, ArrayList<Holder> list) {
inflater = LayoutInflater.from(mainActivity);
this.list =list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item,
parent, false);
holder = new ViewHolder();
holder.tv = (TextView) convertView.findViewById(R.id.textView1);
holder.b = (Button) convertView.findViewById(R.id.button1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Holder h = list.get(position);
holder.tv.setText(h.getTitle());
holder.b.setText(h.getContent());
holder.b.setTextColor(h.getColor());
holder.b.setOnClickListener(mClickListener);
holder.b.setTag(position);
return convertView;
}
private OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
int pos = (Integer) v.getTag();
Holder h = (Holder) list.get(pos);
h.setContent("Accepted");
h.setColor(Color.BLUE);
CustomListAdapter.this.notifyDataSetChanged();
}
};
static class ViewHolder
{
TextView tv;
Button b;
}
}
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="40dp"
android:text="Button" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button1"
android:layout_alignParentLeft="true"
android:layout_marginLeft="22dp"
android:text="TextView" />
</RelativeLayout>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</ListView>
</RelativeLayout>
Snap
Button at row 1 and 5 is clicked so it is changed to Accepted and is Blue.
change imageview in android listview adapter file
The underlying data needs to be changed too, in case the views get repopulated for some reason (e.g. notifyDataSetChanged() was called, scrolled out of view etc). Change this to fix the immediate problem (Order needs to be final):
...
cardetails.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (plantoattend.equalsIgnoreCase("N")) {
alertDialog = new AlertDialog.Builder(activity);
alertDialog.setMessage("You're going! Do you want to share the meet?");
alertDialog.setPositiveButton("Share", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, shareurl);
sendIntent.setType("text/plain");
cardetails.setImageResource(R.drawable.unattend);
activity.startActivityForResult(Intent.createChooser(sendIntent, "Share via"), 1000);
}
});
alertDialog.setNegativeButton("Not now", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Order.put(TodayList.TAG_CAR_STATUS, "Y"); // CHANGE THE UNDERLYING DATA HERE
cardetails.setImageResource(R.drawable.unattend);
new AttendMeet().execute(carid);
}
});
alertDialog.show();
} else {
if (cd.isConnectingToInternet()) {
new UnAttendMeet().execute(carid);
Order.put(TodayList.TAG_CAR_STATUS, "N"); // CHANGE THE UNDERLYING DATA HERE
cardetails.setImageResource(R.drawable.attend);
//Today_List_Adapter.this.notifyDataSetChanged();
} else {
alert.showAlertDialog(activity, "Internet Connection Error",
"Please Try Again Later", false);
return;
}
}
}
});
...
However, I wouldn't want to leave this answer, knowing that there are a lot more problems you're going to run into:
- You shouldn't directly manipulate the ImageView like you did in onPostExecute. By the time your AsyncTask finishes, the view might have been recycled and populated with other data. Rather, change the underlying data and call notifiedDataSetChanged if necessary.
- AsyncTask, not keeping a reference to the (multiple!) AsyncTasks means, you won't be able to cancel them when the user leaves the activity/fragment early. This means anything touching the UI will crash the app. While it is absolutely possible to perform REST requests using AsyncTasks it's painful and gets complicated very quickly if you are performing more than a handful requests. Look into libraries like Retrofit or Volley.
- Finding views using findViewById is slow and will result in scroll lag, try the ViewHolder pattern.
- Storing data in a Map like you did works "somewhat", but is very un-Java-ish and you'll have to sprinkle your code with null checks, or risking null pointer exceptions. Use POJOs instead
- Adhere to naming conventions and make it easier for yourself and everyone else to read your code.
I didn't look up links for these points, but I will add them if requested.
Buttons Missing When Scroll the ListView
You have
android:visibility="invisible"
This makes the button not visible.
And then you have
c.setVisibility(View.VISIBLE);
You need to understand that listview recycles views. So when you scroll your Buttons become invisible because the views are recycled.
Check the below link
How ListView's recycling mechanism works
Well check this example which is very similar to yours
ListView subobject clickable confilct
TO fix you can use a Model class
Model class
public class Model {
int visibility;
String value;
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
MainActivity.java
public class MainActivity extends Activity {
ListView lv;
SampleAdapter sa;
final int visible1 = View.INVISIBLE;
final int visible2 = View.VISIBLE;
ArrayList<Model> as=new ArrayList<Model>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i=0;i<20;i++)
{
Model model = new Model();
model.setValue(String.valueOf(i));
model.setVisibility(visible1);
as.add(model);
}
lv=(ListView)findViewById(R.id.listView1);
sa=new SampleAdapter(MainActivity.this);
lv.setAdapter(sa);
}
class SampleAdapter extends BaseAdapter
{
Context ctx;
Button b;
TextView tv;
LayoutInflater lin;
public SampleAdapter(Context ct) {
this.ctx=ct;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return as.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int pos, View arg1, ViewGroup arg2) {
// TODO Auto-generated method stub
lin=(LayoutInflater)ctx.getSystemService(LAYOUT_INFLATER_SERVICE);
arg1=lin.inflate(R.layout.fg, null);
tv=(TextView)arg1.findViewById(R.id.textView1);
b=(Button)arg1.findViewById(R.id.button1);
tv.setText(as.get(pos).getValue());
b.setText(as.get(pos).getValue());
arg1.setTag(pos);
b.setVisibility(as.get(pos).getVisibility());
arg1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int pos = (int) v.getTag();
Model model = as.get(pos);
model.setVisibility(visible2);
SampleAdapter.this.notifyDataSetChanged();
}
});
return arg1;
}
}
}
Snap
You can scroll up and down and the state remains
Related Topics
Adt Will Not Allow Creation of Android Activity
Java.Lang.Classnotfoundexception on Working App
Java.Lang.Illegalargumentexception: Contains a Path Separator
Cannot Load Library: Reloc_Library[1285]: Cannot Locate 'Rand'
Blue Dot and Circle Is Not Shown on Mylocation Using Android Fused Location API
How to Make an App's Background Image Repeat
How to Handle Handler Messages When Activity/Fragment Is Paused
Unexpected Value from Nativegetenabledtags: 0
What Is "Android.R.Layout.Simple_List_Item_1"
Clear Back Stack Using Fragments
Different Font Size of Strings in the Same Textview
Creating an Android Trial Application That Expires After a Fixed Time Period
How to Display Album Art Using Mediastore.Audio.Albums.Album_Art
Detecting Whether a Headset Is Plugged into an Android Device or Not
How to Create a User-Defined Function in SQLite