Increase cell width in a RecyclerView with GridLayoutManager
I have a RecyclerView
with a GridLayoutManager
with spanCount=2
and a Vertical
orientation.
My items are correctly displayed as the image below:
Now I need to add an animation that when a click on one of the items, let's say number "3", that item increases its width and push the item next to it (in this example, number "4") partially outside the parent/screen.
Visually, it would be something like this:
To expand the item I am setting the visibility to VISIBLE
to a view inside the item and to collapse it, set the visibility to GONE
.
At the moment, I am able to show and hide that view, but it only takes the space of the item, it does increase the width pushing the item next to it.
So my questions are:
- Is this possible to use the default GridLayoutManager for this?
- What would be a good approach to achieve this?
android android-recyclerview gridlayoutmanager
add a comment |
I have a RecyclerView
with a GridLayoutManager
with spanCount=2
and a Vertical
orientation.
My items are correctly displayed as the image below:
Now I need to add an animation that when a click on one of the items, let's say number "3", that item increases its width and push the item next to it (in this example, number "4") partially outside the parent/screen.
Visually, it would be something like this:
To expand the item I am setting the visibility to VISIBLE
to a view inside the item and to collapse it, set the visibility to GONE
.
At the moment, I am able to show and hide that view, but it only takes the space of the item, it does increase the width pushing the item next to it.
So my questions are:
- Is this possible to use the default GridLayoutManager for this?
- What would be a good approach to achieve this?
android android-recyclerview gridlayoutmanager
add a comment |
I have a RecyclerView
with a GridLayoutManager
with spanCount=2
and a Vertical
orientation.
My items are correctly displayed as the image below:
Now I need to add an animation that when a click on one of the items, let's say number "3", that item increases its width and push the item next to it (in this example, number "4") partially outside the parent/screen.
Visually, it would be something like this:
To expand the item I am setting the visibility to VISIBLE
to a view inside the item and to collapse it, set the visibility to GONE
.
At the moment, I am able to show and hide that view, but it only takes the space of the item, it does increase the width pushing the item next to it.
So my questions are:
- Is this possible to use the default GridLayoutManager for this?
- What would be a good approach to achieve this?
android android-recyclerview gridlayoutmanager
I have a RecyclerView
with a GridLayoutManager
with spanCount=2
and a Vertical
orientation.
My items are correctly displayed as the image below:
Now I need to add an animation that when a click on one of the items, let's say number "3", that item increases its width and push the item next to it (in this example, number "4") partially outside the parent/screen.
Visually, it would be something like this:
To expand the item I am setting the visibility to VISIBLE
to a view inside the item and to collapse it, set the visibility to GONE
.
At the moment, I am able to show and hide that view, but it only takes the space of the item, it does increase the width pushing the item next to it.
So my questions are:
- Is this possible to use the default GridLayoutManager for this?
- What would be a good approach to achieve this?
android android-recyclerview gridlayoutmanager
android android-recyclerview gridlayoutmanager
edited Nov 20 '18 at 11:04
Ali
1
1
asked Nov 20 '18 at 10:57
ampamp
4,10195298
4,10195298
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
It is possible to useGridLayoutManager
as follows:
- Define the
GridLayoutManager
with two spans. - Set up an item layout that incorporates the clickable view and the view that will be set to
VISIBLE
andGONE
. - In the adapter, when, say, the left view is clicked, set the expandable view to
VISIBLE
, increase the size of theitemView
by the width of the expandable view. Translate the view to the right by the amount of the expansion to accommodate the increased size of the left view. - Do some housekeeping to make sure that recycled views are reset.
Here is an example. I assume that only the left view can be clicked. The general process is the same for the right view if if it can also be clicked, but the details differ in what needs to be translated, etc.
This example does not retained information of the status of view that are involved in an expansion, so if you expand a view then scroll down and back up, the view may be reset.
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
This demo adapter assumes that there are an even number of items to display. For simplicity, null checks have not been coded.
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>
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView likeitemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?
– amp
Nov 27 '18 at 11:09
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
add a comment |
I see how to implement this using HorizontalScrollView/RecyclerView with LinearLayoutManager. Instead of using GridLayoutManager with two columns you can use LinearLayoutManager with such views:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
Then it's trivial to implement expanded views.
In other case you'll need custom layout manager, which can scroll horizontally and vertically.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53391494%2fincrease-cell-width-in-a-recyclerview-with-gridlayoutmanager%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
It is possible to useGridLayoutManager
as follows:
- Define the
GridLayoutManager
with two spans. - Set up an item layout that incorporates the clickable view and the view that will be set to
VISIBLE
andGONE
. - In the adapter, when, say, the left view is clicked, set the expandable view to
VISIBLE
, increase the size of theitemView
by the width of the expandable view. Translate the view to the right by the amount of the expansion to accommodate the increased size of the left view. - Do some housekeeping to make sure that recycled views are reset.
Here is an example. I assume that only the left view can be clicked. The general process is the same for the right view if if it can also be clicked, but the details differ in what needs to be translated, etc.
This example does not retained information of the status of view that are involved in an expansion, so if you expand a view then scroll down and back up, the view may be reset.
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
This demo adapter assumes that there are an even number of items to display. For simplicity, null checks have not been coded.
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>
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView likeitemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?
– amp
Nov 27 '18 at 11:09
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
add a comment |
It is possible to useGridLayoutManager
as follows:
- Define the
GridLayoutManager
with two spans. - Set up an item layout that incorporates the clickable view and the view that will be set to
VISIBLE
andGONE
. - In the adapter, when, say, the left view is clicked, set the expandable view to
VISIBLE
, increase the size of theitemView
by the width of the expandable view. Translate the view to the right by the amount of the expansion to accommodate the increased size of the left view. - Do some housekeeping to make sure that recycled views are reset.
Here is an example. I assume that only the left view can be clicked. The general process is the same for the right view if if it can also be clicked, but the details differ in what needs to be translated, etc.
This example does not retained information of the status of view that are involved in an expansion, so if you expand a view then scroll down and back up, the view may be reset.
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
This demo adapter assumes that there are an even number of items to display. For simplicity, null checks have not been coded.
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>
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView likeitemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?
– amp
Nov 27 '18 at 11:09
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
add a comment |
It is possible to useGridLayoutManager
as follows:
- Define the
GridLayoutManager
with two spans. - Set up an item layout that incorporates the clickable view and the view that will be set to
VISIBLE
andGONE
. - In the adapter, when, say, the left view is clicked, set the expandable view to
VISIBLE
, increase the size of theitemView
by the width of the expandable view. Translate the view to the right by the amount of the expansion to accommodate the increased size of the left view. - Do some housekeeping to make sure that recycled views are reset.
Here is an example. I assume that only the left view can be clicked. The general process is the same for the right view if if it can also be clicked, but the details differ in what needs to be translated, etc.
This example does not retained information of the status of view that are involved in an expansion, so if you expand a view then scroll down and back up, the view may be reset.
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
This demo adapter assumes that there are an even number of items to display. For simplicity, null checks have not been coded.
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>
It is possible to useGridLayoutManager
as follows:
- Define the
GridLayoutManager
with two spans. - Set up an item layout that incorporates the clickable view and the view that will be set to
VISIBLE
andGONE
. - In the adapter, when, say, the left view is clicked, set the expandable view to
VISIBLE
, increase the size of theitemView
by the width of the expandable view. Translate the view to the right by the amount of the expansion to accommodate the increased size of the left view. - Do some housekeeping to make sure that recycled views are reset.
Here is an example. I assume that only the left view can be clicked. The general process is the same for the right view if if it can also be clicked, but the details differ in what needs to be translated, etc.
This example does not retained information of the status of view that are involved in an expansion, so if you expand a view then scroll down and back up, the view may be reset.
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
This demo adapter assumes that there are an even number of items to display. For simplicity, null checks have not been coded.
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>
edited Nov 26 '18 at 3:14
answered Nov 25 '18 at 19:42
CheticampCheticamp
29.4k43063
29.4k43063
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView likeitemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?
– amp
Nov 27 '18 at 11:09
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
add a comment |
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView likeitemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?
– amp
Nov 27 '18 at 11:09
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView like
itemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?– amp
Nov 27 '18 at 11:09
Thank you, that is a great starting point. I just have one problem. If the expandable view is on the right, if I change the width of the itemView like
itemView.getLayoutParams().width = itemView.getWidth() + translation;
, the width will increase to the right, instead of growing to the left? Is that true?– amp
Nov 27 '18 at 11:09
1
1
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
@amp The view will grow to the right. You will then need to do some translations to the left to make the itemView shows completely. The itemView in the left-hand column will also need to shift to the left.
– Cheticamp
Nov 27 '18 at 11:45
add a comment |
I see how to implement this using HorizontalScrollView/RecyclerView with LinearLayoutManager. Instead of using GridLayoutManager with two columns you can use LinearLayoutManager with such views:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
Then it's trivial to implement expanded views.
In other case you'll need custom layout manager, which can scroll horizontally and vertically.
add a comment |
I see how to implement this using HorizontalScrollView/RecyclerView with LinearLayoutManager. Instead of using GridLayoutManager with two columns you can use LinearLayoutManager with such views:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
Then it's trivial to implement expanded views.
In other case you'll need custom layout manager, which can scroll horizontally and vertically.
add a comment |
I see how to implement this using HorizontalScrollView/RecyclerView with LinearLayoutManager. Instead of using GridLayoutManager with two columns you can use LinearLayoutManager with such views:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
Then it's trivial to implement expanded views.
In other case you'll need custom layout manager, which can scroll horizontally and vertically.
I see how to implement this using HorizontalScrollView/RecyclerView with LinearLayoutManager. Instead of using GridLayoutManager with two columns you can use LinearLayoutManager with such views:
__|HorizontalScrollView/RecyclerView|
| [Firts view] [Second view] |
|---------------------------------|
Then it's trivial to implement expanded views.
In other case you'll need custom layout manager, which can scroll horizontally and vertically.
answered Nov 23 '18 at 9:51
Konstantin BerkowKonstantin Berkow
60611122
60611122
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53391494%2fincrease-cell-width-in-a-recyclerview-with-gridlayoutmanager%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown