Android как обновить текстовый стиль TextView внутри RecyclerView после события проверки CheckBox - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь создать приложение типа простого списка покупок, в котором каждый элемент отображается в RecyclerView с CheckBox и двумя кнопками ImageButton. Когда флажок установлен, я хочу отобразить тексты элементов как зачеркнутые.

Вот мой файл макета адаптера RecyclerView:

<androidx.cardview.widget.CardView
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:id="@+id/adapterCardItemDisplay"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp">

        <TextView
            android:id="@+id/adapterTvItemName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/adapterTvItemNameBeg"
            android:textSize="18sp"
            android:layout_margin="1dp"
            />

        <TextView
            android:id="@+id/adapterTvItemQuantity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/adapterTvItemQuantityBeg"
            android:textSize="18sp"
            android:layout_margin="1dp"
            />

        <TextView
            android:id="@+id/adapterTvItemColor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/adapterTvItemColorBeg"
            android:textSize="18sp"
            android:layout_margin="1dp"
            />

        <TextView
            android:id="@+id/adapterTvItemSize"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/adapterTvItemSizeBeg"
            android:textSize="18sp"
            android:layout_margin="1dp"
            />

        <TextView
            android:id="@+id/adapterTvItemRemarks"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/adapterTvItemRemarksBeg"
            android:textSize="18sp"
            android:layout_margin="1dp"
            />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="15dp"

            >

            <CheckBox
                android:id="@+id/adapterChkItemChecked"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"

                />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"

                android:orientation="horizontal"
                android:gravity="start"
                >

                <ImageButton
                    android:id="@+id/adapterImgBtnEdit"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="#FFFCFC"
                    android:src="@android:drawable/ic_menu_edit"
                    android:layout_marginEnd="10dp"/>

                <ImageButton
                    android:id="@+id/adapterImgBtnDelete"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="#F8F4F4"
                    android:src="@android:drawable/ic_delete" />
            </LinearLayout>

        </LinearLayout>

    </LinearLayout>
</androidx.cardview.widget.CardView>

А вот мой адаптер Java Файл :

public class ItemDisplayAdapter extends RecyclerView.Adapter <ItemDisplayAdapter.ViewHolder> {
    private static final String TAG = "ItemDisplayAdapter";
    private CardView adapterCardItemDisplay;
    private TextView adapterTvItemName;
    private TextView adapterTvItemQuantity;
    private TextView adapterTvItemColor;
    private TextView adapterTvItemSize;
    private TextView adapterTvItemRemarks;
    private CheckBox adapterChkItemChecked;
    private ImageButton adapterImgBtnEdit;
    private ImageButton adapterImgBtnDelete;

    private Context context;
    private ArrayList<Item> adapterItemArrayList;

    public ItemDisplayAdapter(Context context, ArrayList<Item> adapterItemArrayList) {
        this.context = context;
        this.adapterItemArrayList = adapterItemArrayList;
    }

