首页 > 解决方案 > 具有网格布局的回收器视图/项目未显示,而 LayoutManager 具有高度和宽度,并且 getItemCount 返回正确的项目数

问题描述

我在协调器布局中有一个回收器视图,其中一个 GridLayoutManager 设置为垂直和一个自定义适配器。

当布局使用onLayoutChangeListener更改时,列数可以自行调整。

Recycler View 的 Adapter 数据是异步加载的,每次更改时,我都会调用 recyclerview.getAdapter() .notifyDataSetChanged()以确保 Recycler View 显示它。

我在 Android Lollipop 或更多设备上运行应用程序,并且 build.gradle 具有支持库的此实现:

implementation 'com.android.support:recyclerview-v7:27.0.2'

出于某种原因,似乎数据已正确加载,并且根据加载的数据布局高度和宽度是正确的,但网格内的卡片不可见,这是回收站视图边界的屏幕截图以证明我的观点:

当插入的数据发生变化但项目不可见时,回收站视图的高度会发生变化
当插入的数据发生变化但项目不可见时,回收站视图的高度会发生变化

这是包含回收器视图的活动的代码:

public class SessionChildrenActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    public static ArrayList<SessionChild> ChildrenList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_session_children);

        ChildrenList = new ArrayList<>();

        recyclerView = findViewById(R.id.children_gridview);
        recyclerView.setAdapter(new ChildrenAdapter());

        final Context c = this;

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        GridLayoutManager layoutManager = new GridLayoutManager(c,(int)(displayMetrics.widthPixels / (getResources().getDimension(R.dimen.cell_width))),GridLayoutManager.VERTICAL,true);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                recyclerView.setLayoutManager(new GridLayoutManager(c,(int)(displayMetrics.widthPixels / (getResources().getDimension(R.dimen.cell_width))),GridLayoutManager.VERTICAL,true));
            }
        });
        //Start of a query (Google Firestore) that gets the children associated with the session, just showing you the part that adds the retrieved child to the list given to the adapter
        ...
        if(ChildrenList.indexOf(child) == -1){
            ChildrenList.add(child);
            Collections.sort(ChildrenList,new Comparator<SessionChild>() {
                @Override
                public int compare(SessionChild sc1, SessionChild sc2)
                {
                    return sc1.getChild().getNickname().compareTo(sc2.getChild().getNickname());
                }
            });
            recyclerView.getAdapter().notifyDataSetChanged();
        }
        ...
    }
}

这是自定义适配器的代码:

public class ChildrenAdapter  extends RecyclerView.Adapter<ChildrenAdapter.ViewHolder> {


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.session_child, parent, false);
        return new ViewHolder(v);
    }

    public ChildrenAdapter() {
        super();
    }

    @Override
    public void onBindViewHolder(ViewHolder mViewHolder, int position) {
        mViewHolder.firstname.setText(SessionChildrenActivity.ChildrenList.get(position).getChild().getNickname());
        Calendar birthdate = Calendar.getInstance();
        if(SessionChildrenActivity.ChildrenList.get(position).getChild().getPersonalInfo().getBirthdate() != null){
            birthdate.setTime(SessionChildrenActivity.ChildrenList.get(position).getChild().getPersonalInfo().getBirthdate());
            mViewHolder.age.setText(getAge(birthdate));
        }
        else
            mViewHolder.age.setText("?");
        if(SessionChildrenActivity.ChildrenList.get(position).getChild().getPhotoURL() != null && !SessionChildrenActivity.ChildrenList.get(position).getChild().getPhotoURL().equals("") && mViewHolder.image.getDrawingCache() == null) {
            new DownloadImageTask(mViewHolder.image).execute(SessionChildrenActivity.ChildrenList.get(position).getChild().getPhotoURL());
        }
    }

    @Override
    public int getItemCount() {
        return SessionChildrenActivity.ChildrenList.size();
    }

    @Override
    public long getItemId(int position) {
        return (long) position;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private TextView firstname;
        private ImageView image;
        private TextView age;
        private ConstraintLayout card;

        public ViewHolder(View v) {
            super(v);
            firstname = v.findViewById(R.id.firstname);
            age = v.findViewById(R.id.age);
            image = v.findViewById(R.id.thumb_img);
            card = v.findViewById(R.id.cardview);
            card.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(v.getContext(),child_details.class);
                    SessionChild sessionChild = SessionChildrenActivity.ChildrenList.get(((ViewGroup)v.getParent()).indexOfChild(v));
                    intent.putExtra("session_child",sessionChild);
                    v.getContext().startActivity(intent);
                }
            });
        }
    }

    private String getAge(Calendar dob){
        Calendar today = Calendar.getInstance();

        int age = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);

        if (today.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)){
            age--;
        }
        return String.valueOf(age);
    }

    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTask(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {
            String urldisplay = urls[0];
            Bitmap mIcon11 = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon11 = BitmapFactory.decodeStream(in);
            } catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }
            return mIcon11;
        }

        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }

    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }
}

这是膨胀的 ViewHolders 的 xml 文件和它在 Android Studio 中的截图:

由适配器膨胀的项目布局
由适配器膨胀的项目布局

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/card"
    android:foreground="?attr/selectableItemBackground">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="4dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/age"
            style="@android:style/TextAppearance.Material.Medium"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:paddingEnd="8dp"
            android:paddingStart="4dp"
            android:text="@string/whatever"
            android:textColor="@android:color/white"
            app:layout_constraintBottom_toBottomOf="@+id/thumb_img"
            app:layout_constraintEnd_toEndOf="parent" />

        <TextView
            android:id="@+id/firstname"
            style="@android:style/TextAppearance.Material.Medium"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:paddingEnd="4dp"
            android:paddingStart="8dp"
            android:text="@string/note"
            android:textColor="@android:color/white"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@+id/thumb_img"
            app:layout_constraintEnd_toStartOf="@+id/age"
            app:layout_constraintStart_toStartOf="parent" />

        <com.makeramen.roundedimageview.RoundedImageView
            android:id="@+id/thumb_img"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:contentDescription="@string/whatever"
            android:scaleType="centerCrop"
            app:layout_constraintDimensionRatio="H,1:1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:riv_corner_radius="8dp"
            app:riv_oval="false" />

        <ImageView
            android:id="@+id/delete_confirm"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginEnd="2dp"
            android:layout_marginTop="2dp"
            android:contentDescription="@string/whatever"
            android:visibility="invisible"
            app:layout_constraintBottom_toBottomOf="@+id/guideline10"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="@+id/guideline"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/fui_done_check_mark" />

        <ImageView
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:contentDescription="@string/whatever"
            android:src="@drawable/card_bottom"
            app:layout_constraintBottom_toBottomOf="@+id/thumb_img"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/firstname">

        </ImageView>

        <android.support.constraint.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.8" />

        <android.support.constraint.Guideline
            android:id="@+id/guideline10"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.2" />

    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>

最后,这是回收站视图 xml 的代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/children_gridview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:nestedScrollingEnabled="false">

    </android.support.v7.widget.RecyclerView>

</RelativeLayout>

我在任何地方都没有看到任何报告此错误的问题,所以如果您知道它可能来自哪里,那将非常感激。抱歉,这篇文章很长,我试图尽可能多地删除不必要的代码。希望有人能帮助我!

标签: androidandroid-layoutandroid-recyclerviewgridlayoutmanager

解决方案


使用addOnGlobalLayoutListener而不是addOnLayoutChangeListener.


推荐阅读