how to maintain inflated radio button state in listView

387 views Asked by At

So I have a listView that I'm populating with a static xml, but inside that xml I have a dynamic container that I inflate items into when the user clicks on an item in the listView.

Basically the view(s) I'm inflating looks like (x) amount of radio buttons and a textView.

The reason I have to do it this way is that the amount of radio buttons inflated could change depending on what type of list item it is.

The issue I'm running into is that once the radio buttons are inflated and the user selects a button, the list doesn't save the state from which the user last selected the radio button. Or rather, it recycles the radio button state to another position in the list. Which is somewhat correct since that's what listview does. I want it to only save the user selected answer at the position they selected in the listView.

I've been working on this for about a week and can't find a good solution. If anyone would like to help I'd greatly appreciate it. I'll post the relevant code below.

SurveyView (Custom container to inflate views into)

public class SurveyView extends LinearLayout {
private LinearLayout pollContainer;
private Context context;
private String type;
private int numOfAnswers;
private ListView answersList;
private ArrayList<String> answers;
private boolean visibility = true;
private OnClickListener listener;
private ArrayList<View> options;
private static int tag = 88888888;
private ArrayList<Boolean> checked;
private Integer[] percent = {33, 25, 15, 20, 7};
private int position;


/**
 * @param context      the context of the activity
 * @param type         the type of poll
 * @param numOfAnswers if the poll is multiple choice (most likely) provide number of answers.
 */
public void setLayout(final Context context, String type, int numOfAnswers, final int position) {
    this.type = type;
    this.numOfAnswers = numOfAnswers;
    this.context = context;
    this.position = position;

    switch (type) {
        case "Multiple":
            if (visibility) {
                for (int i = 0; i < numOfAnswers; i++) {
                    View v = LayoutInflater.from(getContext()).inflate(R.layout.poll_multiple_choice_answers_row, null);
                    View space = LayoutInflater.from(getContext()).inflate(R.layout.space, null);

                    v.setTag(tag);
                    options.add(v);
                    final RadioButton rb = (RadioButton) v.findViewById(R.id.answer_voted_button);
                    rb.setClickable(false);
                    rb.setFocusable(false);


                    tag++;
                    addView(v);
                    addView(space);
                }
            }
            break;
        case "Slider":
            break;
        case "Tree":
            break;
        case "Sentiment":
            break;
    }
}

public SurveyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setOrientation(VERTICAL);
    options = new ArrayList<>();
}

public boolean isVisibility() {
    return visibility;
}

public void setVisibility(boolean visibility) {
    this.visibility = visibility;
}

public void setAnswers(int position) {
    RadioButton rb;
    for (int i = 0; i < options.size(); i++) {
        if (i != position) {
            rb = (RadioButton) options.get(i).findViewById(R.id.answer_voted_button);
            rb.setChecked(false);
        }
        else {
            rb = (RadioButton) options.get(position).findViewById(R.id.answer_voted_button);
            rb.setChecked(true);
            for (int p = 0; p < options.size(); p++) {
                TextView answer = (TextView) options.get(p).findViewById(R.id.poll_answer);
                answer.setText("Abraham Lincoln");
                TextView tv = (TextView) options.get(p).findViewById(R.id.answer_percent);
                tv.setText(Integer.toString(percent[p]));
                options.get(p).setBackground(new PercentDrawable(percent[p], context.getResources().getColor(R.color.icitizen_poll_opaque_gold)));
            }
        }
    }
}

Adapter for the listview

PollsAdapter extends BaseAdapter {
private LayoutInflater inflater;
private Context context;
private ArrayList<Card> data;
private ArrayList<RelativeLayout.LayoutParams> params;
private ArrayList<Integer> pollAnswers;
private int selectedPosition = 0;

public PollsAdapter(Context context, ArrayList<Card> data,
                    ArrayList<RelativeLayout.LayoutParams> params,
                    ArrayList<Integer> pollAnswers) {
    this.context = context;
    this.data = data;
    inflater = LayoutInflater.from(context);
    this.params = params;
    this.pollAnswers = pollAnswers;
}

public static class ViewHolder {
    TextView type;
    TextView time;
    TextView text;
    TextView space;
    TextView pollSpace;
    ImageView type_icon;
    SurveyView answerView;
    RadioButton rb;
    ArrayList<View> options;

    private ViewHolder() {
    }

    private ViewHolder(TextView type, TextView time, TextView text, ImageView type_icon, SurveyView answerView) {
        this.type = type;
        this.time = time;
        this.text = text;
        this.type_icon = type_icon;
        this.answerView = answerView;
    }

    public TextView getType() {
        return type;
    }

    public void setType(TextView type) {
        this.type = type;
    }

    public TextView getTime() {
        return time;
    }

    public void setTime(TextView time) {
        this.time = time;
    }

    public TextView getText() {
        return text;
    }

    public void setText(TextView text) {
        this.text = text;
    }

    public ImageView getType_icon() {
        return type_icon;
    }

    public void setType_icon(ImageView type_icon) {
        this.type_icon = type_icon;
    }

    public SurveyView getAnswerView() {
        return answerView;
    }

    public void setAnswerView(SurveyView answerView) {
        this.answerView = answerView;
    }
}

@Override
public int getCount() {
    return data.size();
}

@Override
public Object getItem(int position) {
    return data.get(position);
}

@Override
public long getItemId(int position) {
    return 0;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        viewHolder = new ViewHolder();
        convertView = inflater.inflate(R.layout.polls_card_layout, null);
        viewHolder.type = (TextView)convertView.findViewById(R.id.card_type);
        viewHolder.time = (TextView)convertView.findViewById(R.id.card_poll_time);
        viewHolder.text = (TextView)convertView.findViewById(R.id.card_text);
        viewHolder.space = (TextView)convertView.findViewById(R.id.card_space);
        viewHolder.pollSpace = (TextView)convertView.findViewById(R.id.poll_space);
        viewHolder.type_icon = (ImageView)convertView.findViewById(R.id.card_icon);
        viewHolder.answerView = (SurveyView)convertView.findViewById(R.id.poll_component);
        viewHolder.rb = (RadioButton)viewHolder.answerView.findViewById(R.id.answer_voted_button);
        convertView.setTag(viewHolder);
    }
    else {
        viewHolder = (ViewHolder)convertView.getTag();
    }

    viewHolder.type.setText(data.get(position).getType());
    viewHolder.time.setText(data.get(position).getTime());
    viewHolder.text.setText(data.get(position).getText());
    viewHolder.answerView.setLayoutParams(params.get(position));
    viewHolder.answerView.setLayout(context, "Multiple", 5, position);
    viewHolder.answerView.setVisibility(false);
    viewHolder.answerView.setAnswers(pollAnswers.get(position));

    return convertView;
}

