Recyclerview,我无法使用getChildAt(position)获取项视图。空对象引用。

9
我正在导航抽屉中使用recyclerView,并使用这个库Twoway-view来获得单击和选择支持。
它完美地工作,我可以在每个位置的OnClick方法中更改文本和图标的颜色,没有任何问题。
itemClickSupport.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
        @Override
        public void onItemClick(RecyclerView parent, View view, int position, long id) {
            TypedValue typedValue = new TypedValue();
            MainActivity.this.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
            final int color = typedValue.data;

            //TODO Icon and text colors

            for (int i = 0; i < drawerTitles.length; i++){
                if (i == position){
                    ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.imageViewDrawerIcon);
                    TextView textViewDrawerTitle = (TextView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.textViewDrawerItemTitle);
                    imageViewDrawerIcon.setColorFilter(color);
                    if(Build.VERSION.SDK_INT > 15){
                        imageViewDrawerIcon.setImageAlpha(255);
                    }else{
                        imageViewDrawerIcon.setAlpha(255);
                    }
                    textViewDrawerTitle.setTextColor(color);
                    RelativeLayout relativeLayoutDrawerItem = (RelativeLayout) recyclerViewDrawer.getChildAt(i).findViewById(R.id.relativeLayoutDrawerItem);
                    relativeLayoutDrawerItem.setFocusableInTouchMode(true);
                }else{
                    ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.imageViewDrawerIcon);
                    TextView textViewDrawerTitle = (TextView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.textViewDrawerItemTitle);
                    imageViewDrawerIcon.setColorFilter(getResources().getColor(R.color.md_text));
                    if(Build.VERSION.SDK_INT > 15){
                        imageViewDrawerIcon.setImageAlpha(138);
                    }else{
                        imageViewDrawerIcon.setAlpha(138);
                    }
                    textViewDrawerTitle.setTextColor(getResources().getColor(R.color.md_text));
                    RelativeLayout relativeLayoutDrawerItem = (RelativeLayout) recyclerViewDrawer.getChildAt(i).findViewById(R.id.relativeLayoutDrawerItem);
                    relativeLayoutDrawerItem.setFocusableInTouchMode(false);
                }
            }

            //TODO Fragments (closedrawers before setfragment)
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // Do something after some time

                }
            }, 250);
            mDrawerLayout.closeDrawers();
        }
    });

问题在于我想像那个方法一样访问第一个项目,但是在它之前(设置第一个项目为选定状态,使用不同的颜色等),但是当我试图在OnClick方法之外获取第一个项目时,我会遇到崩溃(空引用):
ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(0).findViewById(R.id.imageViewDrawerIcon);

所有代码:

// Setup RecyclerView inside drawer
    recyclerViewDrawer = (RecyclerView) findViewById(R.id.recyclerViewDrawer);
    recyclerViewDrawer.setHasFixedSize(true);
    recyclerViewDrawer.setLayoutManager(new LinearLayoutManager(MainActivity.this));

    ArrayList<DrawerItem> drawerItems = new ArrayList<>();
    final String[] drawerTitles = getResources().getStringArray(R.array.drawer);
    final TypedArray drawerIcons = getResources().obtainTypedArray(R.array.drawerIcons);
    for (int i = 0; i < drawerTitles.length; i++) {
        drawerItems.add(new DrawerItem(drawerTitles[i], drawerIcons.getDrawable(i)));
    }
    drawerIcons.recycle();
    adapterDrawer = new DrawerAdapter(drawerItems);
    recyclerViewDrawer.setAdapter(adapterDrawer);

    // Here is the problem
    ImageView imageViewDrawerIcon2 = (ImageView) recyclerViewDrawer.getChildAt(0).findViewById(R.id.imageViewDrawerIcon);

    // RecyclerView item listener.
    ItemClickSupport itemClickSupport = ItemClickSupport.addTo(recyclerViewDrawer);
    itemClickSupport.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
        @Override
        public void onItemClick(RecyclerView parent, View view, int position, long id) {
            TypedValue typedValue = new TypedValue();
            MainActivity.this.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
            final int color = typedValue.data;

            //TODO Icon and text colors

            for (int i = 0; i < drawerTitles.length; i++){
                if (i == position){
                    ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.imageViewDrawerIcon);
                    TextView textViewDrawerTitle = (TextView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.textViewDrawerItemTitle);
                    imageViewDrawerIcon.setColorFilter(color);
                    if(Build.VERSION.SDK_INT > 15){
                        imageViewDrawerIcon.setImageAlpha(255);
                    }else{
                        imageViewDrawerIcon.setAlpha(255);
                    }
                    textViewDrawerTitle.setTextColor(color);
                    RelativeLayout relativeLayoutDrawerItem = (RelativeLayout) recyclerViewDrawer.getChildAt(i).findViewById(R.id.relativeLayoutDrawerItem);
                    relativeLayoutDrawerItem.setFocusableInTouchMode(true);
                }else{
                    ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.imageViewDrawerIcon);
                    TextView textViewDrawerTitle = (TextView) recyclerViewDrawer.getChildAt(i).findViewById(R.id.textViewDrawerItemTitle);
                    imageViewDrawerIcon.setColorFilter(getResources().getColor(R.color.md_text));
                    if(Build.VERSION.SDK_INT > 15){
                        imageViewDrawerIcon.setImageAlpha(138);
                    }else{
                        imageViewDrawerIcon.setAlpha(138);
                    }
                    textViewDrawerTitle.setTextColor(getResources().getColor(R.color.md_text));
                    RelativeLayout relativeLayoutDrawerItem = (RelativeLayout) recyclerViewDrawer.getChildAt(i).findViewById(R.id.relativeLayoutDrawerItem);
                    relativeLayoutDrawerItem.setFocusableInTouchMode(false);
                }
            }

            //TODO Fragments (closedrawers before setfragment)
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    // Do something after some time

                }
            }, 250);
            mDrawerLayout.closeDrawers();
        }
    });

