使用ListAdapter的android recyclerview中缺少默认动画
我正在使用recyclerview和扩展ListAdapter的适配器。我正在通过调整提交列表来更新内容。但每次内容更新(例如删除一个项目)时,recyclerview都会消失一秒钟,并与更新的内容一起重新出现。有两件事我不喜欢:第一是闪烁,第二是缺少默认动画 如何修复并显示平滑默认动画 适配器:使用ListAdapter的android recyclerview中缺少默认动画,android,android-recyclerview,android-animation,android-databinding,android-listadapter,Android,Android Recyclerview,Android Animation,Android Databinding,Android Listadapter,我正在使用recyclerview和扩展ListAdapter的适配器。我正在通过调整提交列表来更新内容。但每次内容更新(例如删除一个项目)时,recyclerview都会消失一秒钟,并与更新的内容一起重新出现。有两件事我不喜欢:第一是闪烁,第二是缺少默认动画 如何修复并显示平滑默认动画 适配器: public class AdapterFlightRecords extends ListAdapter<FlightRecordListItem, RecyclerView.ViewHold
public class AdapterFlightRecords extends ListAdapter<FlightRecordListItem, RecyclerView.ViewHolder> {
private FlightRecordListItem mRecentlyDeletedItem;
private int mRecentlyDeletedItemPosition;
private class ViewHolderFlightRecord extends RecyclerView.ViewHolder {
private RvItemFlightRecordsBinding binding;
private ViewHolderFlightRecord(final RvItemFlightRecordsBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
private void bind(final EntityFlightRecord flightRecord){
binding.setFlightRecord(flightRecord);
binding.executePendingBindings();
}
}
public class ViewHolderDate extends RecyclerView.ViewHolder {
private RvItemFlightRecordsDateBinding binding;
private ViewHolderDate(final RvItemFlightRecordsDateBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
private void bind(final DateFlightRecordsListItem item){
OffsetDateTime date = item.getDate();
binding.setYearMonth(YearMonth.from(date));
binding.executePendingBindings();
}
}
public AdapterFlightRecords(){
super(new FlightRecordsDiffCallback());
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch(viewType){
case 1:
return new ViewHolderDate(RvItemFlightRecordsDateBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
case 2:
return new ViewHolderFlightRecord(RvItemFlightRecordsBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
default:
throw new RuntimeException("No such viewType");
}
//return new ViewHolderFlightRecord(RvItemFlightRecordsBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
switch(holder.getItemViewType()){
case 1:
DateFlightRecordsListItem date = (DateFlightRecordsListItem) getItem(position);
((ViewHolderDate) holder).bind(date);
break;
case 2:
EntityFlightRecord flightRecord = (EntityFlightRecord) getItem(position);
((ViewHolderFlightRecord) holder).bind(flightRecord);
holder.itemView.setTag(flightRecord);
break;
}
}
@Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return getItem(position).getType().getValue();
}
public EntityFlightRecord getItemFromList(int position){
return (EntityFlightRecord) getItem(position);
}
/*private View.OnClickListener createOnClickListener(int id) {
return view -> {
QuestionnaireFragmentDirections.ActionQuestionnaireFragmentToSubjectFragment action = QuestionnaireFragmentDirections.actionQuestionnaireFragmentToSubjectFragment(id);
Navigation.findNavController(view).navigate(action);
};
}*/
}
class FlightRecordsDiffCallback extends DiffUtil.ItemCallback<FlightRecordListItem> {
@Override
public boolean areItemsTheSame(@NonNull FlightRecordListItem oldItem, @NonNull FlightRecordListItem newItem) {
//TODO implement equals and hashcode in Questionnaire
return false;
//return oldItem.id == newItem.id;
}
@Override
public boolean areContentsTheSame(@NonNull FlightRecordListItem oldItem, @NonNull FlightRecordListItem newItem) {
//TODO implement equals and hashcode in Questionnaire
return false;
//return oldItem.equals(newItem);
}
}
SwipeToDeleteCallback:
public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
private Drawable icon;
private ColorDrawable background;
private OnItemSwipeListener onItemSwipeListener;
private boolean swipeEnabled;
private SwipeToDeleteCallback(int dragDirs, int swipeDirs) {
super(dragDirs, swipeDirs);
}
private SwipeToDeleteCallback(Builder builder) {
this(builder.dragDirs, builder.swipeDirs);
background = builder.bgColorSwipe;
icon = builder.drawableSwipe;
swipeEnabled = builder.swipeEnabled;
onItemSwipeListener = builder.onItemSwipeListener;
}
@Override public boolean isItemViewSwipeEnabled() {
return swipeEnabled;
}
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof AdapterFlightRecords.ViewHolderDate) return 0;
return super.getSwipeDirs(recyclerView, viewHolder);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
onItemSwipeListener.onItemSwiped(position);
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, 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 backgroundCornerOffset = 20; //so background is behind the rounded corners of itemView
int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconBottom = iconTop + icon.getIntrinsicHeight();
if (dX > 0) { // Swiping to the right
int iconLeft = itemView.getLeft() + iconMargin;
int iconRight = itemView.getLeft() + icon.getIntrinsicWidth() + iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + ((int) dX) + backgroundCornerOffset, itemView.getBottom());
} else if (dX < 0) { // Swiping to the left
int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
int iconRight = itemView.getRight() - iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getRight() + ((int) dX) - backgroundCornerOffset,
itemView.getTop(), itemView.getRight(), itemView.getBottom());
} else { // view is unSwiped
background.setBounds(0, 0, 0, 0);
}
background.draw(c);
icon.draw(c);
}
public interface OnItemSwipeListener {
void onItemSwiped(int position);
}
public static final class Builder {
private int dragDirs, swipeDirs;
private Drawable drawableSwipe;
private ColorDrawable bgColorSwipe;
private OnItemSwipeListener onItemSwipeListener;
private boolean swipeEnabled;
public Builder(int dragDirs, int swipeDirs) {
this.dragDirs = dragDirs;
this.swipeDirs = swipeDirs;
}
public Builder drawableSwipe(Drawable val) {
drawableSwipe = val;
return this;
}
public Builder bgColorSwipe(ColorDrawable val) {
bgColorSwipe = val;
return this;
}
public Builder onItemSwipeListener(OnItemSwipeListener val) {
onItemSwipeListener = val;
return this;
}
public Builder setSwipeEnabled(boolean val) {
swipeEnabled = val;
return this;
}
public SwipeToDeleteCallback build() {
return new SwipeToDeleteCallback(this);
}
}
}
公共类SwipeToDeleteCallback扩展了ItemTouchHelper.SimpleCallback{
私人绘图图标;
私人彩色背景;
私有OnItemSwipeListener OnItemSwipeListener;
私有布尔可交换;
专用SwipeToDeleteCallback(int-dragDirs、int-swipeDirs){
超级(dragDirs、swipeDirs);
}
专用SwipeToDeleteCallback(生成器生成器){
这(builder.dragDirs、builder.swipiders);
背景=builder.bgColorSwipe;
icon=builder.drawableSwipe;
SwipEnabled=builder.SwipEnabled;
onItemSwipeListener=builder.onItemSwipeListener;
}
@重写公共布尔值IsItemViewSwipEnabled(){
返回开关已启用;
}
@凌驾
public int getSwipeDirs(RecyclerView RecyclerView,RecyclerView.ViewHolder ViewHolder){
if(AdapterLightRecords.ViewHolderDate的viewHolder实例)返回0;
返回super.getswipiders(recyclerView、viewHolder);
}
@凌驾
公共布尔onMove(RecyclerView RecyclerView、RecyclerView.ViewHolder ViewHolder、RecyclerView.ViewHolder目标){
返回false;
}
@覆盖已擦除的公共void(RecyclerView.ViewHolder ViewHolder,int方向){
int position=viewHolder.getAdapterPosition();
onItemSwipeListener.onItemSwiped(位置);
}
@凌驾
public void onChildraw(画布c、RecyclerView RecyclerView、RecyclerView.ViewHolder ViewHolder、float dX、float dY、int actionState、boolean isCurrentlyActive){
super.onchildraw(c、recyclerView、viewHolder、dX、dY、actionState、isCurrentlyActive);
View itemView=viewHolder.itemView;
int backgroundCornerOffset=20;//因此背景位于itemView的圆角后面
int iconMargin=(itemView.getHeight()-icon.getIntrinsicHeight())/2;
int iconTop=itemView.getTop()+(itemView.getHeight()-icon.getIntrinsicHeight())/2;
int iconBottom=iconTop+icon.getIntrinsicHeight();
如果(dX>0){//向右滑动
int iconLeft=itemView.getLeft()+iconMargin;
int iconRight=itemView.getLeft()+icon.getIntrinsicWidth()+iconMargin;
icon.setBounds(iconLeft、iconTop、iconRight、iconBottom);
background.setBounds(itemView.getLeft(),itemView.getTop(),
itemView.getLeft()+((int)dX)+backgroundCornerOffset,itemView.getBottom());
}如果(dX<0){//向左滑动,则为else
int iconLeft=itemView.getRight()-iconMargin-icon.getIntrinsicWidth();
int iconRight=itemView.getRight()-iconMargin;
icon.setBounds(iconLeft、iconTop、iconRight、iconBottom);
background.setBounds(itemView.getRight()+((int)dX)-backgroundCornerOffset,
itemView.getTop()、itemView.getRight()、itemView.getBottom());
}否则{//视图将不被擦除
背景.背景(0,0,0,0);
}
背景图(c);
图标绘制(c);
}
公共接口侦听器{
无效(内部位置);
}
公共静态最终类生成器{
私人内特德拉格迪尔、瑞士人;
私人提款刷卡;
私人彩绘bgColorSwipe;
私有OnItemSwipeListener OnItemSwipeListener;
私有布尔可交换;
公共建筑商(国际德拉格迪尔、国际瑞士){
this.dragDirs=dragDirs;
this.swipiders=swipiders;
}
公共生成器可提取滑动(可提取val){
drawableSwipe=val;
归还这个;
}
公共生成器bgColorSwipe(可着色val){
bgColorSwipe=val;
归还这个;
}
公共生成器onItemSwipeListener(onItemSwipeListener val){
mswipelistener=val;
归还这个;
}
公共生成器已启用(布尔值){
SwipEnabled=val;
归还这个;
}
公共SwipeToDeleteCallback生成(){
返回新的SwipeToDeleteCallback(此);
}
}
}
我猜一定有任何一行代码会抑制默认动画,但是在哪里呢
我找到了此线程,但没有解决我的问题:
对照我的代码检查您的代码后,FlightRecordsDiffCallback类中出现问题 尝试在代码中取消对return语句的注释,并删除默认值-return false。 在我的代码中-动画无法正常工作,因为我经常在两个返回状态之间混合: @Override
公共布尔项相同(…) @覆盖
公共布尔值的内容相同(…) 这让我检查了你的代码,我认为问题在于,你使用return false,而不是在newItem和oldItem之间创建一个布尔返回。
@BindingAdapter(value = {"swipeEnabled", "drawableSwipe", "bgColorSwipe", "onItemSwipe"}, requireAll = false)
public static void setItemSwipeToRecyclerView(RecyclerView recyclerView, boolean swipeEnabled, Drawable drawableSwipe, ColorDrawable bgColorSwipe,
SwipeToDeleteCallback.OnItemSwipeListener onItemSwipe) {
ItemTouchHelper.Callback swipeCallback = new SwipeToDeleteCallback
.Builder(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT)
.bgColorSwipe(bgColorSwipe)
.drawableSwipe(drawableSwipe)
.setSwipeEnabled(swipeEnabled)
.onItemSwipeListener(onItemSwipe)
.build();
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
private Drawable icon;
private ColorDrawable background;
private OnItemSwipeListener onItemSwipeListener;
private boolean swipeEnabled;
private SwipeToDeleteCallback(int dragDirs, int swipeDirs) {
super(dragDirs, swipeDirs);
}
private SwipeToDeleteCallback(Builder builder) {
this(builder.dragDirs, builder.swipeDirs);
background = builder.bgColorSwipe;
icon = builder.drawableSwipe;
swipeEnabled = builder.swipeEnabled;
onItemSwipeListener = builder.onItemSwipeListener;
}
@Override public boolean isItemViewSwipeEnabled() {
return swipeEnabled;
}
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof AdapterFlightRecords.ViewHolderDate) return 0;
return super.getSwipeDirs(recyclerView, viewHolder);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
onItemSwipeListener.onItemSwiped(position);
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, 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 backgroundCornerOffset = 20; //so background is behind the rounded corners of itemView
int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconBottom = iconTop + icon.getIntrinsicHeight();
if (dX > 0) { // Swiping to the right
int iconLeft = itemView.getLeft() + iconMargin;
int iconRight = itemView.getLeft() + icon.getIntrinsicWidth() + iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + ((int) dX) + backgroundCornerOffset, itemView.getBottom());
} else if (dX < 0) { // Swiping to the left
int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
int iconRight = itemView.getRight() - iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getRight() + ((int) dX) - backgroundCornerOffset,
itemView.getTop(), itemView.getRight(), itemView.getBottom());
} else { // view is unSwiped
background.setBounds(0, 0, 0, 0);
}
background.draw(c);
icon.draw(c);
}
public interface OnItemSwipeListener {
void onItemSwiped(int position);
}
public static final class Builder {
private int dragDirs, swipeDirs;
private Drawable drawableSwipe;
private ColorDrawable bgColorSwipe;
private OnItemSwipeListener onItemSwipeListener;
private boolean swipeEnabled;
public Builder(int dragDirs, int swipeDirs) {
this.dragDirs = dragDirs;
this.swipeDirs = swipeDirs;
}
public Builder drawableSwipe(Drawable val) {
drawableSwipe = val;
return this;
}
public Builder bgColorSwipe(ColorDrawable val) {
bgColorSwipe = val;
return this;
}
public Builder onItemSwipeListener(OnItemSwipeListener val) {
onItemSwipeListener = val;
return this;
}
public Builder setSwipeEnabled(boolean val) {
swipeEnabled = val;
return this;
}
public SwipeToDeleteCallback build() {
return new SwipeToDeleteCallback(this);
}
}
}