在Recycler View中扩展/折叠卡有时会导致空白和绘制错误

时间:2017-04-07 06:33:59

标签: java android xml view android-recyclerview

问题

我有卡片项目的回收者视图。这些卡片商品仅包含文字且可展开。看起来像Collapsed Expanded

现在我有时会展开并折叠其中一个并滚动,不知何时卡片之间会出现更多的空白: Whitespace between cards

此外,对于单击以折叠它们的长文本卡片,会出现: Big Cards

守则

xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.ramotion.foldingcell.FoldingCell
        android:id="@+id/folding_cell"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        app:backSideColor="#F5F5F5">

        <FrameLayout
            android:id="@+id/cell_content_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="300dp"
            android:visibility="gone">

            <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:cardview="http://schemas.android.com/apk/res-auto"
                xmlns:custom="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/movie_card2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="true"
                android:foreground="?attr/selectableItemBackground"
                android:minHeight="300dp"
                cardview:cardBackgroundColor="@color/card_background"
                cardview:cardCornerRadius="1dp"
                cardview:cardElevation="4dp"
                cardview:cardUseCompatPadding="true">

                <RelativeLayout
                    android:id="@+id/review_item2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:clickable="true"
                    android:orientation="vertical">

                    <View
                        android:id="@+id/review_detail_header"
                        android:layout_width="match_parent"
                        android:layout_height="50dp"
                        android:background="@color/material_red_400" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignBottom="@id/review_detail_header"
                        android:layout_alignTop="@id/review_detail_header"
                        android:layout_centerHorizontal="true"
                        android:gravity="center"
                        android:text="Review Details"
                        android:textColor="@color/text_secondary" />

                    <ImageView
                        android:id="@+id/ic"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@id/review_detail_header"
                        android:layout_marginTop="@dimen/material_layout_keylines_horizontal_margin"
                        android:adjustViewBounds="true"
                        android:paddingLeft="@dimen/material_layout_keylines_horizontal_margin"
                        android:paddingRight="@dimen/material_layout_keylines_horizontal_margin"
                        android:src="@drawable/ic_account_circle_white_24dp"
                        android:tint="@color/accent"
                        tools:ignore="ContentDescription" />

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_author2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@id/review_detail_header"
                        android:layout_gravity="center_vertical"
                        android:layout_marginTop="@dimen/material_layout_keylines_horizontal_margin"
                        android:layout_toRightOf="@id/ic"
                        android:textSize="14sp"
                        custom:robotoType="bold"
                        tools:text="User Name" />

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_body2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/review_author2"
                        android:layout_marginBottom="@dimen/material_layout_keylines_horizontal_margin"
                        android:layout_marginLeft="56dp"
                        android:layout_marginRight="24dp"
                        android:layout_marginTop="@dimen/material_layout_vertical_spacing_between_content_areas"
                        android:layout_weight="1"
                        android:ellipsize="none"
                        android:maxLines="100"
                        android:scrollHorizontally="false"
                        android:textSize="14sp"
                        custom:robotoType="regular"
                        tools:text="The movie's review goes here..." />

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_spoiler2"
                        style="@style/ReviewBodyStyle"
                        android:text="@string/reviews_alert"
                        android:textColor="@color/primary"
                        android:visibility="gone"
                        custom:robotoType="bold" />


                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_time2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentRight="true"
                        android:layout_below="@+id/review_body2"
                        android:layout_margin="@dimen/material_layout_keylines_horizontal_margin"
                        android:textSize="@dimen/material_layout_keylines_horizontal_margin"
                        android:visibility="gone"
                        custom:robotoType="regular"
                        tools:text="01 Jan 2016" />

                </RelativeLayout>

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

        </FrameLayout>
        ​

        <FrameLayout
            android:id="@+id/cell_title_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:cardview="http://schemas.android.com/apk/res-auto"
                xmlns:custom="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/movie_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="true"
                android:foreground="?attr/selectableItemBackground"
                cardview:cardBackgroundColor="@color/card_background"
                cardview:cardCornerRadius="1dp"
                cardview:cardElevation="4dp"
                cardview:cardUseCompatPadding="true">

                <RelativeLayout
                    android:id="@+id/review_item"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="?attr/selectableItemBackground"
                    android:clickable="true"
                    android:orientation="vertical"
                    android:padding="@dimen/material_layout_keylines_horizontal_margin">


                    <ImageView
                        android:id="@+id/ic2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentLeft="true"
                        android:layout_alignParentStart="true"
                        android:adjustViewBounds="true"
                        android:src="@drawable/ic_account_circle_white_24dp"
                        android:tint="@color/accent"
                        tools:ignore="ContentDescription" />

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_author"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/material_layout_keylines_horizontal_margin"
                        android:layout_toRightOf="@+id/ic2"
                        custom:robotoType="bold"
                        android:textSize="14sp"
                        tools:text="User Name" />

                    <!-- Review open icon -->
                    <ImageView
                        android:id="@+id/review_open"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentRight="true"
                        android:adjustViewBounds="true"
                        android:src="@drawable/ic_open_in_new_white_24dp"
                        android:tint="@color/accent"
                        tools:ignore="contentDescription" />

                    <!-- Review Body -->

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_body"
                        style="@style/ReviewBodyStyle"
                        android:layout_marginLeft="40dp"
                        android:layout_marginRight="8dp"
                        android:layout_below="@+id/review_spoiler"
                        custom:robotoType="regular"
                        tools:text="The movie's review goes here..." />

                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_spoiler"
                        style="@style/ReviewBodyStyle"
                        android:layout_below="@id/review_open"
                        android:text="@string/reviews_alert"
                        android:textColor="@color/primary"
                        android:layout_marginLeft="40dp"
                        android:layout_marginRight="8dp"
                        android:visibility="gone"
                        custom:robotoType="bold" />


                    <com.mt.moviesiwanttowatch.ui.widget.TextViewRoboto
                        android:id="@+id/review_time"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentRight="true"
                        android:layout_below="@+id/review_body"
                        android:layout_margin="@dimen/material_layout_keylines_horizontal_margin"
                        android:textSize="@dimen/material_layout_keylines_horizontal_margin"
                        android:visibility="gone"
                        custom:robotoType="regular"
                        tools:text="01 Jan 2016" />

                </RelativeLayout>

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

        </FrameLayout>
    </com.ramotion.foldingcell.FoldingCell>
