我将recyclerview与扩展ListAdapter的适配器一起使用。我正在通过调整提交列表来更新内容。但每次内容更新(例如删除一项)时,recyclerview都会消失一秒钟,并与更新的内容一起重新出现。有两件事我不喜欢:第一是闪烁,第二是缺少默认动画。
如何修复它并显示流畅的默认动画?
适配器:
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);
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="adapter"
type="de.flightlogger.view.adapter.AdapterFlightRecords"/>
<variable
name="viewmodel"
type="de.flightlogger.viewmodel.VmFlightRecords"/>
<variable
name="handler"
type="de.flightlogger.view.adapter.SwipeToDeleteCallback.OnItemSwipeListener" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.ui.FragmentFlightRecords">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv_empty_rv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_entry"
android:visibility="@{viewmodel.flightRecords.size() == 0}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/cl_total_flight_time"
app:srcCompat="@drawable/ic_add_black_24dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_flight_records"
android:layout_width="match_parent"
android:layout_height="0dp"
android:adapter="@{adapter}"
android:visibility="@{viewmodel.flightRecords.size() != 0}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/cl_total_flight_time"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
bind:bgColorSwipe="@{@color/primaryDarkColor}"
bind:drawableSwipe="@{@drawable/ic_add_black_24dp}"
bind:onItemSwipe="@{(position) -> handler.onItemSwiped(position)}"
bind:swipeEnabled="@{true}"
tools:listitem="@layout/rv_item_flight_records"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_total_flight_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/primaryDarkColor"
android:padding="@dimen/rv_items_padding"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/primaryTextColor"
android:text="@string/total_flight_time"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/primaryTextColor"
android:text="Test"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</layout>
绑定适配器:
@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);
}
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);
}
}
}
我猜肯定有任何一行代码取消了默认动画,但是在哪里呢?
我找到了这个线程,但没有解决我的问题:RecyclerView上没有关于项目移除的动画
在对照我的代码检查您的代码后,发现FlightRecordsDiffCallback类中存在问题,请尝试取消代码中的return语句的注释,并删除默认值-
return false
。在我的代码中,动画没有正常工作,因为我不断地在两个返回语句之间混淆:
@重写<br>公共布尔项是相同的(…)
@ Override < br > public boolean areContentsTheSame(...)
我使用的是Json。net将对象序列化到数据库。 我向类中添加了一个新属性(该属性在数据库的json中缺失),我希望新属性在json中缺失时具有默认值。 我尝试了DefaultValue属性,但它不起作用。我正在使用私有setter和构造函数来反序列化json,因此在构造函数中设置属性的值将不起作用,因为有一个带有该值的参数。 以下是一个例子: 我预计年龄是5岁,但现在是零岁。 有什么建议吗?
问题内容: 我在play scala中具有以下模型的等效项: 对于以下Foo实例 我将获得以下JSON文档: 该JSON将持久保存并从数据存储中读取。现在,我的要求已更改,我需要向Foo添加一个属性。该属性具有默认值: 写入JSON没问题: 但是,从中读取会由于缺少“ / status”路径而产生JsError。 如何提供具有最小噪声的默认设置? (ps:我有一个答案,我将在下面发布,但我对此并不
可能有一个非常明显的答案,但如何做到以下几点: 基本上是从一个类型中检索所有键,以循环通过?
问题内容: 当未设置相同名称的环境变量时,是否可以确保将GOMAXPROCS设置为1? 此代码显示值: 并像这样运行它: 显示在这种情况下为1,但我在这里寻找一些确认。 问题答案: UPDATE 2018: 默认情况下,Go程序在将GOMAXPROCS设置为可用内核数的情况下运行;在以前的版本中,它默认为1。 从Go 1.5开始,默认值为核心数。如果您在较新的Go版本中对此不满意,则只需要显式设置
我正在尝试使用纱线与Kafka一起运行spark streaming应用程序。我得到以下堆栈跟踪错误- 造成原因:org.apache.kafka.common.config.配置异常:缺少所需的配置partition.assignment.strategy没有默认值。在org.apache.kafka.common.config.配置ef.parse(配置ef.java:124)在org.apa
问题内容: http://selenium.googlecode.com/svn/trunk/docs/api/dotnet/html/M_OpenQA_Selenium_Chrome_ChromeDriver__ctor_4.htm 有人知道chromedriver commandtimeout的默认值是什么吗?做了谷歌搜索,但找不到任何东西。 问题答案: 记住Selenium是开源的。 您可以