【问题标题】:FirebaseRecyclerAdapter doesn't recognize first layout as a positionFirebaseRecyclerAdapter 无法将第一个布局识别为位置
【发布时间】:2018-11-19 12:34:06
【问题描述】:

我的标题有点难以理解,但基本上当我将项目添加到我的数据库中时,它应该显示在 RecyclerView 中。现在在我的 RecyclerView 中,我有两个布局,但问题是我的数据库的第一项落后于我在其他布局中的第一项。因此,如果我的数据库中有 3 个项目,它只显示数据库中的 2 个项目,第一个项目隐藏在 RecyclerView 中我的第一个项目后面,这是一个完全不使用数据库的不同布局。

这是我的代码:

 FirebaseRecyclerOptions<Event> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Event>()
            .setQuery(query1, Event.class).build();
    AccAdapter = new FirebaseRecyclerAdapter<Event, RecyclerView.ViewHolder>(firebaseRecyclerOptions){

        final static int TYPE_HEADER = 0;
        final static int TYPE_ITEM = 1;


        @Override
        public int getItemViewType(int position) {
            if (position == 0) return TYPE_HEADER;
            return TYPE_ITEM;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

            if (viewType == TYPE_HEADER){
                View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_add_items,
                        parent, false);
                return new ProdudctHolder3(view);
            } else {
                View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_acc,
                        parent, false);
                return new ProductHolder2(view);
            }
        }

        @Override
        protected void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, final Event model) {
            if (holder instanceof ProdudctHolder3){
                ((ProdudctHolder3) holder).addBackground.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        startActivity(new Intent(getActivity(), AccAddItems.class ));
                    }
                });
            } else{

                final ProductHolder2 productHolder2 = (ProductHolder2) holder;


                productHolder2.mName.setText(model.getName());
                productHolder2.view.setBackgroundResource(getBackgroundDrawable(Integer.valueOf(model.getProductAmount())));
                productHolder2.mbackground.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {

                        dialog = new Dialog(getActivity());
                        dialog.setContentView(R.layout.popup_edit_product);

                        SeekBar amountSeekBar = dialog.findViewById(R.id.amountSeekBar);
                        amountSeekBar.setMax(100);
                        amountSeekBar.setProgress(Integer.valueOf(model.getProductAmount()));
                        amountSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                            @Override
                            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                                progress = i;
                            }

                            @Override
                            public void onStartTrackingTouch(SeekBar seekBar) {

                            }

                            @Override
                            public void onStopTrackingTouch(SeekBar seekBar) {
                                getRef(holder.getAdapterPosition()).child("productAmount").setValue(String.valueOf(progress));
                                dialog.dismiss();

                            }
                        });

                        dialog.show();

                    }
                });

                productHolder2.mbackground.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        final PopupMenu popupMenu = new PopupMenu(getActivity(), productHolder2.mbackground);

                        popupMenu.inflate(R.menu.menu_acc);
                        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                            @Override
                            public boolean onMenuItemClick(MenuItem menuItem) {
                                switch (menuItem.getItemId()){
                                    case R.id.deleteProduct:
                                        getRef(productHolder2.getAdapterPosition()).removeValue();
                                        popupMenu.dismiss();
                                        return true;

                                    default:
                                        return false;
                                }
                            }
                        });

                        popupMenu.show();

                        return true;
                    }
                });

            }
        }

    };

    mAccRecyclerViewRef.setAdapter(AccAdapter);

我的两个产品持有人

私有类 ProdudctHolder3 扩展 RecyclerView.ViewHolder{

    private RelativeLayout addBackground;

    public ProdudctHolder3(View itemView) {
        super(itemView);
        addBackground = itemView.findViewById(R.id.mBackground2);
    }
}

private class ProductHolder2 extends RecyclerView.ViewHolder{

    private TextView mName;
    private RelativeLayout mbackground;
    private View view;

    public ProductHolder2(View itemView) {
        super(itemView);

        mName = itemView.findViewById(R.id.ItemName);
        mbackground = itemView.findViewById(R.id.mBackground1);
        view = itemView.findViewById(R.id.amountIndicator);

    }
}

【问题讨论】:

  • 仍然没有解决它,请有人帮忙。我不明白为什么我已经看了好几个小时了
  • 您介意分享您的布局 xml 文件吗?
  • 可以粘贴xml代码吗?
  • 我已经更新了!

标签: android firebase firebase-realtime-database android-recyclerview firebaseui


【解决方案1】:

既然您可以轻松地进行自定义,为什么还要使用 Firebase Recycler Adapter?如果我理解得很好,您希望将一个项目固定在位置 0(标题),而其他项目将添加到第一个项目下方,对吗?如果是这样,这是我喜欢使用的解决方案:

public interface ViewType {
    public int getViewType();
}

public interface ViewTypeDelegateAdapter {
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}

public class ViewTypes {
    public static int HEADER = 0
    public static int ITEM = 1
}

