I'm reading Cards - Material design. I'd like to implement swipe gesture in my layout, but I'm facing some problems with this.
This is the effect I want to get.
The problem with my current implementation with ItemTouchHelper is that the item is always completely removed from the layout, I do not want that to happen, as in the video above I would like to allow the layout to be swiped to the direct in the maximum 30% of the entire width of the screen, if the user drops it before it, I'd like it to back up so that the layout goes back to its default position (without being partially moved to the side) and if the user reaches 30% of the screen, to perform an action (such as saving the item to watch later) and returning the item to its initial 0% position.
Whatsapp does something very similar to what I want to have, when swiped right a message, you can respod the message.
This is my code
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;
RecyclerView recyclerView;
public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener, RecyclerView recyclerView) {
super(dragDirs, swipeDirs);
this.listener = listener;
this.recyclerView = recyclerView;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Log.i("waeaweaweaeawe", "onMove");
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
Log.i("waeaweaweaeawe", "onSelectedChanged");
if (viewHolder != null) {
final View foregroundView = ((clv_exibirPosts.ViewHolder) viewHolder).container_post;
getDefaultUIUtil().onSelected(foregroundView);
}
}
#Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
Log.i("waeaweaweaeawe", "clearView");
final View foregroundView = ((clv_exibirPosts.ViewHolder) viewHolder).container_post;
getDefaultUIUtil().clearView(foregroundView);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
Log.i("waeaweaweaeawe", "onSwiped");
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
Log.i("waeaweaweaeawe", "convertToAbsoluteDirection");
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
public interface RecyclerItemTouchHelperListener {
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
}
}
I have no idea how to set a maximum distance that swipe gesture can be dragged. I found this in stackOverflow, this makes me able to make the layout not completely exit the screen
super.onChildDraw(c, recyclerView, viewHolder, dX / 2, dY, actionState, isCurrentlyActive);
But a few problems here.
1 - Swipe speed is slow.
2 - When swiped to 50% of the entire width allowed to swiped, the object continues with its position changed, keeping it in its maximum allowable position (I want the item to always return to 0% after reaching 50% of swiped allowed.)
I've looked all over the internet and found no examples that talk about it. I'm sure this problem is not just mine. If you can give me some clues, examples of codes, posts, anything that might help I'll already be extremely grateful!
I think this library is what you need https://github.com/yanzhenjie/SwipeRecyclerView
In case you want to implement it yourself, have a look at the code of the library itself.
Related
Using LayoutManager.findFirstCompletelyVisibleItemPosition(); I’m trying to zoom-in when the element is fully visible and zoom-out when it becomes partially/completely invisible. Scrolling over an object that is still visible completely slowly, the object position number is repeated several times along with the animation on the already animated object or in animation. My problem then is, stop this repetition and make the animation correct and unique. This is what I tried to do:
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
Animation scale_in = AnimationUtils.loadAnimation(recyclerView.getContext(), R.anim.scale_in_tv);
Animation scale_out = AnimationUtils.loadAnimation(recyclerView.getContext(), R.anim.scale_out_tv);
scale_in.setFillAfter(true);
//scale_out.setFillAfter(true);
int firstCompletelyVisible = layoutManager.findFirstCompletelyVisibleItemPosition();
int lastCompletelyVisible = layoutManager.findLastCompletelyVisibleItemPosition();
int before = -1;
View firstComp = layoutManager.findViewByPosition(firstCompletelyVisible);
View lastComp = layoutManager.findViewByPosition(lastCompletelyVisible);
if(firstComp != null && before != firstCompletelyVisible) {
before = firstCompletelyVisible;
firstComp.startAnimation(scale_out);
}
There is such issue, I have horizontal RecyclerView where each cell less than width of screen.
So I found a solution here
RecyclerVIew auto scroll to display all the elements as in News Feed etc.,
All work excellent if one cell take whole width of the screen otherwise(if each cell take 95% of screen width) every auto swipe place the cell at the beginner of screen (right side) and it is logical. So at the end of one visible cell it is start of another cell
it is doesn't looks good. I need this cell to be at the middle of the screen like this.
I need to see previous cell - current - next one
Now I would like to explain some magic how I make current smooth scroll (as I mentioned at link above)
this method in my CustomLinnearLayoutManager
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext())
{
#Override
public PointF computeScrollVectorForPosition(int targetPosition)
{
return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
{
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
But this method works without offset
I found out one more method that can provide desired offset
scrollToPositionWithOffset(final int position, final int offset)
And it is looks like exactly what I need , but this method works without smooth animation.
So, eventually my question is : how to apply animation logic from first method to second (that with offset)
Feel free to ask
To auto snapping and showing one item at center of RecyclerView, simply you need to use LinearSnapHelper like following:
LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
If you want to scroll to a specific item programmatically, LinearSnapHelper handles snapping functionality too.
SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
#Override
protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_ANY;
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 120f / displayMetrics.densityDpi;
}
};
...
smoothScroller.setTargetPosition(position);
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
Here is the visual result:
.
..................Manually Scrolling...........................Programmatically Scrolling..........
Eventually, I found the way thanks a lot to #aminography for his answer and also one more answer help me a lot
https://stackoverflow.com/a/39654328
Actually now I have such implementation
My custom LinnearLayoutManager implementation
public class SmoothLayoutManager extends LinearLayoutManager
{
public static final int X_25 = 25;
public static final int X_200 = 200;
public static final float DEFAULT = X_25;
/**
* !! IMPORTANT !!
* If you need to add new value, don't forget add it here also
*/
#Retention(RetentionPolicy.SOURCE)
#IntDef({X_25, X_200})
private #interface Speed
{
}
private static float MILLISECONDS_PER_INCH = DEFAULT;
public SmoothLayoutManager(Context context)
{
super(context);
}
public SmoothLayoutManager(Context context, int orientation, boolean reverseLayout)
{
super(context, orientation, reverseLayout);
}
public SmoothLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
}
public SmoothLayoutManager setSpeedOfSmooth(#Speed int iSpeed)
{
MILLISECONDS_PER_INCH = iSpeed;
return this;
}
#Override
public void scrollToPositionWithOffset(final int position, final int offset)
{
super.scrollToPositionWithOffset(position, offset);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext())
{
#Override
public PointF computeScrollVectorForPosition(int targetPosition)
{
return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected int getVerticalSnapPreference()
{
return LinearSmoothScroller.SNAP_TO_ANY;
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
{
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
#Override
public int calculateDtToFit(final int viewStart, final int viewEnd, final int boxStart, final int boxEnd, final int snapPreference)
{
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
}
And this is how I make set
private void setRv(Context iC)
{
RecyclerView.Adapter adapter = new UpSaleInnerAdapter(mPicasso, mInflater, iLink -> mListener.onButtonClick(iLink));
mRv.setLayoutManager(new SmoothLayoutManager(iC, LinearLayoutManager.HORIZONTAL, false).setSpeedOfSmooth(SmoothLayoutManager.X_200));
mRv.setAdapter(adapter);
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(mRv);
}
Note :
I noticed that sometimes if you make fast swipe, so SnapHelper a little bit confused and pass more cells that need... like a turbo mode :)
If someone will find how to fix it, let me know.
Thanks!
I have a RealmRecyclerViewAdapter that listens to a query in realm, and I've Implemented a drag and drop functionality on it using the ItemTouchHelper.
private final ItemTouchHelper.Callback _ithCallback = new ItemTouchHelper.Callback() {
private int fromPosition;
private int toPosition;
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if (viewHolder.getItemViewType() != target.getItemViewType()) {
return false;
}
toPosition = target.getAdapterPosition();
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder.getItemViewType() == TaskListRecyclerViewAdapter.FOOTER) {
return 0;
} else {
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
}
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
fromPosition = viewHolder.getAdapterPosition();
toPosition = viewHolder.getAdapterPosition();
} else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE
&& fromPosition != toPosition) {
// adapter.onDetachedFromRecyclerView(mRecyclerView);
dragAndDropManager.executeDragAndDrop(liveRealm, store.getStoreUid(), fromPosition, toPosition);
...
...
// adapter.onAttachedToRecyclerView(mRecyclerView);
}
}
};
To indicate the movement, whenever I drag an item over another Item, I call the adapter's notifyItemMoved method:
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
and whenever the user releases the item he dragged, I commit the changes to the realm DB:
dragAndDropManager.executeDragAndDrop(liveRealm, store.getStoreUid(), fromPosition, toPosition);
the problem is - whenever I release the item I've dragged, the animation appears to be working as if I haven't dropped the item in its location, but as if the item starts moving from its original location to the location in which I've dropped it.
I understand that this happens because I've committed the changes to Realm and as such the change is notified in the adapter, but the animation looks buggy.
I've tried calling
adapter.onDetachedFromRecyclerView(mRecyclerView);
and
adapter.onAttachedToRecyclerView(mRecyclerView);
to remove and add the listener to the adapter but it seems to be unreliable.
Is there a better solution for this issue?
Michael - did you ever get this working to your satisfaction?
I just ran across your post, having the same issue. I'm using the local Java DB version of Realm and after reviewing several examples that show similar techniques for implementing drag and drop with the stock recyclerView (generally they are all using an array of strings as the data model, NOT something like a live DB such as Realm) here is my experience - what I saw as issues with the "standard" techniques and how I resolved them:
Issues To Resolve
Issue 1: Custom Callback class forwards large numbers of onMove events
The various examples I found (like this one here) always utilize a
custom class that extends ItemTouchHelper.Callback. This classes typically defines
an interface that is in turn implemented by the adapter. Then this class overrides
onMove()/onSwiped from the Callback to call the onViewMoved()/onViewSwiped() method of the interface implemented by the adapter:
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
contract.onViewMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
In the onViewMoved() implementation that is in the adapter, the examples typically update the data source, then call notifyItemMoved():
public void onViewMoved(int oldPosition, int newPosition) {
User targetUser = usersList.get(oldPosition);
User user = new User(targetUser);
usersList.remove(oldPosition);
usersList.add(newPosition, user);
notifyItemMoved(oldPosition, newPosition);
}
In the example above, the data model is a simple ArrayList of "User" objects.
The problem I found with this when using Realm is that in the Callback onMove() gets called a lot as the user drags, which
given what is happening in the standard interface implementation would cause a huge amount of DB
writes.
Issue 2: The drag animation stops as soon as a single row change is detected
I noticed that as I was dragging the top row of the recyclerview down, as soon as it reached the very next row the animation stopped. Why? It is because as you found out the base class RealmRecyclerViewAdapter automatically updates itself when it gets notifications that the data model has changed, and this update apparently triggers the ItemTouchHelper to stop the animation.
To solve these two issues, I did the following:
Like the examples I found, I extended ItemTouchHelper.Callback into my own class. I utilize some variables to keep track of whether I have dragged over a new target or not:
public class RecyclerViewSwipeAndDragHelper extends ItemTouchHelper.Callback {
private SwipeAndDraggable implementor;
private static final int POSITION_UNKNOWN = -1;
private int oldPosition = POSITION_UNKNOWN;
private int newPosition = POSITION_UNKNOWN;
And similar to the example, in this class I define the interface that will be used by my adapter:
public interface SwipeAndDraggable {
void onViewMoved(int oldPosition, int newPosition);
void onViewSwiped(int position);
void onClearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder);
}
I added the onClearView() method in this interface to what is typically shown in the examples, more on how that is used in a moment.
To solve the first issue, I needed to consolidate all the onMove() callbacks into only a single call into my adapter. Fortunately, ItemTouchHelper already does a lot of this work for us. A return value of TRUE from onMove() will trigger a follow-up call to onMoved(). Returning FALSE does not. So, in my Callback implementation when I override onMove(), I don't call the implementer of the interface. Instead, I only keep track of whether or not I've dragged over the same target position, so that it only returns TRUE the first time I hit a new target (and I also noticed through testing the sometimes I would get an initial -1 value for viewHolder.getAdapterPosition(), so I test for that as well):
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
oldPosition = viewHolder.getAdapterPosition();
if ( oldPosition > POSITION_UNKNOWN) {
if ( newPosition != target.getAdapterPosition() ) {
newPosition = target.getAdapterPosition();
return true;
}
}
return false;
}
Only when onMove() returns TRUE is onMoved() in the Callback subsequently called. It is in that method that I call my implementation of onViewMoved():
#Override
public void onMoved(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, int fromPos, #NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
implementor.onViewMoved(fromPos, toPos);
}
That is how I solved the first issue of needing to consolidate all the onMove() callbacks into a single update. I only get a call a single time now as the user drags over individual viewholders.
As to the second issue - like you I have disabled the data listening in the RealmRecyclerView. I used the technique in the article to utilize an image in my viewholder to instigate the drag (in my case, it is a thumbnail image representing the individual entry in the recyclerview). This is done as the last step in the onBindViewHolder() method:
holder.getMediaImageView().setOnTouchListener((View view, MotionEvent motionEvent) -> {
if (motionEvent.getAction()== MotionEvent.ACTION_DOWN) {
// Turn off the data change listener within the RealmRecyclerViewAdapter superclass, so that
// when we make changes via the drag it doesn't automatically update - we will handle that manually
onDetachedFromRecyclerView(mMediaRecyclerView);
mItemTouchHelper.startDrag(holder);
}
return false;
});
Now when my onViewMoved() method is called, I can adjust the data model manually and notify the adapter:
public void onViewMoved(int oldPosition, int newPosition) {
Timber.d("Recognized a movement to a new position: old position, new position is: %d, %d", oldPosition, newPosition);
MediaDataMgr.get().moveMediaInPlaylist(oldPosition, newPosition, mPlaylist.getId());
// RealmRecyclerViewAdapter is no longer automatically notified when underlying data changes, so need to make notify()* calls here
notifyItemMoved(oldPosition, newPosition);
}
MediaDataManager is a class I wrote that consolidates all my Realm access. Here is that method as an example of how I do this (as well as the technique of insuring I'm calling Realm from the same thread I am currently on):
public void moveMediaInPlaylist(int from, int to, String playlistId) {
boolean success = false;
boolean mainThread = Thread.currentThread().equals(Looper.getMainLooper().getThread());
Realm realm = null;
if (mainThread) {
realm = mUIThreadRealm;
} else {
realm = Realm.getDefaultInstance();
}
try {
Playlist p = getPlaylist(playlistId);
if ( p== null) {
throw new Exception("Error retrieving playlist with ID: "+ playlistId );
}
realm.beginTransaction();
p.getMediaList().move(from, to);
success = true;
} catch (Exception e) {
Timber.d( "Exception deleting a Media in Playlist: %s", e.getMessage());
success = false;
} finally {
if ( success ) {
realm.commitTransaction();
} else {
realm.cancelTransaction();
}
if (!mainThread) {
realm.close();
}
}
}
Then when clearView() is called in the Callback, I forward this to the adapter via the interface definition. In Callback:
public void clearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
oldPosition = POSITION_UNKNOWN;
newPosition = POSITION_UNKNOWN;
implementor.onClearView(recyclerView, viewHolder);
}
And in adapter implementation of the interface I use this to re-attach the data listener:
public void onClearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
// reset RealmRecyclerViewAdapter data listener
onAttachedToRecyclerView(mMediaRecyclerView);
}
Now I am able to get a smooth looking animation, updating the DB in real time only once as items are dragged down the recyclerview using Realm:
I have successfully implemented the on scroll toolbar Hide/Show but i am stuck at onTouch Hide/Show toolbar. i have researched many related questions but nothing works for me. I want my toolbar to hide when user touches on screen and again shows when the screen is touched again, please help
I am using Android Studio
below is my OnScrollListener java class
this.mrecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
int mLastFirstVisibleItem = 0;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final int currentFirstVisibleItem = layout.findFirstVisibleItemPosition();
if (currentFirstVisibleItem > this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().hide();
} else if (currentFirstVisibleItem < this.mLastFirstVisibleItem) {
HomePage.this.getSupportActionBar().show();
}
this.mLastFirstVisibleItem = currentFirstVisibleItem;
}
});
Updated
mrecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
ActionBar actionBar = getSupportActionBar();
if(actionBar.isShowing()) {
actionBar.hide();
} else
actionBar.show();
return false;
}
});
this code works, but the problem now is that whenever i touch the screen it shows the toolbar and when i pick up my finger it hide itself, and as i am using RecyclerView it is getting difficult to scroll with all that showing and hiding. please help to make it stable so that if i touch once it stays shown and on another touch it hides itself.
here you go. This should work :)
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (actionBar.isShowing()) {
actionBar.hide();
} else {
actionBar.show();
}
return true;
} else return false;
}
});
Use onTouchListener to your root layout. And write your code inside callback.
I am trying to implement an animation on the views which is basically behind my RecyclerView. I am using ItemTouchHelper.SimpleCallback class to get the motion events on RecyclerView and overriding the callback method onChildDraw() to propagate the animation.
This animation is basically controlled by user swipe gestures. So here is my problem.
I have a RecyclerView with a email content on a card view. There are two images on the left and right side of the screen below that card view. It is something like this shown in the image inside this link:
CardView inside a RecyclerView with left and right images behind card view
Initially, Red and Pink images are invisible and will be animated on the amount of swipe on the white cardview. Now when I swipe on the white card view to the left and right hand side, the images in red and pink will be shown up by scale, alpha animation. Scale animation starts from 0.8 and alpha animation starts from 0 to 255. When these two animation finishes the Red and Pink images will be translated towards the direction of the swipe.
Here is my code:
public class ViewItemTouchHelperCallback extends ItemTouchHelper.SimpleCallback {
private Context mContext;
private OnViewSwipedListener mOnSwipeListener;
public interface OnViewSwipedListener {
void onViewSwiped(float dX);
}
public FocusViewItemTouchHelperCallback(int dragDirs, int swipeDirs, Context context, OnViewSwipedListener listener) {
super(dragDirs, swipeDirs);
this.mContext = context;
this.mOnSwipeListener = listener;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
if(mContext instanceof ViewActivity) {
if(viewHolder != null) {
WebView webView = ((ViewAdapter.MailObjectHolder) viewHolder).webViewBody;
if(webView != null) {
webView.clearView();
webView.loadUrl(Constants.ABOUT_BLANK);
if(swipeDir == ItemTouchHelper.LEFT) {
((ViewActivity) mContext).onSwipedLeft();
} else if(swipeDir == ItemTouchHelper.RIGHT) {
((ViewActivity) mContext).onSwipedRight();
}
}
}
}
}
#Override
public void onChildDraw(Canvas canvas, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
if(mOnSwipeListener != null) {
mOnSwipeListener.onViewSwiped(dX);
}
super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
}
Below is my activity code where I get the callbacks from the above class:
#Override
public void onViewSwiped(float dX) {
if(dX == 0) {
mFlagEmailIcon.setVisibility(View.INVISIBLE);
mNextEmailIcon.setVisibility(View.INVISIBLE);
} else if(dX > 0) {
//Left to right - flag email
float swipedWidth = Math.abs(dX) / mFlagEmailIcon.getMeasuredWidth();
if(swipedWidth >= 1) {
LogUtils.log(TAG, "Left to right dX = " + dX + "and Swiped width = " + swipedWidth);
mFlagEmailIcon.setVisibility(View.VISIBLE);
float scaleChange = Math.scalb(Math.abs(dX) / mFlagEmailIcon.getMeasuredWidth(), 1);
if(scaleChange >= 0.8 && scaleChange <= 1) {
mFlagEmailIcon.animate().scaleX(scaleChange).scaleY(scaleChange);
}
mFlagEmailIcon.animate().alpha(scaleChange);
} else {
}
} else {
//Right to left - next email
float swipedWidth = Math.abs(dX) / mNextEmailIcon.getMeasuredWidth();
if(swipedWidth >= 1) {
LogUtils.log(TAG, "Right to left dX = " + dX + "and Swiped width = " + swipedWidth);
mNextEmailIcon.setVisibility(View.VISIBLE);
float scaleChange = Math.scalb(Math.abs(dX) / mNextEmailIcon.getMeasuredWidth(), 1);
if(scaleChange >= 0.8 && scaleChange <= 1) {
mNextEmailIcon.animate().scaleX(scaleChange).scaleY(scaleChange);
}
mNextEmailIcon.animate().alpha(scaleChange);
} else {
}
}
}
In the above code, I am trying to animate the Red and Pink image based on the amount of user swipe on the white card view. But I am really stuck in the calculation based on "dX" and can't figure out how to calculate the values for animation.
Note:- When user swipes left to right on the card then Red image
should be animated and when user swipes right to left on the card then
Pink image should be animated. Animation will contain scale and alpha
animation initially and when both animation finishes the Red or Pink
image will start translating towards the direction of the swipe.
Can anyone help me to calculate the animation values based on user swipe. If you have any query related to this question, please ask. I am really stucked in this problem and there is no solution for this anywhere on the web.
Any help will be appreciated. Thanks in advance.