</layout>

适配器:

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

    public ArrayList<Review> reviewList;
    public int foldingCellPosition = -1;
    public FoldingCell currentFoldingCell;
    // Constructor
    public ReviewAdapter(ArrayList<Review> reviewList) {
        this.reviewList = reviewList;
    }

    // RecyclerView methods
    @Override
    public int getItemCount() {
        return reviewList.size();
    }

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

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        Review review = reviewList.get(position);
        ReviewViewHolder holder = (ReviewViewHolder) viewHolder;
        if (position == foldingCellPosition) {
            holder.binding.foldingCell.unfold(true);
            holder.binding.reviewBody2.setText(review.getComment());
            holder.binding.reviewAuthor2.setText(review.getUsername());
            return;
        }


        holder.binding.foldingCell.fold(true);
        holder.binding.reviewAuthor.setText(review.getUsername());
        if (review.isHasSpoiler()) {
            holder.binding.reviewBody.setVisibility(View.GONE);
            holder.binding.reviewSpoiler.setVisibility(View.VISIBLE);
        } else {
            holder.binding.reviewBody.setText(review.getComment());
            holder.binding.reviewBody.setVisibility(View.VISIBLE);
            holder.binding.reviewSpoiler.setVisibility(View.GONE);
        }
        holder.binding.reviewTime.setText(review.getCreatedAt());
    }

    // ViewHolder
    public class ReviewViewHolder extends RecyclerView.ViewHolder {
        ItemListReviewBinding binding;

        public ReviewViewHolder(final ViewGroup itemView) {
            super(itemView);
            binding = DataBindingUtil.bind(itemView);

            binding.reviewItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //       onReviewClickListener.onReviewClicked(getAdapterPosition());
                    Log.e("TEST", "CLIKC");

                    if (foldingCellPosition != -1) {
                        currentFoldingCell.fold(false);
                    }
                    currentFoldingCell = binding.foldingCell;
                    binding.reviewBody2.setText(reviewList.get(getAdapterPosition()).getComment());
                    binding.reviewAuthor2.setText(reviewList.get(getAdapterPosition()).getUsername());
                    binding.foldingCell.toggle(false);
                    foldingCellPosition = getAdapterPosition();

                }
            });

            binding.reviewItem2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    binding.reviewItem2.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            foldingCellPosition = -1;
                            binding.foldingCell.fold(false);
                        }
                    });
                }
            });


        }
    }
}

