以编程方式选择时,CheckedTextView 未绘制复选标记

Posted

技术标签:

【中文标题】以编程方式选择时,CheckedTextView 未绘制复选标记【英文标题】:CheckedTextView not drawing checkmark when programmatically selected 【发布时间】:2017-06-09 10:39:27 【问题描述】:

我正在编写一个包含带有 CheckedTextView 项目的 ListView 的 android 应用程序。这基本上是一个具有可变数量答案的问题。如果您选择一个答案,您可以按“下一步”并查看下一个问题。

我已经编写了所有代码来保存答案并转到下一个问题,我还为用户提供了一个“上一个”按钮来返回上一个问题。如果上一个问题已经有答案,我希望选择该答案。这就是问题开始的地方。

现在,我可以得到所选答案的位置,我打电话给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();

供参考:

list_item 布局:

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    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: android:/>
            <solid android:color="@color/colorPrimaryDarker"/>
            <stroke android:color="@android:color/white" android:/>
        </shape>
    </item><!-- pressed -->

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

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

</selector>

【问题讨论】:

没有人吗?这是一个非常阻塞的问题。我已经尝试使用自定义复选标记绘图,但没有运气。 看看这个帖子setItemChecked not working?,看看有没有帮助。 问题是,它确实有效。但是,它不会绘制复选标记,直到通过将状态栏向下拖动到应用程序上来“刷新”视图。 列表视图的选择模式也是“singleChoice” 使用适配器、list_item_layout 和活动代码的完整代码更新您的帖子,以进一步分析问题。 【参考方案1】:

我认为您应该在将答案设置为 true 后致电 notifyDataSetChanged(),以便 ListView 可以立即刷新其视图

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

【讨论】:

没有区别。仍然是相同的行为。 对不起,我看错了问题,我认为视图正在适配器中进行检查,而 listAnswers 是数据集【参考方案2】:

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

android:button="@drawable/questionnaire_answer_radio"

对于 CheckedTextView 使用属性 checkMark:

android:checkMark="@drawable/questionnaire_answer_radio"

【讨论】:

【参考方案3】:

我在使用单选按钮等界面时遇到了类似的问题。将一个布尔值传递给 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();

希望对你有帮助

【讨论】:

那行不通。当您刚刚更新适配器时,将 CheckedTextView 设置为在 getView 中检查仍然不会呈现它。绘制单选按钮 onClick 可以正常工作,但是当您以编程方式选择项目时绘制它就不行了。【参考方案4】:

我不记得了,因为我已经有一段时间没有使用 ListView 来显示列表了。如果您使用 RecyclerView,则将其与 onBindViewHolder 绑定到适配器,ListView 的等效方法应该可以解决问题。但是 RecyclerView 是 superior 到 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 中选定列的颜色的 sn-p。最后调用notifyDatasetChanged,视图将在您修改为选中时更改。

【讨论】:

以上是关于以编程方式选择时,CheckedTextView 未绘制复选标记的主要内容,如果未能解决你的问题,请参考以下文章

Android基础到进阶UI CheckedTextView 使用+实例

Android基础到进阶UI CheckedTextView 使用+实例

以编程方式自动布局到 UISearchController 选择它时消失

以编程方式在点击时选择的 UITabBar 视图

Fabricjs - 以编程方式选择对象以立即移动/拖动

以编程方式更改模型时选择框不更新