I am trying to make grid view with two column but the problem is that I want to change the width of every column randomly.
I try to create it using stagger grid view but it only change the height of column and I need to change of width of column.
I am adding image what I want to make below:
Please use setSpan method for GridLayoutManager. In beginning use number of columns as 4, then as per need give span to each view in GridView.
GridLayoutManager gridLayoutManager = new GridLayoutManager(activity, 4);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup()
{
#Override
public int getSpanSize(int position)
{
if (position == 0)
{
return 2;
}
else if(position == 1)
{
return 2;
}
else if(position == 2)
{
return 3;
}
else if(position == 3)
{
return 1;
}
}
});
Use two or more synchronized list view will do. By 'synchronized', I mean when you swipe horizontally, both list views move accordingly.
You might checkout this PinterestListView repo for reference.
The sole difference is that you change the orientation of the list view, from vertical to horizontal.
If you don't wish to support horizontal swipes/scrolls, use two linear layout embedded into a vertical layout, that is it!
Related
I want to implement grid layout manager of 1,5, and 2 item in row 1 I want one item in 2 I want 5 item then in rest I want 2 item. How to achieve this. Please help I am doing coding of the same but not able to achieve 5 in the 2nd row there is 3 only.
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (position == 0)
return 5;
else if (position == 1)
return 1;
else
return 2;
}
});
You don't mention how many total spans you have across but I guess that it is 5.
The number of spans you define should be even divisible by the size of each item. So, divisible by 1 (of course), 5 and 2. 1*5*2=10, 10 spans will do. Create your GridLayoutManager with 10 spans.
Now, when you want just one item in a row, return 10 from setSpanSizeLookup(). If you want 2 items, then return 5. For 5 items return 2.
Your code will look something like this:
mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (position == 0)
return 10;
else if (position < 6)
return 2;
else
return 5;
}
});
I am implementing Dashboard in android with Recyclerview and Grid layout manager with 3 items in a row. I will get the dashboard items from server. According to the no of Items, I need to adjust the Recyclerview items to centre.
For example, If I have 11 items, I need to align last 2 items to the centre.
If I have , 10 items, last one item need to be aligned centre . For this Logic I made lot of research but didn't find any solution. Even I tried using spansize concept of GridLayoutManager but no luck.
Any help/example code would be very thankful.
Thanks in advance
If I understand your requirements correctly, there is no way to accomplish what you want with RecyclerView + GridLayoutManager. Even if you implement a custom GridLayoutManager.SpanSizeLookup, you will only be able to have your extra one or two items stretch to fill the row... you can't center them.
You can, however, accomplish what you want by using RecyclerView with a FlexboxLayoutManager, which is a part of Google's FlexboxLayout project: https://github.com/google/flexbox-layout
When you create your FlexboxLayoutManager, you need to set the FlexDirection to "row" and the JustifyContent to "center":
FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);
manager.setJustifyContent(JustifyContent.CENTER);
Then, when you create your ViewHolders, you need to size them to one third of the RecyclerView's width:
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.item_view, parent, false);
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams();
layoutParams.width = (parent.getWidth() / 3) - layoutParams.leftMargin - layoutParams.rightMargin;
itemView.setLayoutParams(layoutParams);
return new MyViewHolder(itemView);
}
Here's a link to a gist for a small app that demonstrates this: https://gist.github.com/zizibaloob/0c44bfe59b371b5ae0bd2edcb4a7e592
set spanSizeLookup on your GridLayoutManage
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if(ItemList.size() % 3 == 0){
return 3;
} else if( ItemList.size() % 3 == 2){
return 2;
} else{
return 1; // number of items to span
}
}
});
I’m using a staggered recycler view layout for a list of photos. I want the spacing on the sides to be zero while still having space between the two columns. I’m using an item decoration sub class to get the spacing seen in the attached photo. I know I have control over the left and right spacing but the problem is that I never know which column the photo is in. It seems like the staggered layout manager does some of its own reordering. I've tried using getChildAdapterPosition but it seems to return the position in the data source array and not the actual position of the photo in the layout. Any idea how I should approach this?
I managed to get it working. In my case, I don't need any borders on the left or right edges of the screen. I just need borders in the middle and bottom. The solution is to get the layout parameters of the view that are of type StaggeredGridLayoutManager.LayoutParams. In those parameters you can get the spanIndex that tells you on which index the view is. So if you have a spanCount of 2, the left view will have a spanIndex of 0 and the right view will have a spanIndex of 1.
Here is my code, maybe it help you.
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
int spanIndex = lp.getSpanIndex();
if (position > 0) {
if (spanIndex == 1) {
outRect.left = space;
} else {
outRect.right = space;
}
outRect.bottom = space * 2;
}
}
}
In my case, firstly I have to get the position, since on the index 0 I have a header View, which doesn't have any borders. After that, I get the span index and depending on it I set the borders that I need on that View. And finally I set the bottom border on every View.
so the one solution I was able to use was with an item decorator but it definitely is a little weird/hacky feeling.
Basically you'll adjust the outer rectangle of the item based on its column position (or something similar). My understanding is that the outer rectangle is more or less the spacing you want to change. Give the code below a try, obviously you'll need to make your own adjustments and logic to 'calculate' which column the item is on but this should be enough to figure it out, hopefully:
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int left = outRect.left;
int right = outRect.right;
int top = outRect.top;
int bottom = outRect.bottom;
int idx = parent.getChildPosition(view);
int perRow = gridLayoutManager.getSpanCount();
int adj = blahh... // some adjustment
if (idx < itemsPerRow) {
// on first row, adjust top if needed
}
if(idx % perRow == 0){
// on first column, adjust. Left magically adjusts bottom, so adjust it too...
left += adj;
bottom -= adj;
}
if(idx % itemsPerRow == perRow - 1){
// on last column, adjust. Right magically adjusts bottom, so adjust it too...
right += adjustment;
bottom -= adjustment;
}
outRect.set(left, top, right, bottom);
}
});
Again this is hacky and takes some trial and error to get right.
Another solution I have tried with some success is to define different views for the different columns. In your case the columns would have views with different, negative margins, on the left and right to get the effect you want.
As a side note, I assume you are using an elevation on the card view. One thing I've noticed is that if the card view does NOT have elevation and instead you handle it yourself (yeah, i know, isn't the point to not handle elevation yourself) much of this difficulty goes away and things start to behave, likely because of the elevation/shadow calculations. But anyway... Hope this is at least somewhat helpful...
Please suggest which is the best approach to follow. I tried with Grid View but i was not able to get a empty column
If you do not want to use a GridView (should work fine for your case), you could use a GridLayout. I would not advise this if you are going to have a lot of ImageViews, because you will need the recycling abilities of the GridView.
In the case of GridLayout, you can create the base GridLayout, set to 5 columns and use GridLayout.addView(View, LayoutParams) to append new ImageViews. When you are on the second column add a Space view.
Some simple pseudocode:
for(int i = 0; i < imageList.size(); i++) {
ImageView imageView = getImageViewUsingList(i);
if((i % 5) % 2 == 1) {
gridLayout.addView(new Space(), layoutParams);
} else {
gridLayout.addView(imageView, layoutParams);
}
}
I want to be able to take a ListView and have a specific row be scrollable to the top of that Listview's bounds, even if the row is near the end and normally wouldn't be able to scroll that high in a normal android ListView (similar to how twitter works when you drill into a specific tweet and that tweet is always scrollable to the top even when there's nothing underneath it.)
Is there any way I can accomplish this task easily? I've tried measuring the row i want to scroll to the top and applying bottom padding to account for the extra space it would need, but that yields odd results (i presume because changing padding and such during the measure pass of a view is ill advised). Doing so before the measure pass doesn't work since the measured height of the cell in question (and any cells after it) hasn't happened yet.
Looks like you the setSelectionFromTop method of listview.
mListView.setSelectionFromTop(listItemIndex, 0);
I figured it out; its a bit complex but it seems to work mostly:
public int usedHeightForAndAfterDesiredRow() {
int totalHeight = 0;
for (int index = 0; index < rowHeights.size(); index++) {
int height = rowHeights.get(rowHeights.keyAt(index));
totalHeight += height;
}
return totalHeight;
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (measuringLayout.getLayoutParams() == null) {
measuringLayout.setLayoutParams(new AbsListView.LayoutParams(parent.getWidth(), parent.getHeight()));
}
// measure the row ahead of time so that we know how much space will need to be added at the end
if (position >= mainRowPosition && position < getCount()-1 && rowHeights.indexOfKey(position) < 0) {
measuringLayout.addView(view, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
measuringLayout.measure(MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED);
rowHeights.put(position, view.getMeasuredHeight());
measuringLayout.removeAllViews();
view.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
if (position == getCount()-1 && view.getLayoutParams().height == 0) {
// we know how much height the prior rows take, so calculate the last row with that.
int height = usedHeightForAndAfterDesiredRow();
height = Math.max(0, parent.getHeight() - height);
view.getLayoutParams().height = height;
}
return view;
}
This is in my adapter. It's a subclass of a merge adapter, but you can just put it in your code and substitute the super call with however you generate your rows.
the first if statement in getView() sets the layout params of a frame layout member var that is only intended for measuring, it has no parent view.
the second if statement calculates all the row heights for rows including and after the position of the row that I care about scrolling to the top. rowHeights is a SparseIntArray.
the last if statement assumes that there is one extra view with layout params already set at the bottom of the list of views whose sole intention is to be transparent and expand at will. the usedHeightForAndAfterDesiredRow call adds up all the precalculated heights which is subtracted from the parent view's height (with a min of 0 so we don't get negative heights). this ends up creating a view on the bottom that expands at will based on the heights of the other items, so a specific row can always scroll to the top of the list regardless of where it is in the list.