Android 从RecyclerView获取可见和不可见项目

Android 从RecyclerView获取可见和不可见项目,android,android-recyclerview,Android,Android Recyclerview,下面这个简单的代码只获取所有可见项,但我需要获取所有项(可见项和不可见项) 这是否可能完全获得所有项目?如何获得 // This gets only visible items final RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(index); // Same as this final View child = recyclerView.getChildAt(index);

下面这个简单的代码只获取所有可见项,但我需要获取所有项(可见项和不可见项)

这是否可能完全获得所有项目?如何获得

// This gets only visible items
final RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(index);

// Same as this
final View child = recyclerView.getChildAt(index);
final RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(child);

我也对这方面的任何工作感兴趣。如果可能的话。

我相信这个问题是第一次被问到的

在第一个视图中,正如波厄尔指出的那样,你似乎要求的是不可能的,因为除非感兴趣的视图实际上是可见的,否则相应的视图持有者可能存在,也可能不存在,而且显然没有本机方法来强制其创建

我的要求是远程确定数据集中任何项目的可见性和突出显示

实现这一点的策略是通过滚动到所需项目,然后通过回调返回新创建的ViewHolder,从而强制创建ViewHolder

这个解决方案很重要,但我相信代码已经有了很好的文档。我建议您将静态方法和接口复制到一个实用程序类中,并按照dummy exampleOfUse()方法部署它们。如果您不能按原样使用它们,请告诉我

我已经包括了2个滚动相关的完整性只方法。忽略我的记录器:lg()

请记住,预滚动到所需的项目是您获得ViewHolder所付出的代价,因此可以发出notifyItemChanged()。[适合我,但可能不是所有人。]

// ---------------------------------------------------------------------------------------------
//  These 3 static methods provide:
//      (A) Smooth or direct scrolling for any RecyclerView. [ ScrollTo() ]
//      (B) A technique for obtaining the ViewHolder of any item (visible or otherwise).
//          [ Achieved via callback when scroll to desired position has completed. ]
//          [ Why: (e.g.) To highlight an externally selected (or any) RecyclerView item ]
// ---------------------------------------------------------------------------------------------

/** Sample method of use */
public void dummyExampleOfUse(RecyclerView rv, int pos) {
    getAnyViewHolder(rv, pos, true, new GetAnyViewHolder() {
        @Override
        public void scrollForViewHolder(RecyclerView.ViewHolder vh, int pos) {
            if (vh==null) lg("Failed!!!");      // <-- Your logger
            //else ((YourViewHolder)vh).yourViewHolderMethod(pos);
            // yourViewHolderMethod would typically issue notifyItemChanged(pos);
        }
    });
}

/** Interface to receive requested ViewHolder */
public interface GetAnyViewHolder {
    void scrollForViewHolder(RecyclerView.ViewHolder vh, int pos);
}

/** RecyclerView scroll with callback returning desired ViewHolder */
public static boolean getAnyViewHolder(RecyclerView rv, int pos, boolean smooth, GetAnyViewHolder cb) {
    if (rv==null) return false;
    if (rv.getAdapter() == null) return false;
    if (rv.getAdapter().getItemCount() < 1) return false;
    if (pos <0 || pos > rv.getAdapter().getItemCount()-1) return false;
    rv.addOnScrollListener(new MPA_SL(rv, cb, pos));
    scrollTo(rv, pos, smooth, null);       // Note user-specified scroll action!
    return true;
}

/** Custom Scroll listener needed for 'getAnyViewHolder()' */
private static class MPA_SL extends RecyclerView.OnScrollListener {
    RecyclerView rv; GetAnyViewHolder gavh; int pos;
    MPA_SL( RecyclerView rv,GetAnyViewHolder gavh, int pos ) {  // Constructor
        this.rv = rv; this.gavh = gavh; this.pos = pos;}
    @Override public void onScrollStateChanged(@NonNull RecyclerView rv, int newState) {
        super.onScrollStateChanged(rv, newState);
        lg(format("Scroll state: %d", newState));
        if(newState == RecyclerView.SCROLL_STATE_IDLE) {
            RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(pos);
            gavh.scrollForViewHolder(vh, pos);      // Notify user
            rv.removeOnScrollListener(this);        // Self-destruct
        }
    }
}

