Firebase ui - 在android中设置FirebaseRecyclerView的标题视图

时间:2016-11-15 13:30:07

标签: android firebase firebase-realtime-database firebaseui

我需要在RecyclerView中添加标题视图,而我使用的适配器来自Firebase ui。

对于普通的RecyclerView适配器,我只需处理不同的视图类型并处理一些计数/位置偏移。

但在FirebaseAdapter中遵循相同的方法似乎是一种不好的做法,在这种情况下最好的方法是什么。

这是我能得到的最接近的。

       mAdapter = new FirebaseRecyclerAdapter<Comment, RecyclerView.ViewHolder>(Comment.class,
            R.layout.item_comment, CommentHolder.class, ref) {

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

        @Override
        protected void populateViewHolder(RecyclerView.ViewHolder viewHolder, Comment comment, int position) {
            //cast to comment holder
            final CommentHolder commentViewHolder = (CommentHolder) viewHolder;

            //initialize view
            commentViewHolder.setComment(comment.getComment());
            commentViewHolder.setTime(comment.getTimestamp());

            //get user details and set view
            DatabaseReference ref = FirebaseDatabase.getInstance().getReference(FireContract.PATH_USER_PROFILE)
                    .child(comment.getUserKey());
            ref.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    User user = dataSnapshot.getValue(User.class);
                    if(user != null) {
                        commentViewHolder.setName(user.getName());
                        commentViewHolder.setUsername("@" + user.getUsername());
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });
        }

        //return header view holder is type is header else return super from firebase ui
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(viewType == TYPE_HEADER){
                View view = LayoutInflater.from(getActivity()).inflate(R.layout.post_details,
                        parent, false);

                return new PostViewHolder(view);
            }
            else
                return super.onCreateViewHolder(parent, viewType);
        }

        //initialize post details as header if position is 0 else call super with position less
        //by one to cater for the header offset
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
            if(position == 0)
                initializePostDetails((PostViewHolder) viewHolder);
            else
                super.onBindViewHolder(viewHolder, position - 1);
        }

        //return view type header if position is 0 else call super from firebase ui
        @Override
        public int getItemViewType(int position) {
            if(position == 0)
                return TYPE_HEADER;

            return super.getItemViewType(position - 1);
        }

        //set count equal to 1 plus actual list items, 1 is added for header view
        @Override
        public int getItemCount() {
            return super.getItemCount() + 1;
        }

    };

但这会产生cannot resolve constructor问题,但即使解决了这个问题,它也可能无效。

2 个答案:

答案 0 :(得分:1)

所以,这是我能够升级我的适配器,它确实适用于我但不确定它是否仍然是实现此目标的最佳方法。如果有人可以验证这一点或者可能提出更简单的解决方案,那将会很棒

mAdapter = new FirebaseRecyclerAdapter<Comment, RecyclerView.ViewHolder>(Comment.class,
            R.layout.item_comment, RecyclerView.ViewHolder.class, ref) {

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

        @Override
        protected void populateViewHolder(RecyclerView.ViewHolder viewHolder, Comment comment, int position) {
            Log.d(TAG, "running populateViewHolder");
        }

        //return header view holder is type is header else return super from firebase ui
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(viewType == TYPE_HEADER){
                View view = LayoutInflater.from(getActivity()).inflate(R.layout.post_details,
                        parent, false);

                return new PostViewHolder(view);
            }
            //if type is not header its item view, so return commentHolder instance
            else{
                View view = LayoutInflater.from(getActivity()).inflate(R.layout.item_comment,
                        parent, false);

                return new CommentHolder(view);
            }

        }

        //initialize post details as header if position is 0 else call super with position less
        //by one to cater for the header offset
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
            //if holder is post view holder, initialize header
            if(viewHolder instanceof PostViewHolder)
                initializePostDetails((PostViewHolder) viewHolder);

            else{
                //cast to comment holder
                final CommentHolder commentViewHolder = (CommentHolder) viewHolder;
                Comment comment = getItem(position);

                //initialize view
                commentViewHolder.setComment(comment.getComment());
                commentViewHolder.setTime(comment.getTimestamp());

                //get user details and set view
                DatabaseReference ref = FirebaseDatabase.getInstance().getReference(FireContract.PATH_USER_PROFILE)
                        .child(comment.getUserKey());
                ref.addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        User user = dataSnapshot.getValue(User.class);
                        if(user != null) {
                            commentViewHolder.setName(user.getName());
                            commentViewHolder.setUsername("@" + user.getUsername());
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }

        }

        //return view type header if position is 0 else call super from firebase ui
        @Override
        public int getItemViewType(int position) {
            if(position == 0)
                return TYPE_HEADER;

            return TYPE_ITEM;
        }

        //set count equal to 1 plus actual list items, 1 is added for header view
        @Override
        public int getItemCount() {
            return super.getItemCount() + 1;
        }

        //return comment item, decrement 1 from position to avoid out of rand exception as it was
        //incremented for adding header
        @Override
        public Comment getItem(int position) {
            return super.getItem(position - 1);
        }
    };

