ItemDecoration Before LayoutManager? - android

I've created a custom ItemDecoration for a RecyclerView that is using a GridLayoutManager. The ItemDecoration essentially ensures that equivalent spacing between all of the child views is applied within the RecyclerView:
The ItemDecoration is working exactly as I hoped it would and I think it looks great. However, I noticed that I need to add the ItemDecoration before I set the layout manager for my RecyclerView. My main question is: Why is that?
I'm working with some legacy code that uses a CursorLoader to pull RSS feeds from the web and display them to the end user. For whatever reason, the layout manager is being set in onLoadFinished():
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
Adapter adapter = new Adapter(cursor);
adapter.setHasStableIds(true);
mRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, mColumnCount, GridLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(gridLayoutManager);
}
I noticed that if I add my ItemDecoration within onLoadFinished(), the margins between the items looks bigger than it really should:
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
Adapter adapter = new Adapter(cursor);
adapter.setHasStableIds(true);
mRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, mColumnCount, GridLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(gridLayoutManager);
// Adding the custom ItemDecoration
EqualOffsetItemDecoration itemDecoration = new EqualOffsetItemDecoration(this, R.dimen.card_view_margin, mColumnCount);
mRecyclerView.addItemDecoration(itemDecoration);
}
The screenshot above shows far more margin than I was expecting since I'm only applying 8dps (the value of card_view_margin). However, if I add the ItemDecoration within onCreate(), then it appears as expected:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mColumnCount = getResources().getInteger(R.integer.list_column_count);
/*
In order to have equal spacing along the edges of the screen as well as between the
child views of the RecyclerView, an EqualOffsetItemDecoration is applied to the RecyclerView.
*/
EqualOffsetItemDecoration itemDecoration = new EqualOffsetItemDecoration(this, R.dimen.card_view_margin, mColumnCount);
mRecyclerView.addItemDecoration(itemDecoration);
...
}
...which is the case for the first screenshot. So why does this matter? Why do I need to add the ItemDecoration before applying a layout manager to my RecyclerView? I'm sure that this has something to do with the order in which things are executed under the hood. Any sort of explanation is greatly appreciated :)
FYI, in case anyone is interested in how I created my ItemDecoration, here it is:
https://github.com/mikepalarz/XYZReader/blob/master/app/src/main/java/com/example/xyzreader/ui/EqualOffsetItemDecoration.java

Interesting question, but I don't believe it matters if you set the layout manager before or after the item decoration. Both calls result in a request for layout.
I am going to guess that you are adding the decoration to the RecyclerView more than one time. Since decorations compound, you will see a greater gap with the decoration added two times (or more times) instead of just once.

Related

How to arrange multiple images horizontally on single activity

I am new to android i have developed an application in which i have to display images horizontal view on single activity i have done using staggered recycleview but am getting like this.
But i want to design like this as part of the activity.
You can easily do that with GridLayoutManager. Use SpanSizeLookup to control your row/column . For your case you have to use HORIZONTAL orientation. SpanSizeLookup will help you to control your rows in each column in HORIZONTAL GridLayoutManager.
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), NUM_OF_ROW, LinearLayoutManager.HORIZONTAL, reverseOrder);
GridLayoutManager.SpanSizeLookup spanSizeLookup = new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
// for position 0 use only one row. for this position it will take all rows
if (position == 0) {
return NUM_OF_ROW;
}
return 1;
}
};
Here is blog post about different Layout Manager implementation.
I have uploaded a repo on Github about different LayoutManager usage like LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager and some advance RecyclerView usage like swipe, Drag and Drop. You can also check that
here is what i use for arranging items horizontally provided you're using RecyclerView:
int numberOfColumns = 3; //edit as you want pls
final GridLayoutManager gridLayoutManager = new GridLayoutManager(this.getContext(), numberOfColumns);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
I might be off your solution, perdon if so, but pasting some of your code might help better.

how to get data from bottom to top from firebase?

I'm trying to get data from bottom to top (from the last item uploaded to the first item uploaded like Instagram) but I couldn't make this. I searched a lot and found this answer here.
I made it with firebaseRecyclerAdapter and worked fine but with custom Adapter I couldn't do it!
here is the method I used:
#Override
public ItemsRecyclerView getItem(int pos){
return super.getItem(getCount() - 1 - pos);
}
What you should be doing is reversing the recyclerview, forget about the method that you used above.
And do this when you set your recycler view:
LinearLayoutManager manager = new LinearLayoutManager(context);
manager.setReverseLayout(true);
manager.setStackFromEnd(true);
recycler_View.setLayoutManager(manager);
Possible solution:
try this:
Maybe try to reverse the list that you pass to your adapter like this:
//your list
List<model> your_list = new ArrayList()<>;
//before you pass it to the adapter do this
Collections.reverse(your_list);
//now your list is reversed, pass it to the adapter
Adapter adapter = new Adapter (your_list,.....,....);

