简体   繁体   English

CheckedTextView在编程选择时不绘制复选标记

[英]CheckedTextView not drawing checkmark when programmatically selected

I'm writing an Android app that has a ListView with CheckedTextView items in it. 我正在编写一个Android应用程序,其中包含带有CheckedTextView项目的ListView。 It's basically a question with a variable number of answers. 这基本上是一个答案数量可变的问题。 If you select one answer you can press "next" and see the next question. 如果您选择一个答案,可以按“下一步”,然后查看下一个问题。

I've written all the code to save the answers and go to the next questions, and I've also provided the user with a "previous" button to go back to the previous question. 我已经编写了所有代码来保存答案并转到下一个问题,我还为用户提供了一个“上一个”按钮以回到上一个问题。 If the previous question already has an answer, I want that answer to be selected. 如果上一个问题已经有答案,我希望选择该答案。 And that's where the problems start. 这就是问题开始的地方。

Right now, I can get the position of the selected answer and I call listView.setItemChecked(pos, true) but the radio button is not selected. 现在,我可以获取所选答案的位置,并调用listView.setItemChecked(pos, true)但未选中单选按钮。

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

Only when I do something else, like drag down the statusbar does the view seem to refresh and draw the selected state of the radiobutton. 只有当我执行其他操作时,例如向下拖动状态栏,视图才会刷新并绘制无线电按钮的选定状态。

I fill the list with answers like this: 我在列表中填写如下答案:

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

For reference: 以供参考:

The list_item layout: list_item布局:

<?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"/>

The adapter: 适配器:

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);
        }
    }
}

The relevant fragment code (first call to openQuestion happens onStart): 相关的片段代码(第一次调用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 selector drawable: CheckedTextView选择器drawable:

<?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>

I think you should call notifyDataSetChanged() after setting the answer to true so that the ListView can refresh its views immediatly 我认为您应该在将答案设置为true后调用notifyDataSetChanged() ,以便ListView可以立即刷新其视图

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

For the simple checkbox, the attribute button will be used: 对于简单的复选框,将使用属性按钮:

android:button="@drawable/questionnaire_answer_radio"

And for the CheckedTextView use the attribute checkMark: 对于CheckedTextView,使用checkMark属性:

android:checkMark="@drawable/questionnaire_answer_radio"

I've had similar problems facing the interface while using things such as radio buttons. 在使用诸如单选按钮之类的东西时,我遇到了类似的界面问题。 Pass along a boolean value to the getView and then inside the getView state that: 将布尔值传递给getView,然后在getView状态内:

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

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

Then when anyone clicks to change the button implement the following in the onClick function of the radioButton: 然后,当任何人点击更改按钮时,在radioButton的onClick函数中实现以下内容:

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

I hope this helps 我希望这有帮助

I can't remember, since i have not used ListView for lists for awhile. 我不记得了,因为我暂时没有使用ListView列表。 If you use RecyclerView, u bind that with onBindViewHolder to adapter, the equivalent method of the ListView should do the trick. 如果你使用RecyclerView,你将它与onBindViewHolder绑定到适配器,ListView的等效方法应该可以解决问题。 But RecyclerView is superior to Listview. 但RecyclerView 优于 Listview。

Creata field, named selectedPosition for instance, inside the Adapter class. Creata字段,例如,在Adapter类中命名为selectedPosition。 When you invoke notifyDatasetChanged , onBindView method of RecyclerView.Adapter is invoked. 当您调用notifyDatasetChanged ,将调用notifyDatasetChanged onBindView方法。 Check position that you want to be selected with the selectedPosition field of the adapter and change the view with that position as you like. 使用适配器的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);
    }
}

This is the snippet i use to set color of the selected column inside the horizontal RecyclerView. 这是我用来在水平RecyclerView中设置所选列的颜色的片段。 Finally call notifyDatasetChanged and the view will change as you modify it to be when selected. 最后调用notifyDatasetChanged ,视图将在您选择时将其修改为更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM