当程序选择时,CheckedTextView没有绘制复选标记

6
我正在编写一个Android应用程序,其中包含一个带有CheckedTextView项的ListView。它基本上是一个问题,有可变数量的答案。如果您选择一个答案,您可以按“下一步”并查看下一个问题。
我已经编写了保存答案并进入下一个问题的所有代码,并且还为用户提供了“上一个”按钮以返回上一个问题。如果以前的问题已经有答案,我希望选择该答案。这就是问题的开始。
现在,我可以获取所选答案的位置,并调用listView.setItemChecked(pos, true)但是单选按钮没有被选中。
if(selectedAnswer != null) {
    int pos = mAnswerAdapter.getPosition(selectedAnswer);
    if(pos != -1) {
        listAnswers.setItemChecked(pos, true);
    }
}

只有当我进行其他操作,例如向下拖动状态栏时,视图似乎才会刷新并绘制单选按钮的选定状态。

我使用以下方式填充答案列表:

mAnswerAdapter = new AnswerArrayAdapter(getContext(), R.layout.listitem_answer, currentQuestion.getAnswers(), user.getLanguage());
listAnswers.setAdapter(mAnswerAdapter);
mAnswerAdapter.notifyDataSetChanged();

供参考:

列表项布局:

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/listPreferredItemHeightSmall"
    android:drawableStart="@drawable/questionnaire_answer_radio"
    android:drawablePadding="10dp"
    android:gravity="center_vertical"
    android:paddingStart="5dp"
    android:paddingEnd="5dp"
    android:textColor="@android:color/white"
    android:id="@+id/questionnaire_answer_checkbox"/>

适配器:
package be.iminds.mresist;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;

import java.util.List;

import be.iminds.mresist.models.QuestionnaireDefinition;
import butterknife.BindView;
import butterknife.ButterKnife;

public class AnswerArrayAdapter extends ArrayAdapter<QuestionnaireDefinition.Answer> {

    private String mLang;
    private Context mContext;

    public AnswerArrayAdapter(Context context, int textViewResourceId, List<QuestionnaireDefinition.Answer> answers, final String lang) {
        super(context, textViewResourceId, answers);
        this.mContext = context;
        this.mLang = lang;
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        AnswerArrayAdapter.ViewHolder holder = null;
        QuestionnaireDefinition.Answer item = getItem(position);

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.listitem_answer, parent, false);
            holder = new AnswerArrayAdapter.ViewHolder(convertView);
            convertView.setTag(holder);
        } else
            holder = (AnswerArrayAdapter.ViewHolder) convertView.getTag();

        holder.answerText.setText(item.getAnswer(mLang));

        return convertView;
    }


    static class ViewHolder {
        @BindView(R.id.questionnaire_answer_checkbox) CheckedTextView answerText;

        public ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
}

相关代码片段(第一次调用openQuestion发生在onStart):
/**
     * Opens the question with the corresponding index
     * @param questionIdx
     */
    private void openQuestion(int questionIdx)
    {
        currentQuestionIdx = questionIdx;
        final Question currentQuestion = getCurrentQuestion();

        txtQuestionTitleCounter.setText(String.format(getString(R.string.questionnaire_counter), questionIdx + 1, qAssignment.getDefinition().getQuestions().size()));
        txtQuestion.setText(currentQuestion.getQuestion(user.getLanguage()));
        mAnswerAdapter = new AnswerArrayAdapter(getContext(), R.layout.listitem_answer, currentQuestion.getAnswers(), user.getLanguage());
        listAnswers.setAdapter(mAnswerAdapter);
        mAnswerAdapter.notifyDataSetChanged();


        //If it's not the last question and there are more questions than one, make the next button visible
        if(!isLastQuestion(currentQuestionIdx) && qAssignment.getDefinition().getQuestions().size() > 1)
            mNextButton.setVisibility(View.VISIBLE);
        else
            mNextButton.setVisibility(View.GONE);

        //If it's not the first question and there are more questions than one, make the previous button visible
        if(!isFirstQuestion(currentQuestionIdx) && qAssignment.getDefinition().getQuestions().size() > 1)
            mPreviousButton.setVisibility(View.VISIBLE);
        else
            mPreviousButton.setVisibility(View.GONE);

        //If the question's already been answered, fill in the answer
        markPreviousAnswer(currentQuestion);

    }


