我使用recyclerView以一种很好的方式显示数据库中的所有条目。我添加了SwipeToDeleteCallback类,以提供从recyclerView中删除项目的能力。当删除项时,recyclerview向上提升下一项。
每个项目包含2个textView,在recyclerView适配器中的onBindViewHolder()中更新。问题是当我删除一些项目时,屏幕上出现的最后一个项目没有正确显示这些textView。我已经尝试了adapter.notifyItemChanged()和view.postInvalidate(),但没有用。
看起来如果recyclerView试图在动画期间更新其子对象的值,它会产生这样的错误。我不确定我说的对不对。
Screenshot: After deleting a few previous item two last items doesn't appear properly
DictionaryActivity.kt:
class DictionaryActivity : AppCompatActivity() {
private lateinit var coordinatorLayout : CoordinatorLayout
private lateinit var recyclerView : RecyclerView
private lateinit var dictionaryAdapter: DictionaryAdapter
private lateinit var linearLayoutManager: LinearLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dictionary)
coordinatorLayout = findViewById<View>(R.id.dictionaryCoordinatorLayout) as CoordinatorLayout
recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
// Create adapter passing in the sample user data
dictionaryAdapter = DictionaryAdapter(Database.getAllEntries(this))
// Attach the adapter to the recyclerview to populate items
recyclerView.adapter = dictionaryAdapter
// Set layout manager to position the items
linearLayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = linearLayoutManager
enableSwipeToDeleteAndUndo()
}
private fun enableSwipeToDeleteAndUndo() {
val swipeToDeleteCallback: SwipeToDeleteCallback = object : SwipeToDeleteCallback(this) {
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, i: Int) {
val position = viewHolder.adapterPosition
val entry: Entry = dictionaryAdapter.entries[position]
dictionaryAdapter.removeEntry(position)
val snackbar = Snackbar
.make(
coordinatorLayout,
"Item was removed from the list.",
Snackbar.LENGTH_LONG
)
snackbar.setAction("UNDO") {
dictionaryAdapter.restoreEntry(entry, position)
recyclerView.scrollToPosition(position)
}
snackbar.setActionTextColor(Color.YELLOW)
snackbar.show()
}
}
val itemTouchhelper = ItemTouchHelper(swipeToDeleteCallback)
itemTouchhelper.attachToRecyclerView(recyclerView)
}
}
SwipeToDeleteCallback.java:
abstract public class SwipeToDeleteCallback extends ItemTouchHelper.Callback {
Context mContext;
private Paint clearPaint;
private ColorDrawable background;
private int backgroundColor;
private Drawable deleteDrawable;
private int intrinsicWidth;
private int intrinsicHeight;
SwipeToDeleteCallback(Context context) {
mContext = context;
background = new ColorDrawable();
backgroundColor = Color.parseColor("#b80f0a");
clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
deleteDrawable = ContextCompat.getDrawable(mContext, R.drawable.ic_delete);
intrinsicWidth = deleteDrawable.getIntrinsicWidth();
intrinsicHeight = deleteDrawable.getIntrinsicHeight();
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, ItemTouchHelper.LEFT);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int itemHeight = itemView.getHeight();
boolean isCancelled = dX == 0 && !isCurrentlyActive;
if (isCancelled) {
clearCanvas(c, itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom());
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
return;
}
background.setColor(backgroundColor);
background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
background.draw(c);
int deleteIconTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
int deleteIconMargin = (itemHeight - intrinsicHeight) / 2;
int deleteIconLeft = itemView.getRight() - deleteIconMargin - intrinsicWidth;
int deleteIconRight = itemView.getRight() - deleteIconMargin;
int deleteIconBottom = deleteIconTop + intrinsicHeight;
deleteDrawable.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom);
deleteDrawable.draw(c);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
private void clearCanvas(Canvas c, Float left, Float top, Float right, Float bottom) {
c.drawRect(left, top, right, bottom, clearPaint);
}
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return 0.7f;
}
}
DictionaryAdapter.java:
public class DictionaryAdapter extends
RecyclerView.Adapter<DictionaryAdapter.ViewHolder> {
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
public class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
private final TextView wordRussianTextView;
private final TextView wordHebrewTextView;
private final ProgressBar progressBar;
private final ImageButton editButton;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
wordRussianTextView = (TextView) itemView.findViewById(R.id.textView7);
wordHebrewTextView = (TextView) itemView.findViewById(R.id.textView8);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar2);
editButton = (ImageButton) itemView.findViewById(R.id.imageButton2);
}
}
private List<Entry> entries;
// Pass in the contact array into the constructor
public DictionaryAdapter(List<Entry> entries) {
this.entries = entries;
}
// Usually involves inflating a layout from XML and returning the holder
@NonNull
@Override
public DictionaryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View contactView = inflater.inflate(R.layout.word_element, parent, false);
// Return a new holder instance
ViewHolder viewHolder = new ViewHolder(contactView);
return viewHolder;
}
// Involves populating data into the item through holder
@Override
public void onBindViewHolder(DictionaryAdapter.ViewHolder holder, int position) {
// Get the data model based on position
Entry entry = entries.get(position);
// Set item views based on your views and data model
holder.wordRussianTextView.setText(entry.getWord(Entry.LANGUAGE.RUSSIAN));
holder.wordHebrewTextView.setText(entry.getWord(Entry.LANGUAGE.HEBREW));
holder.progressBar.setProgress(entry.getProgress());
Log.e("onBindViewHolder", "New item:");
Log.e("onBindViewHolder", "russian : " + holder.wordRussianTextView.getText());
Log.e("onBindViewHolder", "hebrew : " + holder.wordHebrewTextView.getText());
Log.e("onBindViewHolder", "--------------------------------");
//holder.wordRussianTextView
}
// Returns the total count of items in the list
@Override
public int getItemCount() {
return entries.size();
}
public void removeEntry(int position) {
entries.remove(position);
notifyItemRemoved(position);
}
public void restoreEntry(Entry entry, int position) {
entries.add(position, entry);
notifyItemInserted(position);
}
public List<Entry> getEntries() {
return entries;
}
}
1条答案
按热度按时间2sbarzqh1#
我自己找到了答案。出于某种原因,我将textViews的参数
layout_width
设置为0dp
而不是wrap_content
。我改变了值,一切都开始正常工作。