答案 1 :(得分:0)

更新(2016年12月6日):如果您需要检查一个空的FirebaseRecyclerView,这一切都有点hacky,但到目前为止,这是我知道的唯一方法。 总而言之,你需要照顾两个案例。

  1. 当列表中有项目时 - 您可以将项目装饰器添加到Recycler视图,以便在列表中有项目时创建标题。 (正如我在原帖中所写,或as seen here)。如果您不需要担心空的回收者视图,这就是您需要做的全部。

  2. 当列表为空时 - 项目装饰器无法显示,因此您可以添加在View.VISIBLE(对于空列表)和View.GONE(对于填充列表)之间切换的视图。 (有关详细信息,请查看this link

    View emptyView = findViewById(R.id.empty_view);
    dataBaseReference.addListenerValueEvent(new ValueEventListener() {
         @Override
         public void onDataChange(DataSnapshot dataSnapshot) {
              if (dataSnapshot.hasChildren()) {
                    emptyView.setVisibility(View.GONE);
                 } else {
                    emptyView.setVisibility(View.VISIBLE);
                 }
    
         @Override
         public void onCancelled(DatabaseError databaseError) {
    
         }
    

    });

  3. 因此,一旦列表中有内容,我们就会删除该空视图,并显示项目装饰器,它将随着回收器视图的滚动而移动。

    **原始邮寄**

    我最近遇到了同样的困境。我使用了一个普通的RecyclerViewAdapter解决方案,它可以很好地工作here,这只是将一个ItemDecorator添加到recyclerView本身,如下所示:

    recyclerView.addItemDecoration(new HeaderDecoration(this,
                               recyclerView,  R.layout.test_header));
    

    从这里开始制作自定义物品装饰器。如果你需要水平或任何东西,你会搞乱那里的值(大多数引用顶部需要引用左边的东西):

    public class HeaderDecoration extends RecyclerView.ItemDecoration {
    
    private View mLayout;
    
    public HeaderDecoration(final Context context, RecyclerView parent, @LayoutRes int resId) {
        // inflate and measure the layout
        mLayout = LayoutInflater.from(context).inflate(resId, parent, false);
        mLayout.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
    }
    
    
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        // layout basically just gets drawn on the reserved space on top of the first view
        mLayout.layout(parent.getLeft(), 0, parent.getRight(), mLayout.getMeasuredHeight());
        for (int i = 0; i < parent.getChildCount(); i++) {
            View view = parent.getChildAt(i);
            if (parent.getChildAdapterPosition(view) == 0) {
                c.save();
                final int height = mLayout.getMeasuredHeight();
                final int top = view.getTop() - height;
                c.translate(0, top);
                mLayout.draw(c);
                c.restore();
                break;
            }
        }
    }
    
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (parent.getChildAdapterPosition(view) == 0) {
            outRect.set(0, mLayout.getMeasuredHeight(), 0, 0);
        } else {
            outRect.setEmpty();
        }
    }
    

    }

    到目前为止,它的问题是,使用空列表,没有项目装饰器。我正在查看关于回收站视图的空视图,当我使用Firebase时,我会更新此信息。