我怎样才能得到我的 ItemDecoration当我从我的适配器中删除给定 View 然后调用 notifyItemRemoved() 时,“更新”其他 View 的项目偏移量?
在我的特殊情况下,我有一个 ItemDecoration为每个项目提供少量的顶部偏移量,并为最后一个项目提供大量的底部偏移量。当我删除最后一项时,成为新的最后一项 的 View 没有任何底部偏移。
之前和之后:
如果我随后滚动列表,当我返回到列表底部时,我的"new"最后一项具有正确的偏移量。只要“新的”最后一项在屏幕上保持可见,这只是一个问题。
如果我改变我的 notifyItemRemoved()调用 notifyDataSetChanged() ,新的最后一项将应用正确的项目偏移量,但我失去了从 notifyItemRemoved() 获得的内置动画.
如果我继续使用 notifyItemRemoved()并且另外调用notifyItemChanged()在前一个项目上,我会得到正确的项目偏移量,但动画有点卡顿;倒数第二个项目(在删除之前)似乎淡出然后再次出现(在此屏幕截图中,写着“项目 19”的卡片刚刚被删除):
我知道我可以通过对我的 <RecyclerView> 应用底部填充来在我的列表末尾创建一个大空间。标记并指定 android:clipToPadding="false" , 但由于各种原因,这种解决方案是 Not Acceptable 。
我最初是在我正在开发的一个更大的应用程序中遇到这个问题的,但这里有一个演示该问题的小应用程序。
主要 Activity .java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyAdapter adapter = new MyAdapter(20);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
adapter.removeItemAt(adapter.getItemCount() - 1);
}
});
RecyclerView recycler = findViewById(R.id.recycler);
recycler.setLayoutManager(new LinearLayoutManager(this));
recycler.addItemDecoration(new MyItemDecoration());
recycler.setAdapter(adapter);
}
private static class MyItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int viewPosition = parent.getChildViewHolder(view).getLayoutPosition();
int lastPosition = state.getItemCount() - 1;
outRect.top = 20;
outRect.bottom = (viewPosition == lastPosition) ? 200 : 0;
}
}
private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final List<String> list;
private MyAdapter(int count) {
this.list = new ArrayList<>();
for (int i = 0; i < count; ++i) {
list.add("" + i);
}
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.text.setText("item: " + list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
private void removeItemAt(int position) {
if (list.size() > 0) {
list.remove(position);
notifyItemRemoved(position);
}
}
}
private static class MyViewHolder extends RecyclerView.ViewHolder {
private final TextView text;
public MyViewHolder(View itemView) {
super(itemView);
this.text = itemView.findViewById(R.id.text);
}
}
}
activity_main.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#eee">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="REMOVE LAST ITEM"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
项目.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_margin="8dp"
android:gravity="center"
android:textColor="#000"
android:textSize="16sp"/>
</android.support.v7.widget.CardView>
最佳答案
我通过更改 removeItemAt() 解决了这个问题方法如下:
private void removeItemAt(int position) {
if (list.size() > 0) {
list.remove(position);
notifyItemRemoved(position);
if (position != 0) {
notifyItemChanged(position - 1, Boolean.FALSE);
}
}
}
notifyItemChanged() 的第二个参数是关键。它实际上可以是任何对象,但我选择了 Boolean.FALSE因为它是一个“众所周知”的对象,并且因为它传达了一点 Intent :我不希望动画在我正在更改的项目上运行。
原来还有第二个onBindViewHolder() RecyclerView.Adapter 中定义的方法我以前从未见过。来自源代码:
public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
摘自该方法的文档:
The
payloadsparameter is a merge list fromnotifyItemChanged(int, Object)ornotifyItemRangeChanged(int, int, Object). If thepayloadslist is not empty, theViewHolderis currently bound to old data andAdaptermay run an efficient partial update using the payload info. If the payload is empty,Adaptermust run a full bind.
换句话说,通过在 notifyItemChanged() 中传递某些东西(任何东西)作为有效负载,我们告诉系统我们只想执行“部分更新”(在可能的情况下)。
所以,当然,我们已经指示系统执行部分更新...但是这如何停止通过调用 notifyItemChanged(position - 1) 引起的闪烁呢? ?它与 RecyclerView.ItemAnimator 有关附加到所有 RecyclerView默认情况下:DefaultItemAnimator .
DefaultItemAnimator的源代码包括这个方法:
@Override
public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
您会注意到此方法还需要一个 List<Object> payloads范围。这与其他 onBindViewHolder() 中使用的有效负载列表相同。上面提到的调用。
因为我们传递了一个 payload 参数,这个方法将返回 true .由于动画师现在被告知可以重用已经存在的 ViewHolder对于我们的“已更改”项目,它不会将其拆除并创建一个新项目(或重复使用回收的项目)...这会停止运行已更改项目上的默认淡入淡出动画!
关于android - 从 RecyclerView.Adapter 中删除项目后,RecyclerView.ItemDecoration 不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47342034/
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit