I need to implement a simple chat client on Android and in this application there is a stackFromEnd in my RecyclerView which I need to populate its data from database (or my server). So I added OnScrollListener to my list as below.
messageList.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (messageLoading == false && layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
messageLoading = true;
ActionManager.getInstance().getChatAction().getThreadMessages(thread);
}
super.onScrolled(recyclerView, dx, dy);
}
});
The problem is when its called, the RecyclerView jumps to the first item of the list.
P.S:
ActionManager.getInstance().getChatAction().getThreadMessages(thread)
Just adds new items to adapter and calls notifyDataSetChanged
P.S.S:
Is there any library for message list (e.g. whatsapp, messenger etc.?!)
Related
I have a horizontal Recycler view implemented with SnapHelper to get a carousal effect. In my ViewHolder I have a function to animate the views inside Recycler item. So whenever an item is scrolled to center (selected) in SnapHelper I need to start the animation. I have tried following code but its not working. Sometimes I am getting viewholder as null.
widgetScrollView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(final RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
int pos = ((LinearLayoutManager) widgetScrollView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
ResultTallyAdapter.ViewHolder viewHolder = (ResultTallyAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(pos);
viewHolder.startAnimation(MainActivity.this, pos);
}
}, 1000);
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
I was trying same thing like you. But code is different. I use SnapHelper to find current view and get position from this view and start operation on adapter by this position. You can get idea following code, may help you
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
synchronized (this) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//calculatePositionAndScroll(recyclerView);
View view = snapHelper.findSnapView(recyclerView.getLayoutManager());
if (view != null) {
int pos = recyclerView.getLayoutManager().getPosition(view);
Log.d("RecyclerViewTest", "position: " + pos + " item: " + itemList.get(pos).getName());
makeSelectedItem(pos); // do your stuff on this view
// adapter.notifyDataSetChanged();
}
}
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
How can I get object from recyclerview when it leaves screen while scrolling? For example I have note with id 11 how can I get this note id whenever it leaves screen?
One way you could do it:
Boolean upScrolling;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager mgr = (LinearLayoutManager) recyclerView.getLayoutManager();
int topPosition = mgr.findFirstVisibleItemPosition();
/// your code
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy < 0) {
upScrolling = true;
} else if (dy > 0) {
upScrolling = false;
}
}
});
After scrolling up, in the listener you get the 1st visible item. At the position your code you write the code to check if the 1st visible item is the one below the item you want. If this is the case then you get the time it went off the screen.
Edited to check if it scrolls up or down.
my app has 3 fragments that are being inflated from mainActivity with BottomNavigationView. One of the fragments uses RecyclerView and is scrollable, with BottomNavigationView the last item in recyclerView is being covered up. According to Google's guidelines bottomNavigationView should hide on scroll down and show on scroll up. It's easy enough to make it hide from the mainAcitivity but it doesn't work when Im trying to hide it from the other fragment. How do I do this properly?
This code from recyclerView checks for the scroll state:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
//mainActivity.setNavigationVisibility(false);
} else if (dy < 0 ) {
//mainActivity.setNavigationVisibility(true);
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
And should call this method in the mainActivity that hides the bottomNavigationView:
public void setNavigationVisibility(boolean visible) {
if (navigation.isShown() && !visible) {
navigation.setVisibility(View.GONE);
}
else if (!navigation.isShown() && visible){
navigation.setVisibility(View.VISIBLE);
}
}
try this
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
((MainActivity)getActivity()).setNavigationVisibility(false);
} else if (dy < 0 ) {
((MainActivity)getActivity()).setNavigationVisibility(true);
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
When you use activity method from fragment then you have to create your method public and you can access that method by typecasting.
I have implemented addonscrollListener for my recyclerview since I want to
hide my FAB when recyclerview is scrolled as follows :
mRvNearby.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.e("DY",""+dy);
if(dy<0){
mFloatingActionMenu.hideMenuButton(true);
}else{
mFloatingActionMenu.showMenuButton(true);
}
}
});
But unfortunately, when I use this listener, the "dy" only changes once, and when I scrolled continuously, the value
hasn't changed.
I was expecting that when scrolled down, The value will be less than 0.
and when scrolled up, the value is greater than 0.
Use greater than sign instead of less than. When you scroll down the value is greater than 0. So your code will be :
mRvNearby.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.e("DY",""+dy);
if(dy>0){
mFloatingActionMenu.hideMenuButton(true);
}else{
mFloatingActionMenu.showMenuButton(true);
}
}
});
You can use FloatingActionButton.Behavior for showing/hiding FAB while Recyclerview scrolls.
Check out this Tutorial
I am developing an App for Android TV via Nexus Player. In my App, I use the VerticalGridFragment to show TV shows. For shows' number is 2000+, I want to use page loading when the VerticalGridView scrolls to its bottom.
However, I get stuck on how to judge the VerticalGridView has scrolled to bottom.
I use reflect to get the VerticalGridView,and addScrollListener() to it.Here the codes:
private void addGridScrollListener() {
try {
Class<VerticalGridFragment> VerticalGridFragmentClass = VerticalGridFragment.class;
Field verticalGridViewHolder = VerticalGridFragmentClass.getDeclaredField("mGridViewHolder");
verticalGridViewHolder.setAccessible(true);
VerticalGridPresenter.ViewHolder viewHolder = (VerticalGridPresenter.ViewHolder) verticalGridViewHolder.get(this);
VerticalGridView gridView = viewHolder.getGridView();
gridView.addOnScrollListener(scrollListener);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
};
RecyclerView doesn't has the function such as getLastVisiableItemPosition, so I can't know if the VerticalGridView has scrolled to bottom or not.
What should I do in the scrollListener ? Or is there any other solutions?
Thanks!
I found the solution:
private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState != RecyclerView.SCROLL_STATE_IDLE) {
return;
}
//get current last child View
View lastChildView = recyclerView.getLayoutManager().getChildAt(recyclerView.getLayoutManager().getChildCount() - 1);
//get the bottom
int lastChildBottom = lastChildView.getBottom();
// get recyclerView's bottom
int recyclerBottom = recyclerView.getBottom() - recyclerView.getPaddingBottom();
//get last childview's position
int lastPosition = recyclerView.getLayoutManager().getPosition(lastChildView);
if (lastChildBottom == recyclerBottom && lastPosition == recyclerView.getLayoutManager().getItemCount() - 1) {
// yes to bottom.
}
}
};