The fragment for the listview

SurveyListFragment extends ListFragment {
private ArrayList<Card> cardList;
private PollsAdapter adapter;
private ArrayList<Answer> answers;
ArrayList<Integer> visible;
private ArrayList<RelativeLayout.LayoutParams> params;
private ArrayList<Integer> pollAnswers;

/**
    when user clicks on a poll display the poll options for it
 */
@Override
public void onListItemClick(ListView l, View view, final int position, long id) {
    final PollsAdapter.ViewHolder holder = (PollsAdapter.ViewHolder)adapter.getView(position, view, l).getTag();
    if (holder.getAnswerView().getHeight() == 0) {

        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.BELOW, R.id.poll_space);
        params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
        //holder.getAnswerView().setLayoutParams(params);
        this.params.set(position, params);

        for (int i = 0; i < holder.getAnswerView().getOptions().size(); i++) {
            holder.getAnswerView().getOptions().get(i).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    for (int p = 0; p < holder.getAnswerView().getOptions().size(); p++) {
                        if (holder.getAnswerView().getOptions().get(p) == v) {
                            holder.getAnswerView().setAnswers(p);
                            pollAnswers.set(position, p);
                            adapter = new PollsAdapter(getActivity(), cardList, SurveyListFragment.this.params, pollAnswers);
                            setListAdapter(adapter);
                        }
                    }
                }
            });
        }
    }
    else {
        holder.getAnswerView().setVisibility(false);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 0);
        params.addRule(RelativeLayout.BELOW, R.id.poll_space);
        params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
        this.params.set(position, params);
       // holder.getAnswerView().setLayoutParams(params);
        adapter.notifyDataSetChanged();
    }
    super.onListItemClick(l, view, position, id);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    setListAdapter(adapter);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    cardList = new ArrayList<>();
    answers = new ArrayList<>();
    visible = new ArrayList<>();
    params = new ArrayList<>();
    pollAnswers = new ArrayList<>();
    Answer answer = new Answer();
    answer.setText("one");
    answers.add(answer);
    answer = new Answer();
    answer.setText("two");
    answers.add(answer);
    answer = new Answer();
    answer.setText("three");
    answers.add(answer);
    answer = new Answer();
    answer.setText("four");
    answers.add(answer);

    Card card = new Card();
    card.setType("Polls");
    card.setText("What issue listed below would you like to see as a priority for Nashville’s next mayor?");
    card.setTime("Closing Soon");


    for (int i = 0; i < cardList.size(); i++) {
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 0);
        params.addRule(RelativeLayout.BELOW, R.id.poll_space);
        params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
        this.params.add(params);
        pollAnswers.add(-1);

    }
    adapter = new PollsAdapter(getActivity(), cardList, params, pollAnswers);
}
1

There are 1 answers

0
Rindt Lin On

Parse the survey object to the view class when you create the convertView. And parse a new object every time recycle previous views. Here are some codes.

1) Initialize the views in ProductListItemView

public ProductListItemView(Context context, ProductItem item) {
    super(context);
    mProductItem = item;
    initView(context);
}

/**
 * This function sets up all the Views contained in the FrameLayout
 *
 * @param context
 */
private void initView(Context context) {
    addView(LayoutInflater.from(context).inflate(R.layout.list_item_product, null));
    ButterKnife.inject(this);
    if (mProductItem != null) {
        setProductItem(mProductItem);
    }
}

2) set object to the view

public void setProductItem(final ProductItem item) {

    /**
     * Clear Listener. Important!! Cause by Android Recycle View
     * Do whatever you want to reset the recycled view or new view
     */
    mPurchase.setOnClickListener(null);

    endorsed_by_image.setVisibility(INVISIBLE);
    endorsed_by_name.setVisibility(INVISIBLE);
    mBtnEndorse.setOnCheckedChangeListener(null);
    mProductItem = item;
    mProductName.setText(mProductItem.getName());

3) In your adapter

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        final ProductItem item = mProducts.get(position);

        if (convertView == null) {
            convertView = new ProductListItemView(getActivity(), item);
        } else {
            ((ProductListItemView) convertView).setProductItem(item);
        }
    } 

Hope I explain it well.

And in getView(), it is better to implement ViewHolder. Visit http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html