【问题标题】:Firebase ui - set header view for FirebaseRecyclerView in androidFirebase ui - 在 android 中为 FirebaseRecyclerView 设置标题视图
【发布时间】:2017-03-29 09:49:06
【问题描述】:

我需要在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 问题,但即使在解决此问题后也可能无法正常工作。

【问题讨论】:

    标签: android firebase firebase-realtime-database firebaseui


    【解决方案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);
            }
        };
    

    【讨论】:

    • 所以解决方案的问题是,每次 Firebase 触发项目更改或插入通知时,它都会被定向到前一个项目意味着更改应该针对 4,它带有转到项目 5,然后目前还没有办法避免这种情况
    【解决方案2】:

    更新(2016 年 12 月 6 日):如果您需要检查一个空的 FirebaseRecyclerView,这有点麻烦,但到目前为止,这是我知道的唯一方法。 所以总结一下,你需要处理两种情况。

    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) {
      
           }
      

      });

    所以一旦列表中有东西,我们就拿走那个空视图,并显示项目装饰器,它会随着回收器视图的滚动而移动。

    **原始帖子**

    我最近遇到了同样的困境。我使用了一个正常的 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 时我会更新它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-01
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 1970-01-01
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多