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/')
Related
The recycler view sometimes show or not show the data when I start the activity. This is how it's programmed, I have a main activity and an activity that has a recycler view in it. To test it I hardcoded a data using a for loop in the onCreate method. It will only loop and add data to the array before it is set to the recycler view. Now the problem is that, sometimes the data shows up and sometimes there's nothing in the list. I can easily reproduce the issue by going back and fort to the main activity and the activity with recycler view. I think I'm doing it wrong by adding it to the onCreate.
Here's what I have in the onCreate:
for(i in 1..5){
val newDeliveredAsset = AssetDelivered()
newDeliveredAsset.id = i
newDeliveredAsset.accountNumber = 1
newDeliveredAsset.barCode = "BB" + i.toString()
newDeliveredAsset.description = "test " + i.toString()
assets.add(newDeliveredAsset)
}
rvAsset = findViewById(R.id.ce_recycler_view)
layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.VERTICAL
rvAsset.layoutManager = layoutManager
rvAdapter = AssetRecyclerViewAdapter(this, assets as List<Asset>)
rvAsset.adapter = rvAdapter
I also tried to log the getItemSize of the adapter and it shows the correct number.
Update: Left the phone on the activity that's not showing the recycler view items. After few minutes, the items showed up.
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'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,.....,....);
Below is my implementation for recycler view.
The recycler view is refreshing but the view is lagging alot making it not smooth to scroll.
If I dont refresh data the recyclerView is smooth.
The problem is with refreshing only..!!
I need to refresh data completely every 1 sec in RecyclerView maintaining same scroll position.
xml
<android.support.v7.widget.RecyclerView
android:id="#+id/recyView_disp_pgms"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#null" />
Activity :
RecyclerView recyView_disp_pgms = (RecyclerView) findViewById(R.id.recyView_disp_pgms);
DisplayProgramsAdapterRecycler pgmAdapter = new DisplayProgramsAdapterRecycler(programsList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyView_disp_pgms.setLayoutManager(layoutManager);
recyView_disp_pgms.setAdapter(pgmAdapter);
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
System.out.println("AllPgm Runflag : " + runflag);
programList = // Get List from database
if (programsList != null && programsList.size() > 0) {
if (pgmAdapter != null && pgmAdapter.getItemCount() > 0) {
pgmAdapter.resetData(programsList);
}
}
handler.postDelayed(this, 1000);
}
};
handler.post(runnable);
Adapter :
public void resetData(ArrayList<ProgramDetails_Table> programsList) {
this.programDetailsList = programsList;
this.notifyDataSetChanged();
}
Problem - Lagging scroll of recyclerView only while refreshing data for every 1 sec
Tried following other posts; but still no luck.
Please help..!!
if you want to refresh your list find your changes and then just notify that position because notifyDataSetChanged resets all of your data.
you should use lightweight notifies.something like this:
notifyItemChanged(yourPosition);
notifyItemInserted(yourPosition);
notifyItemRemoved(yourPosition);
or if you get more than one change in a range you can use:
notifyItemRangeChanged(yourPosition);//and etc
use DiffUtil. Don't use notifyDataSetChanged.
According to this https://developer.android.com/reference/android/support/v7/util/DiffUtil.html,
DiffUtil is a utility class that can calculate the difference between
two lists and output a list of update operations that converts the
first list into the second one.
It can be used to calculate updates for a RecyclerView Adapter.
Unlike the notifyDataSetChanged method, it does not reload the whole list so it has a better performance.
And you don't have to manually find the differences between the new and the old list like the other notifyData methods from RecyclerView.Adapter.
Delete your line this.programDetailsList = programsList; and add the following. This is a simple hack, a way that makes you understand Async Callbacks.
/* I have done adding one element and then deleting the same element as the last element of programsList */
/* adding and deleting triggers notifyDataChange() callback */
//add an element in index 0 as the last element into the programList
programsList.add(programsList.size() - 1, programsList.get(0));
//remove the same last element from ProgramList
programsList.add(programsList.size() - 1);
//now it works
this.notifyDataSetChanged(programsList.size() - 1);
Make sure you are calling notifyDataSetChanged() inside the resetData function.
Also, try this instead of assigning directly to programList
programList.clear();
programList.addAll(arrayListOfDataFromServer);
The RecyclerView.scrollToPosition() is extremely strange.
for example, supposed a RecyclerView named "rv".
if now item 10 is under the current RecyclerView, call rv.scrollToPosition(10), the RecyclerView will scroll item 10 to bottom.
if now item 10 is in the current RecyclerView, call rv.scrollToPosition(10), there won't be any scrolling, nothing will be done.
if now item 10 is on the top of the current RecyclerView, call rv.scrollToPosition(10), the RecyclerView will scroll item 10 to top.
To help understanding, look at this picture
But what i need is that, whenever i call it, the RecyclerView will scroll the supposed position to the top of current view just like case 3. How to do that?
If I understand the question, you want to scroll to a specific position but that position is the adapter's position and not the RecyclerView's item position.
You can only achieve this through the LayoutManager.
Do something like:
rv.getLayoutManager().scrollToPosition(youPositionInTheAdapter).
Below link might solve your problem:
https://stackoverflow.com/a/43505830/4849554
Just create a SmoothScroller with the preference SNAP_TO_START:
RecyclerView.SmoothScroller smoothScroller = new
LinearSmoothScroller(context) {
#Override protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}
};
Now you set the position where you want to scroll to:
smoothScroller.setTargetPosition(position);
And pass that SmoothScroller to the LayoutManager:
layoutManager.startSmoothScroll(smoothScroller);
If you want to scroll to a specific position and that position is the adapter's position, then you can use StaggeredGridLayoutManager scrollToPosition
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
staggeredGridLayoutManager.scrollToPosition(10);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
This is the Kotlin code snippet but you can just get the point for scrolling to the item by position properly. The point is to declare the member variable for the layout manager and use its method to scroll.
lateinit var layoutManager: LinearLayoutManager
fun setupView() {
...
layoutManager = LinearLayoutManager(applicationContext)
mainRecyclerView.layoutManager = layoutManager
...
}
fun moveToPosition(position: Int) {
layoutManager.scrollToPositionWithOffset(position, 0)
}
try recycler_view.smoothScrollBy(0, 100); here 0 represents x-coordinate and 100 represents y-coordinate I used this in vertical recyclerView where I wanted to scroll to next position in the vertical list and for coming to the previous position I simply replaced 100 with -100