/** Scroll according to speed */
public static void scrollTo(RecyclerView rv, int os, boolean smooth, TextView tv) {
    try {
        if (smooth) { smoothScroll(rv, os); }
        else { rv.scrollToPosition(os); }
    } catch ( IllegalArgumentException ile) {
        if (tv==null) {
            lg(format("Scroll error: %s", ile.getMessage()));
            return;
        }
        String msg = tv.getText().toString() + " ";
        msg += ile.getMessage();
        tv.setText(msg);
    }
}

/** Smoothly scroll to specified position at 1/4 speed */
private static void smoothScroll(RecyclerView rv, int position) throws IllegalArgumentException {
    RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(gc()) {
        @Override protected int getVerticalSnapPreference() {
            return LinearSmoothScroller.SNAP_TO_START;
        }
        @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            float millesecondsPerPixel = super.calculateSpeedPerPixel(displayMetrics);
            return millesecondsPerPixel * 4;
        }
    };
    smoothScroller.setTargetPosition(position);
    rv.getLayoutManager().startSmoothScroll(smoothScroller);
}
//---------------------------------------------------------------------------------------------
//这3种静态方法提供:
//(A)平滑或直接滚动任何RecyclerView。[滚动到()]
//(B)获取任何项目(可见或其他)的视图持有人的技术。
//[当滚动到所需位置完成时,通过回调实现。]
//[原因:(例如)突出显示外部选择的(或任何)RecyclerView项目]
// ---------------------------------------------------------------------------------------------
/**使用方法样本*/
公共空间DummeyExampleofuse(回收视图rv,内部位置){
getAnyViewHolder(rv、pos、true、新getAnyViewHolder(){
@凌驾
公共无效scrollForViewHolder(RecyclerView.ViewHolder vh,int pos){

如果(vh==null)lg(“失败!!!”;//我相信这个问题是第一个被问到的

在第一个视图中,正如波厄尔指出的那样,你似乎要求的是不可能的,因为除非感兴趣的视图实际上是可见的,否则相应的视图持有者可能存在,也可能不存在,而且显然没有本机方法来强制其创建

我的要求是远程确定数据集中任何项目的可见性和突出显示

实现这一点的策略是通过滚动到所需项目,然后通过回调返回新创建的ViewHolder,从而强制创建ViewHolder

这个解决方案非常简单,但我相信代码已经有很好的文档记录。我建议您将静态方法和接口复制到实用程序类中,并按照伪exampleOfUse()方法进行部署。如果您不能按原样使用它们,请告诉我

为了完整起见,我加入了2个与滚动相关的方法。忽略我的记录器:lg()

请记住,预滚动到所需的项目是您获得ViewHolder所付出的代价-因此,发布notifyItemChanged()[适合我,但可能不是所有人。]

// ---------------------------------------------------------------------------------------------
//  These 3 static methods provide:
//      (A) Smooth or direct scrolling for any RecyclerView. [ ScrollTo() ]
//      (B) A technique for obtaining the ViewHolder of any item (visible or otherwise).
//          [ Achieved via callback when scroll to desired position has completed. ]
//          [ Why: (e.g.) To highlight an externally selected (or any) RecyclerView item ]
// ---------------------------------------------------------------------------------------------

/** Sample method of use */
public void dummyExampleOfUse(RecyclerView rv, int pos) {
    getAnyViewHolder(rv, pos, true, new GetAnyViewHolder() {
        @Override
        public void scrollForViewHolder(RecyclerView.ViewHolder vh, int pos) {
            if (vh==null) lg("Failed!!!");      // <-- Your logger
            //else ((YourViewHolder)vh).yourViewHolderMethod(pos);
            // yourViewHolderMethod would typically issue notifyItemChanged(pos);
        }
    });
}

/** Interface to receive requested ViewHolder */
public interface GetAnyViewHolder {
    void scrollForViewHolder(RecyclerView.ViewHolder vh, int pos);
}

/** RecyclerView scroll with callback returning desired ViewHolder */
public static boolean getAnyViewHolder(RecyclerView rv, int pos, boolean smooth, GetAnyViewHolder cb) {
    if (rv==null) return false;
    if (rv.getAdapter() == null) return false;
    if (rv.getAdapter().getItemCount() < 1) return false;
    if (pos <0 || pos > rv.getAdapter().getItemCount()-1) return false;
    rv.addOnScrollListener(new MPA_SL(rv, cb, pos));
    scrollTo(rv, pos, smooth, null);       // Note user-specified scroll action!
    return true;
}

/** Custom Scroll listener needed for 'getAnyViewHolder()' */
private static class MPA_SL extends RecyclerView.OnScrollListener {
    RecyclerView rv; GetAnyViewHolder gavh; int pos;
    MPA_SL( RecyclerView rv,GetAnyViewHolder gavh, int pos ) {  // Constructor
        this.rv = rv; this.gavh = gavh; this.pos = pos;}
    @Override public void onScrollStateChanged(@NonNull RecyclerView rv, int newState) {
        super.onScrollStateChanged(rv, newState);
        lg(format("Scroll state: %d", newState));
        if(newState == RecyclerView.SCROLL_STATE_IDLE) {
            RecyclerView.ViewHolder vh = rv.findViewHolderForAdapterPosition(pos);
            gavh.scrollForViewHolder(vh, pos);      // Notify user
            rv.removeOnScrollListener(this);        // Self-destruct
        }
    }
}

/** Scroll according to speed */
public static void scrollTo(RecyclerView rv, int os, boolean smooth, TextView tv) {
    try {
        if (smooth) { smoothScroll(rv, os); }
        else { rv.scrollToPosition(os); }
    } catch ( IllegalArgumentException ile) {
        if (tv==null) {
            lg(format("Scroll error: %s", ile.getMessage()));
            return;
        }
        String msg = tv.getText().toString() + " ";
        msg += ile.getMessage();
        tv.setText(msg);
    }
}

/** Smoothly scroll to specified position at 1/4 speed */
private static void smoothScroll(RecyclerView rv, int position) throws IllegalArgumentException {
    RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(gc()) {
        @Override protected int getVerticalSnapPreference() {
            return LinearSmoothScroller.SNAP_TO_START;
        }
        @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            float millesecondsPerPixel = super.calculateSpeedPerPixel(displayMetrics);
            return millesecondsPerPixel * 4;
        }
    };
    smoothScroller.setTargetPosition(position);
    rv.getLayoutManager().startSmoothScroll(smoothScroller);
}
//---------------------------------------------------------------------------------------------
//这3种静态方法提供:
//(A)平滑或直接滚动任何RecyclerView。[ScrollTo()]
//(B)获取任何项目(可见或其他)的视图持有人的技术。
//[当滚动到所需位置完成时,通过回调实现。]
//[原因:(例如)突出显示外部选择的(或任何)RecyclerView项目]
// ---------------------------------------------------------------------------------------------
/**使用方法样本*/
公共空间DummeyExampleofuse(回收视图rv,内部位置){
getAnyViewHolder(rv、pos、true、新getAnyViewHolder(){
@凌驾
公共无效scrollForViewHolder(RecyclerView.ViewHolder vh,int pos){

如果(vh==null)lg(“失败!!!”);//您是否知道
RecyclerView
在滚动时重用
ViewHolder
s?即使您的列表中有5000多个项目,也只有足够的
ViewHolder
s来容纳您的查看端口。您是否知道
RecyclerView
在滚动时重用
ViewHolder
s?即使您的列表中有5000多个项目,也会有只有足够的
ViewHolder
s适合您的视图端口。