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 !
Related
I am using MergeAdapter to combine 2 adapters It works fine .
Problem is for 1 adapter I need LinearLayoutManager with single column and for second adapter I need GridLayoutManager to show items in 2 columns . Is there any way to do it ?
I found a working solution(added below) by setting it to GridLayoutManager and span size based on position . I just want to know is there a better way to do this .
Set GridLayoutManager to RecyclerView and span size based on position .
val layoutManager = GridLayoutManager(requireContext(), 2)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
if(position==0){
return 2 //no of colums it show occupy
}
return 1
}
}
recyclerView.layoutManager = layoutManager
In this case if position in mergeadapter is 0 then the only 1 column will be show come else 2 columns will be shown .
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.
I am trying to retrieve data from firebase then display it in recycler view. I set the layout to be reverselayout = true. However, when I run the activity, the view starts at the bottom. I tried to change the initial position when the application is run using scrollToPosition as commented below, but still nothing changes. Does anyone have a solution related to this problem?
I've tried this: https://stackoverflow.com/a/26876044/7825519
But still start from bottom.
mRecyclerView!!.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
(mRecyclerView!!.layoutManager as LinearLayoutManager).reverseLayout = true
(mRecyclerView!!.layoutManager as LinearLayoutManager).stackFromEnd = true
mRecyclerView?.scrollToPosition(3)
// mRecyclerView?.smoothScrollToPosition(3)
// (mRecyclerView!!.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(3,0)
// mNestedScrollView?.scrollTo(0,3)
mAdapter = DiscoverAdapter(mItems, mPostKey, Static.mLikedPosts, this)
mRecyclerView!!.adapter = mAdapter
val spacingInPixels = resources.getDimensionPixelSize(R.dimen.margin_between_card)
mRecyclerView!!.addItemDecoration(SpacesItemDecoration(spacingInPixels))
First of all delete the both lines that make the recyclerview start from the botom.
Set the scrolling after you set the adapter:
mRecyclerView!!.adapter = mAdapter
mRecyclerView?.scrollToPosition(3)
Try to set scrollToPosition using post method of View
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.
How can I get a current item in RecycerView? In my use-case RV item takes all screen space, so there is only one item at a time.
I've tried to google before, but nothing helpful was found.
The whole use case:
UI. The bottom navigation has a button that should call a certain method (let's say a foo() method) in fragment
this foo() method should get a visible item from the adapter and call a specific method in a presenter.
use this in your code
LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
and get your visible item using below code
mLayoutManager.findFirstVisibleItemPosition();
You could also use an OnItemClickListener on your RecyclerView's ListAdapter to determine the current item. In that case the item needs to be clicked though.
My solution
val position = (recyclerView?.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
val product = adapter?.getItemByPosition(position)
FirebaseCrash.logcat(Log.DEBUG, TAG, "onNavClickEvent = $product")
product?.let { productListViewModel?.order(it.id) }
The result is:
onNavClickEvent = Product(id=1, title='Cap', description='some descr.', price=10, photo='http://lorempixel.com/200/200/sports/1/')