Direction of scroll RecyclerView - java

Can I detect the direction of scroll when I add the on scroll listener to my recycler view?
The code is as follows:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (recyclerView.getScrollState()) {
case RecyclerView.SCROLL_STATE_DRAGGING :
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) relativeBaseLayout.getLayoutParams();
if(layoutParams.weight < 1.0f) {
SlideAnimation slideAnimation = new SlideAnimation(layoutParams.weight, 1.0f, relativeBaseLayout);
slideAnimation.setDuration(250);
relativeBaseLayout.startAnimation(slideAnimation);
}
break;
default:
break;
}
}
});
I want this function to work only if I scroll down.
Currently it'll work on both scroll up and down. What changes do I make?
I do not want to implement the onScrolled() method since that will be called after the scroll has finished. I want to detect it during the scroll.
What am I missing here?

Related

How to drag a RecyclerView (or ALL of its items) horizontally?

I have a RecyclerView in Android Studio with items within it, and instead of swiping horizontally to a new activity, I'd like to swipe left/right, have the entire RecyclerView (or all of its items, either way, since the overall effect would appear similar) move with my finger. Once the items (or RecyclerView) leave the screen at a threshold (for example, 50%), then I'd like to initiate an animation of new items sliding in.
So far, I have the animation for the items sliding in but cannot:
Get all items or the entire RecyclerView to be dragged by by finger
Once that's accomplished, calculate the percentage of the items/view is offscreen to invoke a function.
Thanks in advance
EDIT:
In my main activity, I already have an onTouchListener to register swiping and each of my items are clickable, but I want to be able to "animate" the items moving left offscreen when I swipe left
An example of my code:
public class MainActivity extends AppCompatActivity {
// Set up layout and such...
...
Recyclerview recyclerview = findViewById(R.id.mRecyclerview);
// Set layout manager and adapter...
...
recyclerview.setOnTouchListener(new SwipeListener(MainActivity.this) {
#Override
public void onSwipeRight() {
super.OnSwipeRight();
swipeRightAnimation();
}
#Override
public void onSwipeLeft() {...}
...
});
/* How do I animate items moving left when swiping right and vice versa?
Inside of SwipeListener? By implementing a new listener? */
}
EDIT2:
I tried this (acting on the parent layout instead of the RecyclerView), but the overall view seems to grow/shrink symmetrically rather than move left or right, any suggestions?
public class HorizontalDragListener implements View.OnTouchListener {
private Context context;
private int x;
private int dXLeft;
private int dXRight;
private DrawerLayout.LayoutParams layoutParams;
public HorizontalDragListener(Context context) {
this.context = context;
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// Get position information
x = (int) motionEvent.getRawX();
y = (int) motionEvent.getRawY();
// Detect movements
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case (MotionEvent.ACTION_DOWN): {
layoutParams = (DrawerLayout.LayoutParams) view.getLayoutParams();
dXLeft = x - layoutParams.leftMargin;
dXRight = layoutParams.rightMargin - x;
break;
}
case (MotionEvent.ACTION_MOVE): {
// move object
layoutParams = (DrawerLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = x - dXLeft;
layoutParams.rightMargin = x + dXRight;
view.setLayoutParams(layoutParams);
break;
}
}
// Update view
view.invalidate();
return true;
}
}

Check when smoothScrollToPosition has finished

I would like to check when smoothScrollToPosition has finished scrolling back to the first item of recyclerview. I tried doing it like this which only works while smoothScrollToPosition is still scrolling:
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(), 0);
if (!recyclerView.getLayoutManager().isSmoothScrolling()) {
Log.d(TAG, "Scrolling has ended.");
}
I use onScrollStateChanged(RecyclerView recyclerView, int newState) method for tracking scrolling state. The method to initiate scroll looks like this:
private void scrollToPosition(int position){
recyclerView.removeOnScrollListener(onScrollListener);
recyclerView.addOnScrollListener(onScrollListener);
recyclerView.smoothScrollToPosition(position);
}
And here is the listener:
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case SCROLL_STATE_IDLE:
//we reached the target position
recyclerView.removeOnScrollListener(this);
break;
}
}
};
So, when recyclerView reaches SCROLL_STATE_IDLE, that means it has finished scrolling. Don't forget to remove listener in this state, so it won't trigger on the next scroll.
There is a listener for it:
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnScrollListener
void onScrolled (RecyclerView recyclerView,
int dx,
int dy)
Callback method to be invoked when the RecyclerView has been scrolled. This will be called after the scroll has completed.

Drag and drop scrolling in a linear layout

