使用 GridLayoutManager 增加 RecyclerView 中的单元格宽度

Increase cell width in a RecyclerView with GridLayoutManager

我有一个 RecyclerView,一个 GridLayoutManager,一个 spanCount=2,一个 Vertical 方向。

我的物品正确显示如下图:

现在我需要添加一个动画,当点击其中一个项目时,比方说数字“3”,该项目会增加它的宽度并推动它旁边的项目(在这个例子中,数字“4” ) 部分在 parent/screen.

之外

视觉上应该是这样的:

要将我将可见性设置为 VISIBLE 的项目展开到项目内部的视图并折叠它,请将可见性设置为 GONE

目前,我可以显示和隐藏该视图,但它只占用项目的 space,它确实增加了推动旁边项目的宽度。

所以我的问题是:

我看到了如何使用 HorizontalScrollView/RecyclerView 和 LinearLayoutManager 来实现它。您可以将 LinearLayoutManager 与此类视图一起使用,而不是将 GridLayoutManager 与两列一起使用:

__|HorizontalScrollView/RecyclerView| | [Firts view] [Second view] | |---------------------------------|

那么实现扩展视图就很简单了。

在其他情况下,您需要自定义布局管理器,它可以水平和垂直滚动。

可以使用GridLayoutManager如下:

  • 用两个跨度定义 GridLayoutManager
  • 设置一个包含可点击视图和将设置为 VISIBLEGONE 的视图的项目布局。
  • 在适配器中,例如,当单击左视图时,将可展开视图设置为 VISIBLE,将 itemView 的大小增加可展开视图的宽度。将视图向右平移扩展量以适应左视图增加的尺寸。
  • 做一些内务处理以确保重置回收视图。

这是一个例子。我假设只能点击左视图。右边view if if if if if 也可以点击,大体流程是一样的,只是需要翻译的内容等细节有所区别

此示例不保留展开时涉及的视图状态信息,因此如果展开视图然后向下滚动并返回,视图可能会被重置。

MainActivity.java

public class MainActivity extends AppCompatActivity {  
    private LinearLayoutManager mLayoutManager;  
    private RecyclerViewAdapter mAdapter;  
    private List<String> mItems = new ArrayList<>();  
    private RecyclerView mRecycler;  

    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        for (int i = 0; i < 100; i++) {  
            mItems.add(i + 1 + "");  
        }  

        mLayoutManager = new GridLayoutManager(this, 2);  
        mRecycler = findViewById(R.id.recyclerView);  
        mAdapter = new RecyclerViewAdapter(mItems);  
        mRecycler.setLayoutManager(mLayoutManager);  
        mRecycler.setAdapter(mAdapter);  
    }  
}

RecyclerViewAdapter.java
此演示适配器假定要显示的项目数量为偶数。为简单起见,未对空检查进行编码。

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
    implements View.OnClickListener {
    private final List<String> mItems;
    private RecyclerView mRecyclerView;

    RecyclerViewAdapter(List<String> items) {
        mItems = items;
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    @Override
    public @NonNull
    RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        ItemViewHolder vh = (ItemViewHolder) holder;

        vh.mItemTextView.setText(mItems.get(position));

        // Only allow clicks on left items which corresponds to even positions.
        vh.mItemTextView.setOnClickListener((position % 2 == 0) ? this : null);

        // Reset translation and expansion if viewholder is reused.
        vh.itemView.setTranslationX(0);
        if (vh.mExpansion != 0) {
            vh.itemView.getLayoutParams().width -= vh.mExpansion;
            vh.mExpansion = 0;
            vh.mGoneView.setVisibility(View.GONE);
        }

        int bgColor = (position % 2 == 0)
            ? android.R.color.holo_blue_light
            : android.R.color.holo_green_light;
        vh.mItemTextView.setBackgroundColor(vh.itemView.getContext().getResources().getColor(bgColor));
    }

    @Override
    public int getItemCount() {
        return (mItems == null) ? 0 : mItems.size();
    }

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

    @Override
    public void onClick(View v) {
        ItemViewHolder vh = (ItemViewHolder) mRecyclerView.findContainingViewHolder(v);
        View itemView = vh.itemView;

        // Get the child to the right. This child will be translated to the right to make room
        // for the expanded left view.
        View rightChild = mRecyclerView.getChildAt(findRightChildPos(vh.itemView));
        if (vh.mGoneView.getVisibility() == View.GONE) {
            // Reveal the "GONE" view, expand the itemView and translate the right-hand view.
            vh.mGoneView.setVisibility(View.VISIBLE);
            int translation = vh.mGoneView.getLayoutParams().width;
            itemView.getLayoutParams().width = itemView.getWidth() + translation;

            // Works with "GONE" view of fixed width. Make adjustments if width is variable.
            rightChild.setTranslationX(translation);
            vh.mExpansion = translation;
        } else { // View is expanded.
            // Undo the expansion changes.
            vh.mGoneView.setVisibility(View.GONE);
            itemView.getLayoutParams().width = itemView.getWidth() - vh.mExpansion;
            vh.mExpansion = 0;
            rightChild.setTranslationX(0);
        }
    }

    // Find the child to the right of a view within the RecyclerView.
    private int findRightChildPos(View view) {
        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
            if (mRecyclerView.getChildAt(i) == view) {
                return i + 1;
            }
        }
        return RecyclerView.NO_POSITION;
    }

    static class ItemViewHolder extends RecyclerView.ViewHolder {
        final TextView mItemTextView;
        final View mGoneView;
        int mExpansion;

        ItemViewHolder(View item) {
            super(item);
            mItemTextView = item.findViewById(R.id.textView);
            mGoneView = item.findViewById(R.id.expandingView);
        }
    }

    private final static int TYPE_ITEM = 1;
}

recycler_item.xml

<LinearLayout 
    android:id="@+id/item"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:clickable="true"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:textSize="48sp"
        tools:background="@android:color/holo_blue_light"
        tools:text="1" />

    <View
        android:id="@+id/expandingView"
        android:layout_width="100dp"
        android:layout_height="match_parent"
        android:background="@android:color/holo_purple"
        android:visibility="gone" />

    <View
        android:layout_width="10dp"
        android:layout_height="match_parent"
        android:background="@android:color/holo_red_light" />
</LinearLayout>