How to reset the background buttons (swipe menu) of the recyclerview programmatically? - java

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;
}
}

Related

The last item in the recyclerView list

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
}
}
});

ItemTouchHelper not being applied to every View in Adapter

In implementing swipe-to-delete functionality I accidentally made my forground view of the viewholder transparent. In doing so I've uncovered a bug with my ItemTouchHandler not changing the background or hiding the text when it is supposed to.
It appears to me that my ItemTouchHelper is not being applied to every view in my ReycleViewAdapter and/or the views are not being updated or they all share a single parent of some sort, after many hours of attempted debugging I'm at my wit's end, I've included a handy gif of the issue.
The ItemTouchHelper's onDrawChild() and onDrawChildOver() methods are passed to my fragment in order to handle the actions
Code:
AllLists_fragment.java:
public class showAllLists_fragment extends android.support.v4.app.Fragment implements RecycleItemTouchHelper.RecyclerItemTouchHelperListener {
private static final String TAG = "showAllLists";
private RecyclerView mAllItemsView = null;
private DataCommunication mData = null;
private ItemTouchHelper.SimpleCallback itemTouchHelper = null;;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.show_all_lists_frag, container, false);
this.mAllItemsView = (RecyclerView) view.findViewById(R.id.allItems);
this.itemTouchHelper = new RecycleItemTouchHelper(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, this);
new ItemTouchHelper(this.itemTouchHelper).attachToRecyclerView(this.mAllItemsView);
this.mAllItemsView.setAdapter(this.mData.getAdapter());
this.mAllItemsView.setLayoutManager(new LinearLayoutManager(getActivity()){
//
#Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
Log.d(TAG, "Inconsistent Exception Caught -See stack trace");
e.printStackTrace();
}
}
});
viewShadow();
return view;
}
#TargetApi(21)
public void viewShadow(){
this.mAllItemsView.setTranslationZ(100);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
this.mData = (DataCommunication) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement DataCommunication");
}
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
this.mData.getAdapter().notifyDataSetChanged();
this.mData.refresh();
}
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position) {
int noSwipeSize = mData.getAllToDo().size();
if (direction == ItemTouchHelper.LEFT) {
mData.deleteTask(mData.getAdapter().getResults().get(viewHolder.getAdapterPosition()));
mData.getAdapter().notifyItemRangeRemoved(viewHolder.getAdapterPosition(), noSwipeSize);
} else if (direction == ItemTouchHelper.RIGHT) {
mData.completeTask(mData.getAdapter().getResults().get(viewHolder.getAdapterPosition()));
mData.getAdapter().notifyItemRangeRemoved(viewHolder.getAdapterPosition(), noSwipeSize);
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((com.lab1.ac01220.bloomv2.ViewHolder) viewHolder).getForeground();
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
if(dX < 0){
this.mData.getViewHolder().getDeleteText().setVisibility(View.VISIBLE);
this.mData.getViewHolder().getCompleteText().setVisibility(View.INVISIBLE);
this.mData.getViewHolder().getBackground().setBackgroundColor(getResources().getColor(R.color.colorAccent));
} else if(dX >0){
this.mData.getViewHolder().getCompleteText().setVisibility(View.VISIBLE);
this.mData.getViewHolder().getDeleteText().setVisibility(View.INVISIBLE);
this.mData.getViewHolder().getBackground().setBackgroundColor(getResources().getColor(R.color.colorComplete));
}
}
ItemTouchHelper.SimpleCallback.getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,actionState, isCurrentlyActive);
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((com.lab1.ac01220.bloomv2.ViewHolder) viewHolder).getForeground();
ItemTouchHelper.SimpleCallback.getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,actionState, isCurrentlyActive);
}
}
RecycleitemTouchHelper.java
public RecycleItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
super(dragDirs, swipeDirs);
this.listener = listener;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
this.listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
this.listener.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
this.listener.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final View foregroundView = ((ViewHolder) viewHolder).getForeground();
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive);
void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive);
}
}
RecycleViewAdapter.java:
public class RecycleViewAdapter extends RecyclerView.Adapter<ViewHolder>{
private LayoutInflater inflater = null;
private List<GlobalLists> results = null;
private DataCommunication mData = null;
public RecycleViewAdapter(Context context, List<GlobalLists> results){
this.inflater = LayoutInflater.from(context);
this.results = results;
this.mData = (DataCommunication)context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_row, parent, false);
ViewHolder holder = new ViewHolder(view);
this.mData.setViewHolder(holder);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
GlobalLists item = this.results.get(position);
holder.setRowTitle(item.getTitle());
//Grab the first 14 characters of the contents if the row is not null
if(item.getContents() != null){
StringBuffer currentContent = new StringBuffer(item.getContents().substring(0, Math.min(item.getContents().length(),28)));
if(item.getContents().length() > 28) currentContent.append("...");
holder.setRowContent(currentContent.toString());
}
}
public void reloadAdapterData(List<GlobalLists> refresh){
this.results = refresh;
}
#Override
public int getItemCount() {
return this.results == null || this.results.isEmpty() ? 0 : this.results.size();
}
public List<GlobalLists> getResults(){
return this.results;
}
}
The problem was that I was simply setting the first ViewHolder to be a global variable and only anacting changes on that. Instead I should have been getting the current View being draw in onChildDraw and performing functions on that:
Was:
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((com.lab1.ac01220.bloomv2.ViewHolder) viewHolder).getForeground();
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
if(dX < 0){
this.mData.getViewHolder().getDeleteText().setVisibility(View.VISIBLE);
this.mData.getViewHolder().getCompleteText().setVisibility(View.INVISIBLE);
this.mData.getViewHolder().getBackground().setBackgroundColor(getResources().getColor(R.color.colorAccent));
} else if(dX >0){
this.mData.getViewHolder().getCompleteText().setVisibility(View.VISIBLE);
this.mData.getViewHolder().getDeleteText().setVisibility(View.INVISIBLE);
this.mData.getViewHolder().getBackground().setBackgroundColor(getResources().getColor(R.color.colorComplete));
}
}
ItemTouchHelper.SimpleCallback.getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,actionState, isCurrentlyActive);
}
Should be:
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
com.lab1.ac01220.bloomv2.ViewHolder current = (com.lab1.ac01220.bloomv2.ViewHolder) viewHolder;
final View foregroundView = ((com.lab1.ac01220.bloomv2.ViewHolder) viewHolder).getForeground();
if (isCurrentlyActive) {
if(dX < 0){
current.getDeleteText().setVisibility(View.VISIBLE);
current.getCompleteText().setVisibility(View.INVISIBLE);
current.getBackground().setBackground(getResources().getDrawable(R.drawable.ic_rounded_rectangle_accent));
} else if(dX >0){
current.getCompleteText().setVisibility(View.VISIBLE);
current.getDeleteText().setVisibility(View.INVISIBLE);
current.getBackground().setBackground(getResources().getDrawable(R.drawable.ic_rounded_rectangle_complete));
}
}
ItemTouchHelper.SimpleCallback.getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,actionState, isCurrentlyActive);
}