I'm currently working on an app that allows users to add a relative layout, linear layout, or nested linear layout within a linear layout, which is a child of a scroll view. The scrolling seems to work fine when just the relative layout or linear layout is added, however, once the nested linear layout is added, the scrolling becomes a problem. Basically, I want the scroll view to start scrolling once my dragged view comes within x amount of the top/bottom of the screen. Any advice? Below is some of my code to help
protected class myDragEventListener implements View.OnDragListener {
// This is the method that the system calls when it dispatches a drag event to the listener.
public boolean onDrag(View v, DragEvent event) {
// Defines a variable to store the action type for the incoming event
final int action = event.getAction();
Point touchPosition = getTouchPositionFromDragEvent(v, event);
Log.d("y", String.format("%s", String.format("%s", eventTouchYCoord)));
//View dragView = (View) event.getLocalState();
// Handles each of the expected events
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_ENTERED:
return true;
case DragEvent.ACTION_DRAG_LOCATION:
Log.d("point", touchPosition.toString());
if (touchPosition.y > (absoluteBottom + mScrollDistance - 350)){
Log.d("bottom", "greater");
Log.d("actionbar", String.format("%s", actionBarHeight()));
homeScroll.scrollBy(0, 30);
}
if (touchPosition.y < (actionBarHeight + 350)){
Log.d("top", "greater");
homeScroll.scrollBy(0, -30);
}
break;
getTouchPositionFromDragEvent Method
public static Point getTouchPositionFromDragEvent(View item, DragEvent event) {
Rect rItem = new Rect();
item.getGlobalVisibleRect(rItem);
return new Point(rItem.left + Math.round(event.getX()), rItem.top + Math.round(event.getY()));
}
onScrollChangedListener Method
homeScroll.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
mScrollDistance = homeScroll.getScrollY();
int[] coords = new int[2];
homeScroll.getLocationOnScreen(coords);
absoluteTop = coords[1];
absoluteBottom = coords[1] + homeScroll.getHeight();
}
});
Its always best practice to implement scrolling attribute in xml file. This that you want scroll in side it. or in Palette you will find scrollview option of vertical and horizontal scrolling.. just drag and drop to where you want place it.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ScrollView>

get an item only after scroll function finish

I am working with Navigation menu view and I am scrolling it programmatically and then get a Y position of its item.
But the code that get the item positions is running immediately after the list (using the layout manager) starts to scroll and when it haven't finished to scroll and change the positions yet.
How can I do the rest of code after "scrollToPositionWithOffset" wait the end of the scroll action to run?
Here's my code:
RecyclerView recyclerView = (RecyclerView) navigationView.getChildAt(0);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
layoutManager.scrollToPositionWithOffset(4, 0);
//it should wait the line above run completely to can run too
mImage.animate().y(navView.getChildAt(4).getY());
You should use a scroll listener that listens for the Scrolling state to change to idle.. See below.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
mImage.animate().y(navView.getChildAt(4).getY());
recyclerView.removeOnScrollListener(this);
}
}
}
layoutManager.scrollToPositionWithOffset(4, 0);
On researching i found this :
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
#Override
public void onLayoutChildren(final Recycler recycler, final State state) {
super.onLayoutChildren(recycler, state);
//TODO if the items are filtered, considered hiding the fast scroller here
final int firstVisibleItemPosition = findFirstVisibleItemPosition();
if (firstVisibleItemPosition != 0) {
// this avoids trying to handle un-needed calls
if (firstVisibleItemPosition == -1)
//not initialized, or no items shown, so hide fast-scroller
mFastScroller.setVisibility(View.GONE);
return;
}
final int lastVisibleItemPosition = findLastVisibleItemPosition();
int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
//if all items are shown, hide the fast-scroller
mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
}
};
The good thing here is that it works well and will handle even keyboard being shown/hidden.
The bad thing is that it gets called on cases that aren't interesting (meaning it has false positives), but it's not as often as scrolling events, so it's good enough for me.

Android OnGestureListener issues when view contains a listview

Im having some issues with the Android onGestureListener, I have 3 Linear Layouts sitting next to each other horizontally in a Linear Layout, the Linear Layout position is set to the middle Layout onCreate, the middle layout also contains a listview inside of it, what I would like to happen is when I swipe left or right the layout moves, this seems to not pick up the gestures when I attempt to swipe left or right on the Linear Layout with the listview inside of it, but if I swipe right or left on the other views that dont have anything in them it picks up the gesture and the view animates accordingly, has anyone had this issue before or have an idea how to fix it? any help will go a long way thanks
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return gestureDetector.onTouchEvent(event);
}
SimpleOnGestureListener simpleOnGestureListener = new SimpleOnGestureListener() {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float sensitvity = 50;
if ((e1.getX() - e2.getX()) > sensitvity) {
slideLeft();
} else if ((e2.getX() - e1.getX()) > sensitvity) {
slideRight();
}
return true;
}
};
private void slideRight() {
if (swipeDirection > -1) {
if (swipeDirection == 0) {
layoutContainer.animate().translationX(theDistance - 0)
.setDuration(500);
} else {
//go to home
layoutContainer.animate().translationX(0).setDuration(500);
}
swipeDirection--;
}
}
private void slideLeft() {
if (swipeDirection < 1) {
if (swipeDirection == 0) {
layoutContainer.animate().translationX(0 - theDistance)
.setDuration(500);
} else {
layoutContainer.animate().translationX(0).setDuration(500);
}
swipeDirection++;
}
}
The ListView itself has a gesture listener built in already (for scrolling the list), and possibly it also has an onItemClickListener on the individual items in the list. It can be that this interferes with your swipe behavior of the whole layout.
The solution explained here by Pinhassi has worked best for me so far:
Android Swipe on List
probably you will need to expand on the onItemClickListener of your ListView and include the swipe detector mentioned above. Also, putting #Override in front of the line where you declare the onItemClick might be needed to override the listview listeners. That way, you will maintain clickable list items and you can perform swipes on them.

Categories