    private void checkAnItem (boolean isChecked,int position) {
        if (isChecked) {
            Log.d(TAG, "checkAnItem: here");
            adapterTvItemName.setPaintFlags(adapterTvItemName.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            adapterTvItemQuantity.setPaintFlags(adapterTvItemQuantity.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            adapterTvItemColor.setPaintFlags(adapterTvItemColor.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            adapterTvItemSize.setPaintFlags(adapterTvItemSize.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            adapterTvItemRemarks.setPaintFlags(adapterTvItemRemarks.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
        }else {
            adapterTvItemName.setPaintFlags(adapterTvItemName.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            adapterTvItemQuantity.setPaintFlags(adapterTvItemQuantity.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            adapterTvItemColor.setPaintFlags(adapterTvItemColor.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            adapterTvItemSize.setPaintFlags(adapterTvItemSize.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            adapterTvItemRemarks.setPaintFlags(adapterTvItemRemarks.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
        }
        //invalidateViews();

    }

    private void invalidateViews () {
        adapterTvItemName.invalidate();
        adapterTvItemQuantity.invalidate();
        adapterTvItemColor.invalidate();
        adapterTvItemSize.invalidate();
        adapterTvItemRemarks.invalidate();
    }

    private void editAnItem () {

    }

    private void deleteAnItem () {

    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_list_view,parent,false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        //Log.d(TAG, "onBindViewHolder: "+position);
        Item item = adapterItemArrayList.get(position);
        adapterCardItemDisplay.setTag(item.getId());
        String nameString = context.getResources().getString(R.string.adapterTvItemNameBeg)+
                " "+item.getName();
        adapterTvItemName.setText(nameString);
        String quantityString = context.getResources().getString(R.string.adapterTvItemQuantityBeg)+
                " "+item.getQuantity();
        adapterTvItemQuantity.setText(quantityString);
        if (item.getColor().isEmpty()) {
            adapterTvItemColor.setVisibility(View.GONE);
        } else {
            adapterTvItemColor.setVisibility(View.VISIBLE);
            String colorString = context.getResources().getString(R.string.adapterTvItemColorBeg) +
                    " " + item.getColor();
            adapterTvItemColor.setText(colorString);
        }
        if (item.getSize() == 0) {
            adapterTvItemSize.setVisibility(View.GONE);
        } else {
            adapterTvItemSize.setVisibility(View.VISIBLE);
            String sizeString = context.getResources().getString(R.string.adapterTvItemSizeBeg)+
                    " "+item.getSize();
            adapterTvItemSize.setText(sizeString);
        }
        if (item.getRemarks().isEmpty()) {
            adapterTvItemRemarks.setVisibility(View.GONE);
        } else {
            adapterTvItemRemarks.setVisibility(View.VISIBLE);
            String remarksString = context.getResources().getString(R.string.adapterTvItemRemarksBeg)+
                    " "+item.getRemarks();
            adapterTvItemRemarks.setText(remarksString);
        }
        adapterChkItemChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG, "onCheckedChanged: here");
                checkAnItem(isChecked,position);
                notifyItemChanged(position);
                adapterChkItemChecked.setChecked(isChecked);

            }
        });
        adapterImgBtnEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                editAnItem();
            }
        });
        adapterImgBtnDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                deleteAnItem();
            }
        });
    }

    @Override
    public int getItemCount() {
        return adapterItemArrayList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            adapterCardItemDisplay = itemView.findViewById(R.id.adapterCardItemDisplay);
            adapterTvItemName = itemView.findViewById(R.id.adapterTvItemName);
            adapterTvItemQuantity = itemView.findViewById(R.id.adapterTvItemQuantity);
            adapterTvItemColor = itemView.findViewById(R.id.adapterTvItemColor);
            adapterTvItemSize = itemView.findViewById(R.id.adapterTvItemSize);
            adapterTvItemRemarks = itemView.findViewById(R.id.adapterTvItemRemarks);
            adapterChkItemChecked = itemView.findViewById(R.id.adapterChkItemChecked);
            adapterImgBtnEdit = itemView.findViewById(R.id.adapterImgBtnEdit);
            adapterImgBtnDelete = itemView.findViewById(R.id.adapterImgBtnDelete);

        }
    }
}

Я не могу получить ожидаемое поведение. Нажатие на CheckBox не дает эффект зачеркивания для этого элемента, возможно, повторное нажатие приводит к изменению другого элемента (скажем, нажатие флажка на элементе 0 фактически вносит изменение за счет для элемента 4 как такового), иногда получить эффект зачеркивания при повторных щелчках, но в это время флажок не остается установленным. Так что я в растерянности, как этого добиться.

Аннулирование представлений не сработало, как и метод notifyItemChanged (position).

Любые предложения?

ОБНОВЛЕНИЕ Таким образом, я последовал предложению Даниэля, и он избавился от 50% проблемы, но флажок продолжает не проверяться после обновления представления, я полагаю, это ожидаемое поведение, так как представление обновляется, поэтому у меня был код в CheckedChangeListener, который устанавливает checkBox с параметром isChecked после notifyItemChanged (position), но, похоже, работает неправильно. Что я делаю не так?

Обновлен код для класса адаптера:

public class ItemDisplayAdapter extends RecyclerView.Adapter <ItemDisplayAdapter.ViewHolder> {
    private static final String TAG = "ItemDisplayAdapter";


    private Context context;
    private ArrayList<Item> adapterItemArrayList;

    public ItemDisplayAdapter(Context context, ArrayList<Item> adapterItemArrayList) {
        this.context = context;
        this.adapterItemArrayList = adapterItemArrayList;
    }

    private void checkAnItem (ViewHolder holder,boolean isChecked,int position) {
        if (isChecked) {
            Log.d(TAG, "checkAnItem: here");
            holder.adapterTvItemName.setPaintFlags(holder.adapterTvItemName.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            holder.adapterTvItemQuantity.setPaintFlags(holder.adapterTvItemQuantity.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            holder.adapterTvItemColor.setPaintFlags(holder.adapterTvItemColor.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            holder.adapterTvItemSize.setPaintFlags(holder.adapterTvItemSize.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            holder.adapterTvItemRemarks.setPaintFlags(holder.adapterTvItemRemarks.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
        }else {
            holder.adapterTvItemName.setPaintFlags(holder.adapterTvItemName.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            holder.adapterTvItemQuantity.setPaintFlags(holder.adapterTvItemQuantity.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            holder.adapterTvItemColor.setPaintFlags(holder.adapterTvItemColor.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            holder.adapterTvItemSize.setPaintFlags(holder.adapterTvItemSize.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
            holder.adapterTvItemRemarks.setPaintFlags(holder.adapterTvItemRemarks.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
        }
        //invalidateViews();

    }

    private void invalidateViews (ViewHolder holder) {
        holder.adapterTvItemName.invalidate();
        holder.adapterTvItemQuantity.invalidate();
        holder.adapterTvItemColor.invalidate();
        holder.adapterTvItemSize.invalidate();
        holder.adapterTvItemRemarks.invalidate();
    }

    private void editAnItem () {

    }

    private void deleteAnItem () {

    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item_list_view,parent,false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
        //Log.d(TAG, "onBindViewHolder: "+position);
        Item item = adapterItemArrayList.get(position);
        holder.adapterCardItemDisplay.setTag(item.getId());
        String nameString = context.getResources().getString(R.string.adapterTvItemNameBeg)+
                " "+item.getName();
        holder.adapterTvItemName.setText(nameString);
        String quantityString = context.getResources().getString(R.string.adapterTvItemQuantityBeg)+
                " "+item.getQuantity();
        holder.adapterTvItemQuantity.setText(quantityString);
        if (item.getColor().isEmpty()) {
            holder.adapterTvItemColor.setVisibility(View.GONE);
        } else {
            holder.adapterTvItemColor.setVisibility(View.VISIBLE);
            String colorString = context.getResources().getString(R.string.adapterTvItemColorBeg) +
                    " " + item.getColor();
            holder.adapterTvItemColor.setText(colorString);
        }
        if (item.getSize() == 0) {
            holder.adapterTvItemSize.setVisibility(View.GONE);
        } else {
            holder.adapterTvItemSize.setVisibility(View.VISIBLE);
            String sizeString = context.getResources().getString(R.string.adapterTvItemSizeBeg)+
                    " "+item.getSize();
            holder.adapterTvItemSize.setText(sizeString);
        }
        if (item.getRemarks().isEmpty()) {
            holder.adapterTvItemRemarks.setVisibility(View.GONE);
        } else {
            holder.adapterTvItemRemarks.setVisibility(View.VISIBLE);
            String remarksString = context.getResources().getString(R.string.adapterTvItemRemarksBeg)+
                    " "+item.getRemarks();
            holder.adapterTvItemRemarks.setText(remarksString);
        }
        holder.adapterChkItemChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG, "onCheckedChanged: here");
                checkAnItem(holder,isChecked,position);
                notifyItemChanged(position);
               holder.adapterChkItemChecked.setChecked(isChecked);

            }
        });
        holder.adapterImgBtnEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                editAnItem();
            }
        });
        holder.adapterImgBtnDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                deleteAnItem();
            }
        });
    }

    @Override
    public int getItemCount() {
        return adapterItemArrayList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private CardView adapterCardItemDisplay;
        private TextView adapterTvItemName;
        private TextView adapterTvItemQuantity;
        private TextView adapterTvItemColor;
        private TextView adapterTvItemSize;
        private TextView adapterTvItemRemarks;
        private CheckBox adapterChkItemChecked;
        private ImageButton adapterImgBtnEdit;
        private ImageButton adapterImgBtnDelete;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            adapterCardItemDisplay = itemView.findViewById(R.id.adapterCardItemDisplay);
            adapterTvItemName = itemView.findViewById(R.id.adapterTvItemName);
            adapterTvItemQuantity = itemView.findViewById(R.id.adapterTvItemQuantity);
            adapterTvItemColor = itemView.findViewById(R.id.adapterTvItemColor);
            adapterTvItemSize = itemView.findViewById(R.id.adapterTvItemSize);
            adapterTvItemRemarks = itemView.findViewById(R.id.adapterTvItemRemarks);
            adapterChkItemChecked = itemView.findViewById(R.id.adapterChkItemChecked);
            adapterImgBtnEdit = itemView.findViewById(R.id.adapterImgBtnEdit);
            adapterImgBtnDelete = itemView.findViewById(R.id.adapterImgBtnDelete);

        }
    }


}

Вот GIF, изображающий проблему:

GIF, изображающий работу view

Надеюсь, вы увидите, как checkBox продолжает сбрасывать себя.

Спасибо, и наилучшими пожеланиями.

1 Ответ

0 голосов
/ 04 апреля 2020

Здесь может быть более одной проблемы, но давайте начнем с одной первой.

Ваши ссылки на представления находятся в классе адаптера.

    private CardView adapterCardItemDisplay;
    private TextView adapterTvItemName;
    private TextView adapterTvItemQuantity;
    private TextView adapterTvItemColor;
    private TextView adapterTvItemSize;
    private TextView adapterTvItemRemarks;
    private CheckBox adapterChkItemChecked;
    private ImageButton adapterImgBtnEdit;
    private ImageButton adapterImgBtnDelete;

Это должно быть в держателе представления class.

Логическое обоснование состоит в том, что у каждого представления есть собственный набор ссылок на представления.

Теперь, чтобы исправить это, создайте внутренний класс static и переместите вышеуказанные ссылки в класс держателя представления .

    static class ViewHolder extends RecyclerView.ViewHolder {
        private CardView adapterCardItemDisplay;
        private TextView adapterTvItemName;
        private TextView adapterTvItemQuantity;
        private TextView adapterTvItemColor;
        private TextView adapterTvItemSize;
        private TextView adapterTvItemRemarks;
        private CheckBox adapterChkItemChecked;
        private ImageButton adapterImgBtnEdit;
        private ImageButton adapterImgBtnDelete;

        ViewHolder(@NonNull View itemView) {
            ...
        }
    }

Отрегулируйте использование в onBindViewHolder, добавив holder. спереди.

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        ...
        holder.adapterTvItemName.setText(nameString);
        holder.adapterTvItemQuantity.setText(quantityString);
                holder.adapterChkItemChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG, "onCheckedChanged: here");
                checkAnItem(holder, isChecked,position);
                notifyItemChanged(position);
                holder.adapterChkItemChecked.setChecked(isChecked);

            }
        });
        holder.adapterImgBtnEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                editAnItem();
            }
        });
        ... etc...
    }

Добавьте держатель вида в качестве нового параметра в checkAnItem и используйте вид Держатель для доступа к приложению просмотра ссылок. Та же идея, что и в onBindViewHolder.

    private void checkAnItem (ViewHolder holder, boolean isChecked,int position) {  
        ...
      holder.adapterTvItemSize.setPaintFlags(holder.adapterTvItemSize.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
        ...
    }

Пока это все. Дайте мне знать о прогрессе.

Редактировать :

Проблема со снятием флажка в случайном порядке является хорошо известной. См. этот ответ . В основном, когда он отмечен, вам нужно переключить логическое значение в вашем адаптере, чтобы отслеживать, какой элемент отмечен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...