Listview Subobject Clickable Confilct

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.

Sample Image

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:

  1. 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.
  2. 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.
  3. Finding views using findViewById is slow and will result in scroll lag, try the ViewHolder pattern.
  4. 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
  5. 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

Sample Image



Related Topics



Leave a reply



Submit