web-dev-qa-db-ja.com

Android:スクロール後にRecyclerViewのコンテンツがめちゃくちゃになる

RecyclerViewを使用してマークのリストを表示していますが、値の各マークはCardViewとして表示されます。ただし、下の2つのスクリーンショットに示すように、RecyclerViewを下にスクロールし、後ろにスクロールすると、カードの一部のコンテンツが失われます。赤い長方形の内容は、スクロール後に失われます。

スクロールする前; enter image description here

スクロール後; enter image description here

私はそれがRecyclerViewのバグであるかどうか疑問に思っており、それのためのグーグルの後、解決策を見つけることができません。

タイトルを除くすべてのビューは非表示であり、その表示はマークの値に依存します。

なぜこれが起こるのか誰にも分かりますか?

26
Swisyn

onBindHolderは、ビュータイプが変更された場合に新しいビューを使用しない限り、リサイクラーがビューを必要とするため、数回呼び出されました。そのため、子ビューで可視性を設定するたびに、他のビューの状態も変更されます。

上下にスクロールするたびに、これらのビューは誤った可視性オプションで再描画されます。

解決策:

SetValueメソッドを使用して値をチェックし、表示するように設定します。必要な場合は、別のメソッド「showView」を呼び出します。 elseステートメント(値は0またはnull)とhideViewを実装する必要があります...

void setValue(Object value, TextView textView, TableRow row, View seperator) {
    if (value != null) {
        if (!isEmpty(value.toString())) {
            textView.setText(String.valueOf(value));
            showViews(row, seperator);
        }
    } else
        hideViews(row, seperator);
}

private void showViews(TableRow row, View seperator) {
    row.setVisibility(View.VISIBLE);
    seperator.setVisibility(View.VISIBLE);
}

private void hideViews(TableRow row, View seperator) {
    row.setVisibility(View.INVISIBLE); // if there is a empty space change it with View.GONE
    seperator.setVisibility(View.INVISIBLE);
}
29
Emre Aktürk

この同じ問題と約24時間戦った後、私に合った解決策を見つけました。キーは_RecyclerView.ViewHolder_クラスのsetIsRecyclable()メソッドを使用していました。

ここに私のonBindViewHolder()コードのセクションがあります。

_@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    final DataSource dataSource = dataSourceList.get(position);

    holder.setIsRecyclable(false);

    holder.name.setText(dataSource.getName());
    holder.active.setChecked(dataSource.getActive());

    String logoStr = dataSource.getLogo();

    //Logo
    /**
     * Do all the logo insertion stunts here
     */
    /**
     * Register the changes to the Switch
     */
    holder.active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){
            dataSource.setActive(isChecked);
        }
    });
}
_
32
aphoe

onBindHolderは、Recycler Viewが新しいビューでない限りビューを必要とするため、数回呼び出されました。そのため、子ビューで可視性を設定するたびに、他のビューの状態も変更されます。

上下にスクロールするたびに、これらのビューは誤った可視性オプションで再描画されるため、リサイクラビューがウィジェットの以前の状態/条件/値を認識しないため、常に両方の条件を指定します。

解決策:

Ifブロックで任意のAndroid widget.setVisibility(View.Gone)の可視性を設定した場合、elseブロックでvwith widget.setVisibility(View.Visible)の反対側の可視性を設定する必要があります上記の問題。

 @Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {

    viewHolder.tvName.setText(ModelCategoryProducts.name.get(i));
    viewHolder.tvPrice.setText("Rs."+String.format("%.2f", Float.parseFloat(ModelCategoryProducts.price.get(i))));
    if(ModelCategoryProducts.special_price.get(i).equals("null")) {
        viewHolder.tvSpecialPrice.setVisibility(View.GONE); // here visibility is gone and in else it's opposite visibility i set.
        viewHolder.tvPrice.setTextColor(Color.parseColor("#ff0000"));
        viewHolder.tvPrice.setPaintFlags(0);// here Paint flag is 0 and in else it's opposite flag that i want is set.
    }else if(!ModelCategoryProducts.special_price.get(i).equals("null")){
        viewHolder.tvPrice.setTextColor(Color.parseColor("#E0E0E0"));
        viewHolder.tvSpecialPrice.setVisibility(View.VISIBLE);
        viewHolder.tvSpecialPrice.setText("Rs." + String.format("%.2f", Float.parseFloat(ModelCategoryProducts.special_price.get(i))));
        viewHolder.tvPrice.setPaintFlags(viewHolder.tvPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
    }
    if (!ModelCategoryProducts.image_url.get(i).isEmpty()) {
        Picasso.with(context)
                .load(ModelCategoryProducts.image_url.get(i))
                .into(viewHolder.ivProduct);
    }

    viewHolder.setClickListener(new ItemClickListener() {
        @Override
        public void onClick(View view, int position, boolean isLongClick) {
            if (isLongClick) {
//                    Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position) + " (Long click)", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "#" + position + " - " + ModelCategoryProducts.name.get(position), Toast.LENGTH_SHORT).show();
                Intent i = new Intent(context, ProductDetail.class);
                i.putExtra("position",position);
                i.putExtra("flagHlvCheck", 5);
                context.startActivity(i);
            }
        }
    });
}
12
Sachin Mandhare

これは、スクロールが発生したときにビューが再利用されるためです。これを修正するには、他のセル(この例ではYUZME)で表示されているビューをリセットする必要があります。

SetValue(Object value、TextView textView、TableRow row、View seperator)内では、すべてのtxtVize *を再び非表示にします。


リサイクルビューは、3つのビューから始まります。

[0] FIZ104

[1] MAT102

[2] REK361

ビューが下にスクロールされると、[0]と[1]がリサイクルされます。トップビューにスクロールすると、[2]がFIZ104およびMAT102に含まれるデータを表示するために使用され、REK361に対して行われた変更はまだそこにあります。

0
Numan1617

Exの可視性の問題で問題に直面している場合。条件に基づいてビューの可視性を設定しているが、下にスクロールすると、ビューが更新され、リサイクラビューアイテム内のビューの可視性が変更され、条件に違反します。

これが解決策です:

1。最初に、可視性を維持したいビューにtagを割り当てます。

    holder.myImageView.setTag(myTeamLists.get(position));
    MyDTOClass checkWetherToShow=(MyDTOClass)holder.myImageView.getTag();

2。ここで条件を適用し、可視性を切り替えます

    if (checkWetherToShow.getHasToShowImage()){
        holder.myImageView.setVisibility(View.VISIBLE);
    }else{
        holder.myImageView.setVisibility(View.GONE);
    }

ここでの答えの鍵はelseの部分を忘れないでくださいです。

0
Udit Kapahi