Gridlayout manager with different column numbers in each row

I need a recycler view with different number of columns in a row. For that I have used a gridlayout manager with dynamic span size. Here is my code:
rvSubCat.layoutManager = StaggeredGridLayoutManager(4, 1)
val viewTreeObserver = rvSubCat.getViewTreeObserver()
viewTreeObserver.addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener { calculateSize() })
categoryAdapter = CategoryAdapter(categoryList, true, this)
rvSubCat.adapter = categoryAdapter
private fun calculateSize() {
val spanCount = Math.floor((rvSubCat.getWidth() / SizeUtils.dp2px(sColumnWidth.toFloat())).toDouble()).toInt()
(rvSubCat.getLayoutManager() as StaggeredGridLayoutManager).spanCount = spanCount
}
But the desired result is not good. It is fixing the number of columns in every row. I need the number of columns should depend upon the total width of the row items.
Need this (Desired Result):
Getting This
Best light weight library i use
compile 'com.xiaofeng.android:flowlayoutmanager:1.2.3.2'
Benifit is you dont need to change your existing code, you just need to change recyclerview's LayoutManager like
recyclerView.setLayoutManager(new FlowLayoutManager());
You are all set, Happy coding :)
Update You know already how to populate recycler view. But verify by following
private void setAdapter() {
recyclerView = (RecyclerView) fragment_view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new FlowLayoutManager());
myRecyclerAdapter = new AdapterOrders(getActivity(), list);
recyclerView.setAdapter(myRecyclerAdapter);
}
Call myRecyclerAdapter.notifyDataSetChanged(); after list is change from any source.
What you need is flow Layout. I think these library will help you solve the purpose :
https://github.com/nex3z/FlowLayout
https://github.com/ApmeM/android-flowlayout
Adjusts according to size of texts. Hope this helps !

Staggered Grid LayoutManager Stack from end

I am trying to make a application that displays data in list using RecyclerView, In LinearLayoutManager there is a option to set Stack from end and reverse layout that allows for me to show the newest data on top of list. Is there anyway I can show the newest data at position 0 (at top) in staggered grid layout?
StaggeredGridLayoutManager has the method setReverseLayout.
Use it like this:
mLayoutManager = new StaggeredGridLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
You can use GridLayoutManagaer. In constructor you can pass true/false to reverse layout or can use setReverseLayout(boolean) method. check this
You can scroll to the end after updating(inserting) you data (when it's needed)
private void updateData(#NonNull List<Item> items, boolean moveToTheEnd) {
adapter.updateItems(items);
if(moveToTheEnd) {
recyclerView.scrollToPosition(adapter.getItemCount() - 1);
}
}
The solution that worked for me, without having those spaces at the beginning, is to add this line at the beginning of your onBindViewHolder method in your adapter:
position = getItemCount()-1-position;
So your code will be something like this:
#Override
public void onBindViewHolder(#NonNull MyAdapter.ViewHolder holder, int position) {
position = getItemCount()-1-position;
holder.textView.setText(mObjects.get(position).getText());
}

Different (dynamic) items height in GridLayoutManager

I have a RecyclerView and GridLayoutManager with 2 columns.
How can I force LayoutManager to be according with template on the first screenshot? Now I have result as on the 2th screenshot.
Need result:
Current result:
GridLayoutManager will use a grid, and you can set some span, but not different heights for different cells.
What you want is a StaggeredGridLayoutManager. This will just put the items on the screen if they fit, leading to your needed result. You can also change the reordering behavior, if you want to, by using setGapStrategy.
It's really easy. You have to add this manager to RecycleView:
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(mColumnCount, 1));
in my case it's look like this:
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
if (mColumnCount <= 1) {
recyclerView.setLayoutManager(new LinearLayoutManager(context));
} else {
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(mColumnCount, 1));
}
recyclerView.setAdapter(new MyItemRecyclerViewAdapter(DummyContent.ITEMS, mListener));

Categories

Resources