/**
     * Marks a previously selected answer
     * @param currentQuestion
     */
    private void markPreviousAnswer(Question currentQuestion) {
        if(qAssignment.getAnswerValues() != null && qAssignment.getAnswerValues().containsKey(currentQuestion.getQuestionKey())) {

            //Value of answer
            Integer value = qAssignment.getAnswerValues().get(currentQuestion.getQuestionKey());
            QuestionnaireDefinition.Answer selectedAnswer = null;
            for(QuestionnaireDefinition.Answer answer: currentQuestion.getAnswers()) {
                if(answer.getValue() == value) {
                    selectedAnswer = answer;
                    break;
                }
            }
            if(selectedAnswer != null) {
                int pos = mAnswerAdapter.getPosition(selectedAnswer);
                if(pos != -1) {
                    listAnswers.setItemChecked(pos, true);
                }
            }
        }
    }

CheckedTextView选择器可绘制项:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true">
        <shape android:shape="oval">
            <size android:width="16dp" android:height="16dp"/>
            <solid android:color="@color/colorPrimaryDarker"/>
            <stroke android:color="@android:color/white" android:width="2dp"/>
        </shape>
    </item><!-- pressed -->

    <item android:state_checked="true">
        <shape android:shape="oval">
            <size android:width="16dp" android:height="16dp"/>
            <solid android:color="@color/colorPrimaryDarker"/>
            <stroke android:color="@android:color/white" android:width="2dp"/>
        </shape>
    </item> <!-- checked -->

    <item>
        <shape android:shape="oval" android:innerRadius="10dp">
            <size android:width="16dp" android:height="16dp"/>
            <stroke android:color="@android:color/white" android:width="1dp"/>
        </shape>
    </item> <!-- default -->

</selector>

看看这篇文章 setItemChecked不起作用?,或许能帮到你。 - blizzard
完成。我添加了所有相关内容。视图实际上是一个片段,而不是一个活动。 - Ventis
@Ventis 请尝试在CheckedTextView中添加android:checkMark="?android:attr/listChoiceIndicatorSingle"属性,并设置listview android:choiceMode="singleChoice",然后检查一下。 - blizzard
@Ventis 我已经尝试了你提供的代码,它可以正常工作。你能否通过设置断点来调试,并检查 setChecked(pos,true) 是否被正确调用了? - blizzard
你设置了列表的选择模式吗?listAnswers.setChoiceMode(ListView.CHOICE_MODE_SINGLE); - Yoni Gross
显示剩余14条评论
4个回答

3

我认为你应该在将答案设置为true后调用notifyDataSetChanged(),这样ListView可以立即刷新其视图。

int pos = mAnswerAdapter.getPosition(selectedAnswer);
if(pos != -1) {
    listAnswers.setItemChecked(pos, true);
    mAnswerAdapter.notifyDataSetChanged()
}

没有区别,仍然是相同的行为。 - Ventis
抱歉,我误读了问题,我以为在适配器中检查视图并且listAnswers是数据集。 - lelloman

2

对于简单的复选框,将使用button属性:

android:button="@drawable/questionnaire_answer_radio"

对于CheckedTextView,请使用checkMark属性:

android:checkMark="@drawable/questionnaire_answer_radio"

0

我在使用单选按钮等东西时,也遇到了类似的接口问题。将布尔值传递给getView,在getView内部声明:

boolean checked; //The variable being passed
.
.
.

if(item.getBoolean){   
 radioButton.setChecked(true);
}
else
{
radioButton.setChecked(false);
}

然后,当任何人点击更改按钮时,在radioButton的onClick函数中实现以下内容:

if(item.getBoolean){   
 item.setBoolean(false)
 mAnswerAdapter.notifyDatasetChanged();
}
else
{
item.setBoolean(true)
 mAnswerAdapter.notifyDatasetChanged();
}

希望这能有所帮助


那并不是真正可行的。在getView中将CheckedTextView设置为checked时,当你只更新适配器时它仍然无法呈现。点击绘制单选按钮是有效的,但在以编程方式选择项目时绘制它是无效的。 - Ventis

0

我记不清了,因为我已经有一段时间没有使用ListView来显示列表了。如果您使用RecyclerView,将其与onBindViewHolder绑定到适配器上,ListView的等效方法应该可以解决问题。但是RecyclerView比Listview更优越

在Adapter类中创建一个名为selectedPosition的字段。当您调用notifyDatasetChanged时,会调用RecyclerView.Adapter的onBindView方法。检查要选择的位置与适配器的selectedPosition字段,并根据需要更改该位置的视图。

public void onBindViewHolder(MyViewHolder holder, final int position) {
    holder.tvCamMenu.setText(data.get(position));
    if (selectedPosition == position) {
        holder.tvCamMenu.setTextColor(Color.YELLOW);
    } else {
        holder.tvCamMenu.setTextColor(Color.WHITE);
    }
}

这是我用来设置水平RecyclerView中所选列颜色的片段。最后调用notifyDatasetChanged,当您修改所选内容时,视图将随之更改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接