我正在使用一个自定义的 recyclerView,它可以有一个页脚和一个页眉,它应该不会影响动画,这里是一个正在发生的事情的视频:http://www.videosprout.com/video?id=00fae6ac-39ff-47b6-b981-803d2773b67b
为什么每个 View 都向后移动一个位置,然后又回到原来的位置,而不是不这样做?
这是我的适配器:
public class AddEventsAdapter extends HFRecyclerViewAdapter<String, AddEventsAdapter.ViewHolder> {
public AddEventsAdapter(Context context) {
super(context);
}
@Override
public void footerOnVisibleItem() {
}
@Override
public void addData(int position, String item) {
super.addData(position, item);
}
@Override
public ViewHolder onCreateDataItemViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.event_item, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindDataItemViewHolder(ViewHolder holder, int position) {
holder.itemTv.setText(getData().get(position));
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView itemTv;
public ViewHolder(View itemView) {
super(itemView);
itemTv = (TextView)itemView.findViewById(R.id.eventName);
}
}
}
实现:
final AddEventsAdapter MyAdapter = new AddEventsAdapter(this);
AddEventsRecycler.setAdapter(MyAdapter);
AddEventsRecycler.setLayoutManager(new LinearLayoutManager(this));
//add footer
final View footerView = LayoutInflater.from(this).inflate(R.layout.events_footer, AddEventsRecycler, false);
MyAdapter.setFooterView(footerView);
footerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAdapter.addData(0, "Event number" + ++g);
}
});
ArrayList<String> data = new ArrayList<>();
data.add("Vacation");
MyAdapter.setData(data);
自定义 RecyclerAdapter:
public abstract class HFRecyclerViewAdapter<T, VH extends RecyclerView.ViewHolder> extends BaseRecyclerViewAdapter<T> {
public HFRecyclerViewAdapter(Context context) {
super(context);
}
private static final int TYPE_HEADER = Integer.MAX_VALUE;
private static final int TYPE_FOOTER = Integer.MAX_VALUE - 1;
private static final int ITEM_MAX_TYPE = Integer.MAX_VALUE - 2;
private RecyclerView.ViewHolder headerViewHolder;
private RecyclerView.ViewHolder footerViewHolder;
class HFViewHolder extends RecyclerView.ViewHolder {
HFViewHolder(View v) {
super(v);
}
}
public void setHeaderView(View header){
if (headerViewHolder == null || header != headerViewHolder.itemView) {
headerViewHolder = new HFViewHolder(header);
notifyDataSetChanged();
}
}
public void setFooterView(View foot){
if (footerViewHolder == null || foot != footerViewHolder.itemView) {
footerViewHolder = new HFViewHolder(foot);
notifyDataSetChanged();
}
}
public void removeHeader(){
if (headerViewHolder != null){
headerViewHolder = null;
notifyDataSetChanged();
}
}
public void removeFooter(){
if (footerViewHolder != null){
footerViewHolder = null;
notifyDataSetChanged();
}
}
public boolean isHeader(int position){
return hasHeader() && position == 0;
}
public boolean isFooter(int position){
return hasFooter() && position == getDataItemCount() + (hasHeader() ? 1 : 0);
}
private int itemPositionInData(int rvPosition){
return rvPosition - (hasHeader() ? 1 : 0);
}
private int itemPositionInRV(int dataPosition){
return dataPosition + (hasHeader() ? 1 : 0);
}
@Override
public void notifyMyItemInserted(int itemPosition) {
notifyItemInserted(itemPositionInRV(itemPosition));
}
@Override
public void notifyMyItemRemoved(int itemPosition) {
notifyItemRemoved(itemPositionInRV(itemPosition));
}
@Override
public void notifyMyItemChanged(int itemPosition) {
notifyItemChanged(itemPositionInRV(itemPosition));
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
return headerViewHolder;
} else if (viewType == TYPE_FOOTER) {
return footerViewHolder;
}
return onCreateDataItemViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (!isHeader(position) && !isFooter(position))
onBindDataItemViewHolder((VH)holder, itemPositionInData(position));
if (isFooter(position)){
footerOnVisibleItem();
}
}
public abstract void footerOnVisibleItem();
@Override
public int getItemCount() {
int itemCount = getDataItemCount();
if (hasHeader()) {
itemCount += 1;
}
if (hasFooter()) {
itemCount += 1;
}
return itemCount;
}
@Override
public int getItemViewType(int position) {
if (isHeader(position)) {
return TYPE_HEADER;
}
if (isFooter(position)) {
return TYPE_FOOTER;
}
int dataItemType = getDataItemType(itemPositionInData(position));
if (dataItemType > ITEM_MAX_TYPE) {
throw new IllegalStateException("getDataItemType() must be less than " + ITEM_MAX_TYPE + ".");
}
return dataItemType;
}
public int getDataItemCount() {
return super.getItemCount();
}
/**
* make sure your dataItemType < Integer.MAX_VALUE-1
*
* @param position item view position in rv
* @return item viewType
*/
public int getDataItemType(int position){
return 0;
}
public boolean hasHeader(){
return headerViewHolder != null;
}
public boolean hasFooter(){
return footerViewHolder != null;
}
public abstract VH onCreateDataItemViewHolder(ViewGroup parent, int viewType);
public abstract void onBindDataItemViewHolder(VH holder, int position);
}
编辑: 删除 View 时会发生同样的情况,使用 removeData(getAdapterPosition()
最佳答案
为什么
这是因为元素被添加到数组的开头(索引 0)。发生这种情况时,RecyclerView
将做出视频中所示的 react ,因为它假装后备数据存储是一个列表,并且所有元素都移动到一个索引上,并且该元素被插入到开头...恰好在顶部。
您可以看到,如果在适配器末尾添加元素,它不会执行这种丑陋的行为:MyAdapter.addData(MyAdapter.getItemCount() - 1, "Event ");
.但是当然,这也不是你想要的,因为它是错误的索引......现在看起来现有元素实际上在 GUI 和其他东西上跳了一个索引......但这是一个有趣的实验验证理论。
一个解决方案
仍然使用 MyAdapter.addData(MyAdapter.getItemCount() - 1, "Event ");
在数组末尾添加元素,但使 LinearLayoutManager
显示逆向元素!这可以通过以下方式完成:
- 像这样直接设置属性:
linearLayoutManager.setReverseLayout(true)
- 或者你可以使用这个方便的构造函数:
LinearLayoutManager(context,orientation,isReversed)
您可能需要对位于适配器中的页眉和页脚做一些事情,以确保它们在 RecyclerView.Adapter
中保留为页眉和页脚,但是...一旦 RecyclerView .LayoutManager
正在反向显示内容。
关于java - Android:在 RecyclerView 中添加 View 时出现奇怪的 react ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36678466/