使用 GridLayoutManager 增加 RecyclerView 中的单元格宽度
Increase cell width in a RecyclerView with GridLayoutManager
我有一个 RecyclerView
,一个 GridLayoutManager
,一个 spanCount=2
,一个 Vertical
方向。
我的物品正确显示如下图:
现在我需要添加一个动画,当点击其中一个项目时,比方说数字“3”,该项目会增加它的宽度并推动它旁边的项目(在这个例子中,数字“4” ) 部分在 parent/screen.
之外
视觉上应该是这样的:
要将我将可见性设置为 VISIBLE
的项目展开到项目内部的视图并折叠它,请将可见性设置为 GONE
。
目前,我可以显示和隐藏该视图,但它只占用项目的 space,它确实增加了推动旁边项目的宽度。
所以我的问题是:
- 是否可以为此使用默认的 GridLayoutManager?
- 实现此目标的好方法是什么?
我看到了如何使用 HorizontalScrollView/RecyclerView 和 LinearLayoutManager 来实现它。您可以将 LinearLayoutManager 与此类视图一起使用,而不是将 GridLayoutManager 与两列一起使用:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
那么实现扩展视图就很简单了。
在其他情况下,您需要自定义布局管理器,它可以水平和垂直滚动。
可以使用GridLayoutManager
如下:
- 用两个跨度定义
GridLayoutManager
。
- 设置一个包含可点击视图和将设置为
VISIBLE
和 GONE
的视图的项目布局。
- 在适配器中,例如,当单击左视图时,将可展开视图设置为
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>
我有一个 RecyclerView
,一个 GridLayoutManager
,一个 spanCount=2
,一个 Vertical
方向。
我的物品正确显示如下图:
现在我需要添加一个动画,当点击其中一个项目时,比方说数字“3”,该项目会增加它的宽度并推动它旁边的项目(在这个例子中,数字“4” ) 部分在 parent/screen.
之外视觉上应该是这样的:
要将我将可见性设置为 VISIBLE
的项目展开到项目内部的视图并折叠它,请将可见性设置为 GONE
。
目前,我可以显示和隐藏该视图,但它只占用项目的 space,它确实增加了推动旁边项目的宽度。
所以我的问题是:
- 是否可以为此使用默认的 GridLayoutManager?
- 实现此目标的好方法是什么?
我看到了如何使用 HorizontalScrollView/RecyclerView 和 LinearLayoutManager 来实现它。您可以将 LinearLayoutManager 与此类视图一起使用,而不是将 GridLayoutManager 与两列一起使用:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
那么实现扩展视图就很简单了。
在其他情况下,您需要自定义布局管理器,它可以水平和垂直滚动。
可以使用GridLayoutManager
如下:
- 用两个跨度定义
GridLayoutManager
。 - 设置一个包含可点击视图和将设置为
VISIBLE
和GONE
的视图的项目布局。 - 在适配器中,例如,当单击左视图时,将可展开视图设置为
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>