Reputation: 2285
I am basically trying hide and show a text in the list row when I am clicking a button in the list row. I have added the onClick() for the button inside getView() method and then calling the notifyDataSetChanged(). But it is not working. No change in the text visibility. Here is my custom Adapter code:
public class ListAdapter extends BaseAdapter {
private Context context;
private List<String> mListQuestion = null;
private List<String> mListAnswer = null;
ViewHolder holder = null;
boolean flag = false;
public ListAdapter(Context context, List<String> question, List<String> answer ) {
this.mListQuestion = question;
this.mListAnswer = answer;
this.context = context;
}
@Override
public Object getItem(int position)
{
return mListQuestion.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getCount() {
return mListQuestion.size();
}
@Override
@SuppressWarnings("deprecation")
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.list_faq_item, null);
holder = new ViewHolder();
holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.tvQuestion.setText(mListQuestion.get(position));
holder.tvAns.setText(mListAnswer.get(position));
holder.ivArrow.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if (flag == false)
{
Logger.d("arrow clicked when flag is false");
holder.tvAns.setVisibility(View.VISIBLE);
holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);
flag = true;
}
else if (flag == true)
{
Logger.d("arrow clicked when flag is true");
holder.tvAns.setVisibility(View.GONE);
holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);
flag = false;
}
notifyDataSetChanged();
}
});
return convertView;
}
static class ViewHolder {
TextView tvQuestion;
TextView tvAns;
Button ivArrow;
}
}
Can someone please tell what I am doing wrong here. Thanks in Advance.
-Arindam.
Upvotes: 1
Views: 2936
Reputation: 1830
public class ListAdapter extends BaseAdapter {
private Context context;
private List<String> mListQuestion = null;
private List<String> mListAnswer = null;
ViewHolder holder = null;
private List<Boolean> textViewVisibileState;
public ListAdapter(Context context, List<String> question, List<String> answer ) {
this.mListQuestion = question;
this.mListAnswer = answer;
this.context = context;
this.textViewVisibileState=new ArrayList<>(Arrays.asList(new Boolean[getCount()]));
Collections.fill(this.textViewVisibileState,false);
}
@Override
public Object getItem(int position)
{
return mListQuestion.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getCount() {
return mListQuestion.size();
}
@Override
@SuppressWarnings("deprecation")
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.list_faq_item, null);
holder = new ViewHolder();
holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.tvQuestion.setText(mListQuestion.get(position));
holder.tvAns.setText(mListAnswer.get(position));
if(textViewVisibileState.get(position))
{
holder.tvAns.setVisibility(View.GONE);
holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);
}
else
{
Logger.d("arrow clicked when flag is false");
holder.tvAns.setVisibility(View.VISIBLE);
holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);
}
holder.ivArrow.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if (textViewVisibileState.get(position))
{
textViewVisibileState.set(position,false);
}
else
{
textViewVisibileState.set(position,true);
}
notifyDataSetChanged();
}
});
return convertView;
}
static class ViewHolder {
TextView tvQuestion;
TextView tvAns;
Button ivArrow;
}
}
This will work.
Upvotes: 4
Reputation: 38585
Calling notifyDataSetChanged()
causes ListView
to rebuild everything. It will remove its child views, call getView()
for all the items that are visible, and thus you will rebind all the data for those items.
But your data hasn't actually changed. You haven't modified anything in the questions list, so binding the data again is meaningless. Instead you have tried to change something in your ViewHolder
object, but there's no guarantee that the convertView
you get after a notifyDataSetChanged()
is for the same position as before, so it's possible that some other item has been affected (or perhaps none at all?).
Try removing the call to notifyDataSetChanged()
from the OnClickListener
. A visibility change should cause a re-layout of the view hierarchy, but as long as you haven't told ListView
that the data has changed, it should keep all its current children.
Upvotes: 1
Reputation: 6215
The variable flag
is not context sensitive to object holder
. So flag
is always = false in your case. How about setVisibility(View.GONE)
initially? And then setVisibility(View.VISIBLE)
ONLY when ivArrow is clicked upon.
Upvotes: 1
Reputation: 988
Create an instance of the adapter, e.g Adapter myAdapter = new Adapter
, set it to a listview
or recyclerview
e.g listview.setAdapter(mydapter)
and everytime you add new data to it call adapter.notifyDataSetChanged()
Upvotes: 0