How to tell RecyclerView to start at specific item position

前端 未结 6 2129
难免孤独
难免孤独 2021-02-20 10:43

I want my RecyclerView with LinearLayoutManager to show up with scroll position at specific item after adapter got updated. (not first/last position) Means the at first (re-)lay

6条回答
  •  粉色の甜心
    2021-02-20 11:36

    Another contribution to a long running question...

    As mentioned, layoutManager.scrollToPosition/WithOffset() does work to get the RecyclerView positioned, but timing this can be tricky. For example with variable length item views the RecyclerView has to work hard to get all the prior item views measured.

    The approach below simply delays telling the RecyclerView about the prior items, then calls notifyItemRangeInserted(0, offset). This enabled the view to appear in the right place, with no visible scrolling at the start, and ready to scroll back.

    private List bitmaps = new ArrayList<>();
    
    ...
    
    private class ViewAdapter extends RecyclerView.Adapter {
        private volatile int offset;
        private boolean offsetCancelled;
    
        ViewAdapter(int initialOffset) {
            this.offset = initialOffset;
            this.offsetCancelled = initialOffset > 0;
        }
    
        @Override
        public int getItemCount() {
            return bitmaps.size() - offset;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            ImageView imageView = new ImageView(MyActivity.this);  // Or getContext() from a Fragment
    
            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            imageView.setLayoutParams(lp);
    
            return new ViewHolder(imageView);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.imageView.setImageBitmap(bitmaps.get(position + offset));
    
            if (!offsetCancelled) {
                offsetCancelled = true;
                recyclerView.post(() -> {
                    int previousOffset = offset;
                    offset = 0;
                    notifyItemRangeInserted(0, previousOffset);
                    Log.i(TAG, "notifyItemRangeInserted(0, " + previousOffset + ")");
                });
            }
        }
    }
    
    private class ViewHolder extends RecyclerView.ViewHolder {
        private final ImageView imageView;
    
        ViewHolder(@NonNull ImageView itemView) {
            super(itemView);
            this.imageView = itemView;
        }
    }
    

    For context, this is a full example, based around ImageView's and Bitmap's. The key bit is the use of the offset in getItemCount() and onBindViewHolder().

提交回复
热议问题