如何创建回收者视图:

  layoutManager = new LinearLayoutManager(getContext());
     mBinding.movieDetailReviewListRvReviews.setHasFixedSize(true);
     mBinding.movieDetailReviewListRvReviews.setLayoutManager(layoutManager);
     mBinding.movieDetailReviewListRvReviews.setAdapter(adapter); 

到目前为止我尝试了什么

我真的不知道为什么会这样。 但是我在每次折叠/展开之后尝试了notifyDataSetChanged()以及invalidate()。

修改

对于折叠/展开效果,我使用此库:https://github.com/Juriv/folding-cell-android

2 个答案:

答案 0 :(得分:1)

实际上我的代码存在很多问题。首先,正如rom4ek所提到的,我必须将foldingCellPosition = getAdapterPosition()更改为foldingCellPosition = getLayoutPosition()。下一个问题是这个电话:

if(foldingCellPosition != -1) {
     currentFoldingCell.fold(false);
}

不可见的视图应该折叠,这会导致奇怪的行为,所以我添加了这段代码:

  public void checkForHide(int first, int last){
        if(foldingCellPosition != -1){
            if(foldingCellPosition < first || foldingCellPosition > last){
                foldingCellPosition = -1;
            }
        }
    }

如果展开的视图不可见,折叠的cellposition将设置为-1而不是手动折叠。

从片段中调用它:

  mBinding.movieDetailReviewListRvReviews.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                // Load more data if reached the end of the list
                adapter.checkForHide(layoutManager.findFirstVisibleItemPosition(), layoutManager.findLastVisibleItemPosition());

                if (layoutManager.findLastVisibleItemPosition() == adapter.reviewList.size() - 1 && !isLoadingLocked && !isLoading) {
                    if (pageToDownload < totalPages) {
                        mBinding.layoutContent.pbLoadingMore.setVisibility(View.VISIBLE);
                        downloadMovieReviews();
                    }
                }
            }
        });

答案 1 :(得分:0)

尝试离开cardview:cardUseCompatPadding false,这是默认值。

来自https://developer.android.com/reference/android/support/v7/widget/CardView.html#setUseCompatPadding(boolean)

  

setUseCompatPadding

     

在版本24.2.0中添加了void setUseCompatPadding(boolean   useCompatPadding)CardView添加额外的填充以绘制阴影   Lollipop之前的平台。

     

这可能导致卡片在棒棒糖和棒棒糖之间有不同的大小   在棒棒糖之前。如果您需要将CardView与其他视图对齐,那么您   可能需要api版本特定维度资源来考虑   变化。作为替代方案,您可以将此标志设置为true和CardView   将在Lollipop平台及之后添加相同的填充值。

     

由于将此标志设置为true会在UI中添加不必要的间隙,   默认值为false。

这意味着当您折叠/展开卡片时,CardView可能会添加填充。