I want to know when the user keep scrolling (like when you want to update your timeline in Twitter?
Actually I just can use onScrollListener because I'm using this library that make listview capable to implements drag and drop of the listviews
What I want to do, is being capable to "minimize" this listview when the user make the "top to bottom" event, but its imposible to modify the OnTouchListener
What i am doing right now is the next one:
listOrders.getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == recyclerView.SCROLL_STATE_DRAGGING) {
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56, getResources().getDisplayMetrics());
int marginBottom = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
RelativeLayout.LayoutParams layPra = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
layPra.addRule(ALIGN_PARENT_BOTTOM);
layPra.bottomMargin = marginBottom;
frameOrders.setLayoutParams(layPra);
listOrders.setScrollingEnabled(false);
listOrders.setEnabled(false);
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
}
});
try this:
RecyclerView rv = (RecyclerView)findViewById(R.id.rv);
rv.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 (dy < 0) {
// Recycle view scrolling up...
} else if (dy > 0) {
// Recycle view scrolling down...
}
}
});
Related
How can I display a message to the user after scrolling the recyclerview items and viewing the last item in the list?
The code below does not work
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val count= recyclerView.layoutManager?.itemCount
if (customerModels.size==count){
Toast.makeText(applicationContext,"true",Toast.LENGTH_LONG).show()
}
}
})
This is what I usually use when I want to check if the user is reached to the bottom of the recyclerView
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
LinearLayoutManager lm=LinearLayoutManager.class.cast(recyclerView.getLayoutManager());
int items= lm.getItemCount();
int last = lm.findLastVisibleItemPosition();
boolean bottom= last+ 5 >= items;
if (items> 0 && bottom) {
//you have reached to the bottom of your recycler view
}
}
});
I have a recyclerview which has a swipe menu (background buttons) on my android app.
The article that I referred to is: https://codeburst.io/android-swipe-menu-with-recyclerview-8f28a235ff28
This article was quite helpful and I succeeded to embed the basic function of swipe menu features.
However, after the filter function for the list of the recyclerview was embedded, I noticed that I have to figure out a way how to reset/clear the swipe menu manually/programmatically because after the list of the cardviews are filtered, the swipe menu is lingered in the background of each list but I have no clues how to solve this issue. (as shown in the attached pictures)
The things that I tried are:
notifyDataSetChanged by Adapter - not work
notifyItemChanged by Adapter - not work
reset the ItemTouchHelper (put null and reattach) - not work
recyclerview.performClick to reset the state of the ItemTouchHelper - not work
According to the article, it seems clicking a recyclerview resets the state of the ItemTouchHelper.
Could you please teach me how to click a recyclerview programmatically or any other solutions if available?
The following code is a fraction of the source from the article that I assumed relevant to solve this issue...
private void setTouchUpListener(final Canvas c,
final RecyclerView recyclerView,
final RecyclerView.ViewHolder viewHolder,
final float dX, final float dY,
final int actionState, final boolean isCurrentlyActive) {
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
SwipeController.super.onChildDraw(c, recyclerView, viewHolder, 0F, dY, actionState, isCurrentlyActive);
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
setItemsClickable(recyclerView, true);
swipeBack = false;
buttonShowedState = ButtonsState.GONE;
}
return false;
}
});
}
After the swipe menu emerged by swiping
Swipe menus remained after filtering the list
I found out that adding the layout-change listener on the recyclerview could remove the swipe menu.
#Override
public int getMovementFlags(#NotNull final RecyclerView recyclerView, #NotNull final RecyclerView.ViewHolder viewHolder) {
myRecyclerView = recyclerView;
myRecyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
v.removeOnLayoutChangeListener(this);
clearSwipeMenu();
}
});
}
....
#Override
public void onChildDraw(#NotNull Canvas c, #NotNull RecyclerView recyclerView, #NotNull RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ACTION_STATE_SWIPE) {
if (buttonShowedState != ButtonsState.GONE) {
if (buttonShowedState == ButtonsState.LEFT_VISIBLE) dX = Math.max(dX, buttonWidth);
if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) dX = Math.min(dX, -buttonWidth);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
} else {
setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
if (buttonShowedState == ButtonsState.GONE) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
currentItemViewHolder = viewHolder;
}
....
public void clearSwipeMenu() {
if(currentItemViewHolder!=null){
clearView(myRecyclerView, currentItemViewHolder);
currentItemViewHolder = null;
}
}
I'm filing my data with json to recyclerview.
I want new data in every 10 items in recyclerview.
So
10 data -> arrived 10 more data in recyclerview last ....
So how do I detect that the user is at the end of the recyclerview?
Or, if there is another solution, you can submit your ideas. I use it for now, but sometimes it doesn't work ...
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// MyLog.log("rcv1 " + newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
MyLog.log("rcv1 dy: "+ dy);
if (dy>=0 ){
llHeading.setVisibility(View.GONE);
}else {
llHeading.setVisibility(View.VISIBLE);
}
totalItemCount = layoutManager.getItemCount();
visibleItemCount = layoutManager.getChildCount();
pastVisiblesItems = layoutManager.findFirstVisibleItemPosition();
if (!loadingItems && (visibleItemCount + pastVisiblesItems) >= totalItemCount ) {
loadingItems = true;
MyLog.log("rcv1 came to an end.");
getDataClient("",rccount*10,ranking_sort_by,ranking_desc,1);
}
}
});
In your adapter, you could use onBindViewHolder then check the position.
public void onBindViewHolder(ViewHolder holder, int position) {
if (position == getItemCount() - 1) {
// You are at the end of list
}
}
Use this:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) {
Log.d("tag","scrolled to end");
}
}
});
I have ItemTouchHelper class that uses swiping and drag and drop for performing actions. But i want to change drag and drop behavior. It should swap positions of 2 elements, the first one I dragged and the other one where it is dropped on. i want to exchange the items of the dragged & dropped positions. not to change positions of all items among both of them.
How to do it
this is my class for drag and drop
public class ItemTouchHelper extends
androidx.recyclerview.widget.ItemTouchHelper.Callback {
private Drawable icon;
private Context context;
private ColorDrawable background;
private final ItemTouchHelperListener dragDropListener;
public ItemTouchHelper(Context context, Drawable icon,
ItemTouchHelperListener dragDropListener) {
this.icon = icon;
this.dragDropListener = dragDropListener;
this.context = context;
this.background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder,
float dX, float dY,
int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX,
dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconBottom = iconTop + icon.getIntrinsicHeight();
if (dX > 0) {
background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));
iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
iconBottom = iconTop + icon.getIntrinsicHeight();
int iconRight = itemView.getLeft() + iconMargin + icon.getIntrinsicWidth();
int iconLeft = itemView.getLeft() + iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + ((int) dX),
itemView.getBottom());
} else if (dX < 0) {
int iconRight = itemView.getRight() - iconMargin;
int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getRight(), itemView.getTop(),
itemView.getRight() + ((int) dX),
itemView.getBottom());
} else {
background.setBounds(0, 0, 0, 0);
icon.setBounds(0, 0, 0, 0);
}
background.draw(c);
icon.draw(c);
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder,
int direction) {
dragDropListener.deleteElementDialog(viewHolder.getAdapterPosition());
}
#Override
public int getMovementFlags(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = UP | DOWN;
int swipeFlags = START | END;
return makeMovementFlags(dragFlags, swipeFlags);
}
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder,
#NonNull RecyclerView.ViewHolder target) {
dragDropListener.onRowMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
int actionState) {
if (actionState != ACTION_STATE_IDLE && actionState != ACTION_STATE_SWIPE) {
dragDropListener.onRowSelected(viewHolder);
}
super.onSelectedChanged(viewHolder, actionState);
}
#Override
public void clearView(#NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, Objects.requireNonNull(viewHolder));
dragDropListener.onRowClear(Objects.requireNonNull(viewHolder));
}
#Override
public boolean isLongPressDragEnabled() {
return true;
}
}
and this is my ItemTouchHelperListener:
public void setItemTouchHelperListener() {
ItemTouchHelperListener itemTouchHelperListener = new
ItemTouchHelperListener() {
#Override
public void onRowMoved(int fromPosition, int toPosition) {
presenter.rowMoved(fromPosition, toPosition);
}
#Override
public void onRowSelected(RecyclerView.ViewHolder myViewHolder) {
if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
elementsAdapter.rowSelected((ElementsAdapter.ElementsViewHolder) myViewHolder);
presenter.rowSelected(myViewHolder.getAdapterPosition());
}
}
#Override
public void onRowClear(RecyclerView.ViewHolder myViewHolder) {
if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
elementsAdapter.rowClear((ElementsAdapter.ElementsViewHolder) myViewHolder);
presenter.rowClear(myViewHolder.getAdapterPosition());
}
}
#Override
public void deleteElementDialog(int adapterPosition) {
createDeleteDialog(adapterPosition);
}
};
You can achieve this by registering both the dragged item using onMove() method, and the dropped item using clearView() method; then modify the data source of your RecyclerView adapter; so you can use a temp item that stores the dragged item; then set the dropped-by item with the dragged one; and finally put the temp item on the dropped one.
Then utilize RecyclerView adapter notifyItemChanged() for both items to update the layout with this change
Note: here I disabled the swiping as your question mainly on the drag & drop
final int[] oldPos = new int[1];
final int[] newPos = new int[1];
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP |
ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT,
0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
oldPos[0] = viewHolder.getAdapterPosition();
newPos[0] = target.getAdapterPosition();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
#Override
public void clearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
moveItem(oldPos[0], newPos[0]);
}
});
private void moveItem(int oldPos, int newPos) {
Item temp = mItems.get(oldPos);
mItems.set(oldPos, mItems.get(newPos));
mItems.set(newPos, temp);
mAdapter.notifyItemChanged(oldPos);
mAdapter.notifyItemChanged(newPos);
}
The result
I totally agree with #Zain answer but there is one problem i.e suppose you want to replace the 1st item with 3rd then you will click and hold the 3rd item and drag it over the 1st item. Once you dropped, you will notice the 3rd item will get again shifted to its original position and after that, both items will get updated properly. It doesn't look good.
I've just slightly modified the #Zain answer.
private int fromPos = -1;
private int toPos = -1;
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new
ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder,
#NonNull RecyclerView.ViewHolder target) {
toPos = target.getAdapterPosition();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder,
int direction) {}
#Override
public void onSelectedChange(#NonNull RecyclerView.ViewHolder
viewHolder, int actionState) {
switch(actionState){
case ItemTouchHelper.ACTION_STATE_DRAG:{
fromPos = viewHolder.getAdapterPosition();
break;
}
case ItemTouchHelper.ACTION_STATE_IDLE: {
//Execute when the user dropped the item after dragging.
if(fromPos != -1 && toPos != -1
&& fromPos != toPos) {
moveItem(fromPos, toPos);
fromPos = -1;
toPos = -1;
}
break;
}
}
private void moveItem(int oldPos, int newPos) {
Item temp = mItems.get(oldPos);
mItems.set(oldPos, mItems.get(newPos));
mItems.set(newPos, temp);
mAdapter.notifyItemChanged(oldPos);
mAdapter.notifyItemChanged(newPos);
}
Hello I am working on an Android project and i need to detect when scrolling Recycler View, I know you can add OnscrollListener to RecyclerView from Fragment or Activity, but I need to do it from adapter in order to pass data from there to the Fragment, Its something about Realtime Animation, Here is what i have for now in my Adapter
holder.linearLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Intent intent = new Intent("custom-message");
intent.putExtra("address",shop.getAddress());
LocalBroadcastManager.getInstance(v.getContext()).sendBroadcast(intent);
}
});
I used the AddonLayoutChangeListener but it doesn`t work as i expect, I cant figure out how to get this, hope some one can help me
I solved it adding a method in Adapter
public Shop getItem(int position) {
Shop shop = shopsList.get(Integer.valueOf(position));
return shop;
}
and then from Fragment adding the following
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (recyclerView.getScrollState() == recyclerView.SCROLL_STATE_IDLE)
{
int postitionCentereitem = carouselaLyoutManager.getCenterItemPosition();
Shop item = (Shop) mAdapter.getItem(postitionCentereitem);
int Id = item.getId();
String Address = item.getAddress();
lblMessage.setText(Address);
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
Hope this can help someone else.