1
可能是[RecyclerView - 获取特定位置的视图]的重复问题(https://dev59.com/oek6XIcBkEYKwwoYEPzw)。 - Kaibo
6个回答

20

在我的情况下,它像魔法一样工作。

View viewItem = recycleView.getLayoutManager().findViewByPosition(position);
    View icon = viewItem.findViewById(R.id.view);

发出警告:“在Android 4.1之前,方法int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean)将错误地覆盖android.widget.ListView中的包私有方法”。 - Patriotic
4
它返回 null - user25
似乎只有在当前项目可见时才有效,毫无用处。即使在调用findViewByPosition(position)之前调用layoutManager.scrollToPosition(position),它仍然不起作用。 - user25

9

我最终使用以下方法解决了问题 (来源):

recyclerViewDrawer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            ImageView imageViewDrawerIcon = (ImageView) recyclerViewDrawer.getChildAt(0).findViewById(R.id.imageViewDrawerIcon);
            TextView textViewDrawerTitle = (TextView) recyclerViewDrawer.getChildAt(0).findViewById(R.id.textViewDrawerItemTitle);
            imageViewDrawerIcon.setColorFilter(color);
            if (Build.VERSION.SDK_INT > 15) {
                imageViewDrawerIcon.setImageAlpha(255);
            } else {
                imageViewDrawerIcon.setAlpha(255);
            }
            textViewDrawerTitle.setTextColor(color);
            RelativeLayout relativeLayoutDrawerItem = (RelativeLayout) recyclerViewDrawer.getChildAt(0).findViewById(R.id.relativeLayoutDrawerItem);
            relativeLayoutDrawerItem.setFocusableInTouchMode(true);
            // unregister listener (this is important)
            recyclerViewDrawer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    });

顺便说一句,如果有更好的解决方案,我想知道。


我们仍然会在这种方法中遇到一些getChildView(0)为空的情况。我个人无法重现它。使用setAdapter触发子视图膨胀,因此最好有一个回调函数,在子视图被膨胀并添加到RecyclerView时调用。 - ono

8
这对我很有效。
recyclerView.post(new Runnable() {
  @Override
  public void run() {
    View viewItem = recycleView.getLayoutManager().findViewByPosition(position);
    View icon = viewItem.findViewById(R.id.view);
  }
});

很好,使用getChildAt()getChildViewHolder()完美地获取了显示的子项和视图持有者。 - Peterdk
需要注意的是,由于您正在从不同的线程中工作,因此无法使用此方法操纵许多UI元素。您将需要设置跨线程通信。 - Kilves

5

1

findViewByPositionLayoutManager 的一个方法,适用于所有 LayoutManagers。

因此,您可以使用 recycleView.getLayoutManager()findViewByPosition(pos)

另外,recyclerView.findViewHolderForAdapterPosition(pos) 也可以使用。

欲了解更多信息,请查看 RecyclerView - 获取特定位置的视图


0
你可以使用以下代码从recyclerView的holder中获取ItemView:
val holder = yourRecyclerView.findViewHolderForAdapterPosition(position)
if (holder != null) {
  val rootView = holder.itemView
  //do your code here
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接