Doing Paint.SetColor() gradually with ValueAnimator leads to strange results

I want to set the Paint color gradually but it doesn't work the way it's supposed to. The paint color only changes if the item is selected by the user and is moving. Otherwise, the paint color doesn't change. What is causing this?
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ACTION_STATE_SWIPE) {
if (optionsState == OptionState.UPVOTE) {
drawUpvoteOption(c, viewHolder.itemView, dX);
} else if (optionsState == OptionState.DOWNVOTE) {
if (!isRightSwipeMaxed(dX)) drawDownvoteOption(c, viewHolder.itemView, dX);
else drawDownvoteOption(c, viewHolder.itemView, MAX_RIGHT_SWIPE);
}
setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
if (dX == 0) {
optionsState = OptionState.NONE;
}
if (!isRightSwipeMaxed(dX)) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
} else {
super.onChildDraw(c, recyclerView, viewHolder, MAX_RIGHT_SWIPE, dY, actionState, isCurrentlyActive);
}
}
private void drawDownvoteOption(Canvas c, View itemView, float dX) {
rightRect.set(itemView.getRight() + dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
setRightPaintColorAnimate(Color.RED);
c.drawRect(rightRect, rightPaint);
drawText("DOWNVOTE", c, rightRect, rightPaint);
}
private void setRightPaintColorAnimate(int targetColor) {
ValueAnimator colorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), rightPaint.getColor(), targetColor);
colorAnimator.setInterpolator(new LinearInterpolator());
colorAnimator.setRepeatCount(ValueAnimator.INFINITE);
colorAnimator.setDuration(300);
colorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//This only works if the item is currently moving
rightPaint.setColor((int) valueAnimator.getAnimatedValue());
}
});
colorAnimator.start();
}

Hard task - Detect when scrolling from RecyclerViewAdapter no Fragment or activity

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.

Found when user keep scrolling when is in the top, Android

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...
}
}
});

Categories