public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {

    private int resID;
    private Context context;

    public ProductDelegateAdapter(int resID, Context context) {
        this.resID = resID;
        this.context = context;
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
        return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
        (holder as ProductHolder).bind("test");
    }

    class ProductHolder extends RecyclerView.ViewHolder {

        public ProductHolder(View view) {
            super(view);
        }

        public void bind(String test) {

        }

    }

}

public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {

    private int resID;
    private Context context;

    public ProductDelegateAdapter(int resID, Context context) {
        this.resID = resID;
        this.context = context;
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
        return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
        (holder as HeaderHolder).bind("test");
    }

    class HeaderHolder extends RecyclerView.ViewHolder {

        public HeaderHolder(View view) {
            super(view);
        }

        public void bind(String test) {

        }

    }

}

public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private Context context;
    private List<ViewType> items;
    private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
    private ViewType headerItem;

    public AccAdapter(Context context) {
        this.context = context;
        this.items = new ArrayList();
        this.delegateAdapters = new SparseArrayCompat();
        this.headerItem = new ViewType() {
            @Override
            public int getViewType() {
                return ViewTypes.HEADER;
            }
        };

        this.items.add(this.headerItem);
        this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
        this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
        return delegateAdapters.get(viewType).onCreateViewHolder(parent);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
        delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
    }

    @Override
    public Int getItemViewType(Int position) {
        return items.get(position).getViewType();
    }

    @Override
    public Int getItemCount() {
        return items.getSize();
    }

    public void add(ViewType viewType) {
        val initPosition = this.items.size - 1
        this.items.add(item)
        notifyItemRangeChanged(initPosition, this.items.size + 1)
    }

}

public class Event implements ViewType {

    private String id;

    @Override
    public int getViewType() {
        return ViewTypes.ITEM;
    }

}

请原谅我的一些语法错误,我已经从 Kotlin 翻译成 Java 来帮助你。希望对您有所帮助!

【讨论】:

  • 很抱歉,我使用 FirebaseRecyclerAdapter 的原因是它可以实时更新数据并带来其他好处。
  • 您可以在不使用 FirebaseRecyclerAdapter 的情况下轻松实现这一目标。您可以通过这种方式制作结构,然后向您的 Firebase 节点注册一个侦听器,然后只需从“主适配器”调用 add 方法。更加干净简洁。
  • 有没有办法用 firebaserecyclerAdapter 解决这个问题
【解决方案2】:

理想的解决方案是在一个RecyclerView 上设置两个适配器,但不幸的是这是不可能的。 但是,您可以制作一个处理两种类型项目的自定义适配器。我将通过一个例子来解释这一点。

假设您需要显示两种类型的对象,humansaliens。您的对象需要完全不同的布局和完全不同的ViewHoldersViewHolders请看下面的代码:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static class HumanViewHolder extends RecyclerView.ViewHolder {
        public HumanViewHolder(View itemView) {
            super(itemView);

            //Prepare your ViewHolder
        }

        public void bind(Human human) {

            //Display your human object
        }
    }

    private static class AlienViewHolder extends RecyclerView.ViewHolder {
        public AlienViewHolder(View itemView) {
            super(itemView);

            //Prepare your ViewHolder
        }

        public void bind(Alien alien) {

            //Display your alien object
        }
    }
}

首先,您需要向适配器添加两个不同的常量来表示两种视图:

private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;

为简单起见,我们还假设您将对象存储在列表中:

private List<Object> items = new ArrayList<>();

public MyAdapter(List<Object> items) {
    this.items.addAll(items);

    //Other stuff if needed
}

现在,你需要做的第一件事是实现getItemViewType() 方法:

@Override
public int getItemViewType(int position) {
    if (items.get(position) instanceof Human) {
        return ITEM_TYPE_HUMAN;
    } else {
        return ITEM_TYPE_ALIEN;
    }
} 

其次,您需要像这样在onCreateViewHolder() 方法中使用项目类型:

@Override 
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)  {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());

    if (viewType == ITEM_TYPE_HUMAN) {
        View view = layoutInflater.inflate(R.layout.item_human, parent, false);

        return new HumanViewHolder(view);
    } else {      
        View view = layoutInflater.inflate(R.layout.item_alien, parent, false);

        return new AlienViewHolder(view);
    } 
} 

最后,你只需要像这样绑定正确的视图持有者:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    Object item = items.get(position);

    if (viewHolder instanceof HumanViewHolder) {
        ((HumanViewHolder) viewHolder).bind((Human) item);
    } else {
        ((AlienViewHolder) viewHolder).bind((Alien) item);
    } 
} 

【讨论】:

  • 嘿,这个问题是 onCreateViewHolder。使用 FirebaseRecyclerAdapter,我无法按照上面的建议返回不同的 ViewHolder。
  • 在这种情况下,直接在您的持有人类中进行。同样的原则也适用,对吧?
  • 这就是我所拥有的。检查我的 ProductHolder 类的代码我根据 viewType 值准备我的 Viewholder
  • 您是否尝试过使用该 if 语句,但仅用于单个 TextView?
  • 什么意思?对不起
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-21
  • 2015-09-21
相关资源
最近更新 更多