RecyclerView Endless Scroll - java

I know there are lot of questions regarding the same problem but I am not able to find my issue. When I am printing URL in my HttpRequest Class, it's showing the right URL but its still loading the same data.
recyclerView.addOnScrollListener(new asd(manager ) {
boolean loading = false;
int scrollIndex = 1;
#Override
public void onScrolledToEnd() {
if(!loading){
loading = true;
try {
scrollIndex = scrollIndex+10;
String url = "https // xyz com?q=" + query + "&scrollIndex="+ scrollIndex + "&key=" + getResources().getString(R.string.api_key);
new HttpRequest(url,SearchActivity.this).execute();
adapter.notifyItemRangeChanged(list.size(),10);
adapter.notifyDataSetChanged();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
loading = false;
}
});
Here is OnScrollListener
public abstract class asd extends RecyclerView.OnScrollListener {
public static String TAG = asd.class.getSimpleName();
// use your LayoutManager instead
private LinearLayoutManager llm;
public asd(LinearLayoutManager sglm) {
this.llm = sglm;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1)) {
onScrolledToEnd();
}
}
public abstract void onScrolledToEnd();
}

I use this and it's working, maybe you have to play around a little with values to fit your specific case. However I hope it helps:
mRecyclerView.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);
LinearLayoutManager linearLayoutManager = ((LinearLayoutManager)mRecyclerView.getLayoutManager());
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
//Log.d(TAG,"Visible="+visibleItemCount+", total="+totalItemCount+", first="+firstVisibleItemPosition);
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
&& firstVisibleItemPosition >= 0
&& totalItemCount >= pageSize) {
//Log.d(TAG,"Entrato, lancio");
loadMoreItems();
}
}
});
Here pageSize is the number of the elements I'm loading every time; the loadMoreItems() method is responsible to fetch the data from the internet and notify the adapter.

Use this.
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager,maxCount) {
#Override
public void onLoadMore(int current_page) {
/// onLoadMore(current_page);
loadmoreContacts(current_page);
Log.e("onLoadMore ", "" + current_page);
}
});
Create new class
public abstract class EndlessRecyclerOnScrollListener extends
RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class
.getSimpleName();
int maxCount;
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(
LinearLayoutManager linearLayoutManager,int maxCount) {
this.mLinearLayoutManager = linearLayoutManager;
this.maxCount = maxCount;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if(totalItemCount>=maxCount){
loading=false;
return;
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);}

Related

RecyclerView's Items Position On The Screen Changes On The Run

I have this RecyclerView where any item can be clicked to open, and when it's opened, it grows (picture 1 is a closed item, picture 2 is an opened item)
The layout file of an item holds two states - the closed card, and the opened card. To switch between them, I change only the visibility of any state. Here are the methods that control an item's opening (expanding) or closing (shrinking) :
/**
* handles the expanding functionality.
*/
public void expand() {
shrink = true;
if (expandedItem != -1) {
notifyItemChanged(expandedItem);
}
expandedItem = getLayoutPosition();
toggleExpandShrinkIcon(true);
if (!openedFromParent[1]) {
openedFromParent[1] = true;
} else {
openedFromParent[0] = false;
}
expandedContainer.setVisibility(View.VISIBLE);
shrunkProgressBar.setVisibility(View.INVISIBLE);
}
/**
* handles the shrinking functionality.
*/
public void shrink() {
toggleExpandShrinkIcon(false);
expandedContainer.setVisibility(View.GONE);
shrunkProgressBar.setVisibility(View.VISIBLE);
shrink = false;
}
These methods are located in the RecyclerView's adapter, inside of the ViewHolder's class, and they are public so I could use them also out of the RecyclerView's adapter class (not only by clicking), as I did when one item hovers another.
Recently I added drag-to-hover functionality (using this library) so that I can drag any item on top of any other item, and when one item hovers another item, the lower item gets opened.
When an item gets opened, it pushes all the other items below it to be able to expand without hiding the items under it (like in the first video).
When moving from hovering one item to another, say from the second item to the third, when hovering the second item it gets opened and the third item is pushed down, and when moving to the third item the second item gets closed, but the third item won't go back up.
Then when hovering the third item, it gets opened on the fourth item (see the second video to understand better).
Here's the code in the class that handles the hovering action:
public class HoveringCallback extends ItemTouchHelper.SimpleCallback {
//re-used list for selecting a swap target
private List<RecyclerView.ViewHolder> swapTargets = new ArrayList<>();
//re used for for sorting swap targets
private List<Integer> distances = new ArrayList<>();
private float selectedStartX;
private float selectedStartY;
public interface OnDroppedListener {
void onDroppedOn(ActiveGoalsAdapter.ActiveGoalsViewHolder viewHolder, ActiveGoalsAdapter.ActiveGoalsViewHolder target);
}
private List<OnDroppedListener> onDroppedListeners = new ArrayList<>();
#Nullable
private RecyclerView recyclerView;
#Nullable
ActiveGoalsAdapter.ActiveGoalsViewHolder selected;
#Nullable
private ActiveGoalsAdapter.ActiveGoalsViewHolder hovered;
ItemBackgroundCallback backgroundCallback;
public HoveringCallback() {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
}
public void attachToRecyclerView(#Nullable RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
public void addOnDropListener(OnDroppedListener listener) {
onDroppedListeners.add(listener);
}
public void removeOnDropListener(OnDroppedListener listener) {
onDroppedListeners.remove(listener);
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (viewHolder == null) {
if (hovered != null) {
notifyDroppedOnListeners(hovered);
}
} else {
selectedStartX = viewHolder.itemView.getLeft();
selectedStartY = viewHolder.itemView.getTop();
}
this.selected = (ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder;
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder != null) {
viewHolder.itemView.setBackgroundColor(backgroundCallback.getDraggingBackgroundColor(viewHolder));
}
}
private void notifyDroppedOnListeners(ActiveGoalsAdapter.ActiveGoalsViewHolder holder) {
for (OnDroppedListener listener : onDroppedListeners) {
listener.onDroppedOn(selected, (ActiveGoalsAdapter.ActiveGoalsViewHolder) holder);
}
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(backgroundCallback.getDefaultBackgroundColor(viewHolder));
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
#Override
public void onChildDraw(Canvas canvas, RecyclerView parent, RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(canvas, parent, viewHolder, dX, dY, actionState, isCurrentlyActive);
if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) {
return;
}
if (recyclerView == null || selected == null) {
return;
}
final RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
final int childCount = lm.getChildCount();
List<RecyclerView.ViewHolder> swapTargets = findSwapTargets((ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder, dX, dY);
final int x = (int) (selectedStartX + dX);
final int y = (int) (selectedStartY + dY);
hovered = (ActiveGoalsAdapter.ActiveGoalsViewHolder) chooseDropTarget((ActiveGoalsAdapter.ActiveGoalsViewHolder) viewHolder, swapTargets, x, y);
if (hovered == null) {
this.swapTargets.clear();
this.distances.clear();
}
for (int i = 0; i < childCount; i++) {
final View child = lm.getChildAt(i);
if (viewHolder.itemView == child) {
continue;
}
ActiveGoalsAdapter.ActiveGoalsViewHolder childViewHolder = (ActiveGoalsAdapter.ActiveGoalsViewHolder) parent.findContainingViewHolder(child);
if (childViewHolder == null || childViewHolder.getAdapterPosition() == RecyclerView.NO_POSITION) {
continue;
}
final int count = canvas.save();
if (childViewHolder == hovered) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
childViewHolder.expand();
}
}, 500);
} else {
if(!childViewHolder.isShrunk()) {
childViewHolder.shrink();
if(canvas.getSaveCount() != count) {
canvas.restoreToCount(count);
}
}
}
}
}
private List<RecyclerView.ViewHolder> findSwapTargets(ActiveGoalsAdapter.ActiveGoalsViewHolder viewHolder, float dX, float dY) {
swapTargets.clear();
distances.clear();
final int margin = getBoundingBoxMargin();
final int left = Math.round(selectedStartX + dX) - margin;
final int top = Math.round(selectedStartY + dY) - margin;
final int right = left + viewHolder.itemView.getWidth() + 2 * margin;
final int bottom = top + viewHolder.itemView.getHeight() + 2 * margin;
final int centerX = (left + right) / 2;
final int centerY = (top + bottom) / 2;
final RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();
final int childCount = lm.getChildCount();
for (int i = 0; i < childCount; i++) {
View other = lm.getChildAt(i);
if (other == viewHolder.itemView) {
continue; //myself!
}
if (other.getBottom() < top || other.getTop() > bottom
|| other.getRight() < left || other.getLeft() > right) {
continue;
}
final ActiveGoalsAdapter.ActiveGoalsViewHolder otherVh = (ActiveGoalsAdapter.ActiveGoalsViewHolder) recyclerView.getChildViewHolder(other);
if (canDropOver(recyclerView, selected, otherVh)) {
// find the index to add
final int dx = Math.abs(centerX - (other.getLeft() + other.getRight()) / 2);
final int dy = Math.abs(centerY - (other.getTop() + other.getBottom()) / 2);
final int dist = dx * dx + dy * dy;
int pos = 0;
final int cnt = swapTargets.size();
for (int j = 0; j < cnt; j++) {
if (dist > distances.get(j)) {
pos++;
} else {
break;
}
}
swapTargets.add(pos, otherVh);
distances.add(pos, dist);
}
}
return swapTargets;
}
#Override
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
return 0.05f;
}
#Override
public RecyclerView.ViewHolder chooseDropTarget(RecyclerView.ViewHolder selected,
List<RecyclerView.ViewHolder> dropTargets,
int curX, int curY) {
int right = curX + selected.itemView.getWidth();
int bottom = curY + selected.itemView.getHeight();
ActiveGoalsAdapter.ActiveGoalsViewHolder winner = null;
int winnerScore = -1;
final int dx = curX - selected.itemView.getLeft();
final int dy = curY - selected.itemView.getTop();
final int targetsSize = dropTargets.size();
for (int i = 0; i < targetsSize; i++) {
final ActiveGoalsAdapter.ActiveGoalsViewHolder target = (ActiveGoalsAdapter.ActiveGoalsViewHolder) dropTargets.get(i);
if (dx > 0) {
int diff = target.itemView.getRight() - right;
if (diff < 0 && target.itemView.getRight() > selected.itemView.getRight()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
if (dx < 0) {
int diff = target.itemView.getLeft() - curX;
if (diff > 0 && target.itemView.getLeft() < selected.itemView.getLeft()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
if (dy < 0) {
int diff = target.itemView.getTop() - curY;
if (target.itemView.getTop() < selected.itemView.getTop()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
if (dy > 0) {
int diff = target.itemView.getBottom() - bottom;
if (target.itemView.getBottom() > selected.itemView.getBottom()) {
final int score = Math.abs(diff);
if (score > winnerScore) {
winnerScore = score;
winner = target;
}
}
}
}
return winner;
}
}
How can I solve this? (make the third item go back up, like when the drag is released, at the end of the second video)
Help would be highly appreciated! (:
First picture (closed item):
Second picture (opened item):
First Video (item gets opened & closed in the list):
Second video (item dragged):
Without studying the code of Library I assume positions are being changed so it is highly likely that .notifyItemChanged(position) is invoked, and in that, expand function invoke because there is no check to isolate the expand function from unhandled events
A simple answer can be to save the state and disable the expansion of items
Set isDragActive to true when where the item is long pressed
private static isDragActive = false
#Overrides
public onCreateViewHolder(){
itemView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int pos, long id) {
isDragActive = true;
return true;
}
});
}
public void expand() {
if(!isDragActive){
shrink = true;
if (expandedItem != -1) {
notifyItemChanged(expandedItem);
}
expandedItem = getLayoutPosition();
toggleExpandShrinkIcon(true);
if (!openedFromParent[1]) {
openedFromParent[1] = true;
} else {
openedFromParent[0] = false;
}
expandedContainer.setVisibility(View.VISIBLE);
shrunkProgressBar.setVisibility(View.INVISIBLE);
}
}
You can also use the library given below instead of above solution
https://github.com/mikepenz/FastAdapter
I think the best bet is to set your code that opens each recyclerview using ACTION_UP so that the code is triggered on the lifting of the finger, not on the sensing of it.
button.setOnTouchListener(new View.OnTouchListener() { #Override public boolean onTouch(View view, MotionEvent motionEvent) { sw
If(MotionEvent.ACTION_UP) {Toast.makeText(MainActivity.this, "Up", Toast.LENGTH_SHORT).show(); }

recyclerview returning same position on scroll

Hi everyone i am developing an app where i'm using recyclerview along with mapfragment. I have made a carousel with recyclerview and onscroll of recyclerview i'm trying to change the camera position according to LatLong of particular item now my problem is that when i scroll recyclerview each time it returns me the same position. I had implemented viewpager earlier and there i used onPageSelected method which worked fine but now as i have switched to recyclerview i'm having this issue.
I dont know where i'm going wrong
So please if someone can assist me here.
Thank You
MainActivity code
carousel_recycler = (RecyclerView)findViewById(R.id.carousel_recycler);
providers = new ArrayList<>();
manager = new CenterZoomLayoutManager(this, LinearLayoutManager.HORIZONTAL,false);
final int scrollPosition = manager.findFirstVisibleItemPosition();
carousel_recycler.setLayoutManager(manager);
carousel_recycler.setHasFixedSize(true);
place_data = getResources().getStringArray(R.array.nearby_place);
for(String places : place_data){
NearbyDataProvider nearbyDataProvider = new NearbyDataProvider(listItems[i],places,latitude[j],longitude[k]);
providers.add(nearbyDataProvider);
i++;
j++;
k++;
}
adapter = new CarouselRecycler_Adapter(providers);
carousel_recycler.setAdapter(adapter);
LinearSnapHelper snapHelper = new LinearSnapHelper(){
#Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
View centerView = findSnapView(layoutManager);
if (centerView == null)
return RecyclerView.NO_POSITION;
int position = layoutManager.getPosition(centerView);
int targetPosition = -1;
if (layoutManager.canScrollHorizontally()) {
if (velocityX < 0) {
targetPosition = position - 1;
} else {
targetPosition = position + 1;
}
}
if (layoutManager.canScrollVertically()) {
if (velocityY < 0) {
targetPosition = position - 1;
} else {
targetPosition = position + 1;
}
}
final int firstItem = 0;
final int lastItem = layoutManager.getItemCount() - 1;
targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));
return targetPosition;
}
};
snapHelper.attachToRecyclerView(carousel_recycler);
carousel_recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
index = newState;
if(providers.size()>0){
if(!providers.get(index).getLattitude().isEmpty()
&& !providers.get(index).getLongitude().isEmpty()){
double lat = Double.parseDouble(providers.get(index).getLattitude());
double lang = Double.parseDouble(providers.get(index).getLongitude());
changeCameraPosition(lat,lang);
}
else {
Toast.makeText(MapsMarkerActivity.this, "No last location found", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
/*index = scrollPosition;
if(providers.size()>0){
if(!providers.get(scrollPosition).getLattitude().isEmpty()
&& !providers.get(scrollPosition).getLongitude().isEmpty()){
double lat = Double.parseDouble(providers.get(scrollPosition).getLattitude());
double lang = Double.parseDouble(providers.get(scrollPosition).getLongitude());
changeCameraPosition(lat,lang);
}
else {
Toast.makeText(MapsMarkerActivity.this, "No last location found", Toast.LENGTH_SHORT).show();
}
}*/
}
});
}
Will this solve your problem?
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
try {
LinearLayoutManager layoutManager = ((LinearLayoutManager) rv.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
Log.e("refresh", "State - " + newState + " : firstVisiblePosition" + firstVisiblePosition);
} catch (Exception e) {
e.printStackTrace();
}
}
});

GridLayoutManager with EndlessRecyclerOnScrollListener recylerView.addOnScrollListener automatically scrolling in android

public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
// True if we are still waiting for the last set of data to load.
private int visibleThreshold = 0; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 0;
private GridLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(GridLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
Log.i("ProdctOffer load", mLinearLayoutManager.findLastCompletelyVisibleItemPosition() + "//" + ProductList.size() + "//" + loading);
if (mLinearLayoutManager.findLastCompletelyVisibleItemPosition() == ProductList.size() - 1 && loading) {
//bottom of list!
current_page++;
onLoadMore(current_page);
}
}
public abstract void onLoadMore(int current_page);
}

Android not getting getApplicationContext on service

When i using on touch listener. Inside the touch listener i have called a method. The method parameters want activity and view. When i using getApplicationContext() in my service it shows
Wrong 1st argument type. Found: 'android.content.Context', required: 'android.app.Activity'
My code is given below
MyService.java
chatHead.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = params.x;
initialY = params.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
startX = event.getX();
startY = event.getY();
return false;
case MotionEvent.ACTION_UP:
float endX = event.getX();
float endY = event.getY();
if (isAClick(startX, endX, startY, endY)) {
Log.d("LockView", "clicked2");
CircularAnim.fullActivity(getApplicationContext(), v)
.colorOrImageRes(R.color.color1)
.go(new CircularAnim.OnAnimationEndListener() {
#Override
public void onAnimationEnd() {
startActivity(new Intent(getApplicationContext(), BrowserActivity.class));
}
});
}
return true;
case MotionEvent.ACTION_MOVE:
params.x = initialX
+ (int) (event.getRawX() - initialTouchX);
params.y = initialY
+ (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(chatHead, params);
return false;
}
return true;
}
});
windowManager.addView(chatHead, params);
private boolean isAClick(float startX, float endX, float startY, float endY) {
float differenceX = Math.abs(startX - endX);
float differenceY = Math.abs(startY - endY);
if (differenceX > CLICK_ACTION_THRESHHOLD/* =5 */ || differenceY > CLICK_ACTION_THRESHHOLD) {
return false;
}
return true;
}
CircularAnim.java
public static FullActivityBuilder fullActivity(Activity activity, View triggerView) {
return new FullActivityBuilder(activity, triggerView);
}
public static void init(long perfectMills, long fullActivityPerfectMills, int colorOrImageRes) {
sPerfectMills = perfectMills;
sFullActivityPerfectMills = fullActivityPerfectMills;
sColorOrImageRes = colorOrImageRes;
}
The getApplicationContext() is getting in CircularAnim.fullActivity(MainActivity.this, view) but it is not in CircularAnim.fullActivity
How to solve problem of getApplicationContext in CircularAnim.fullActivity(getApplicationContext(), v)
Please help me.
Full code of CircularAnim
public class CircularAnim {
public static final long PERFECT_MILLS = 618;
public static final int MINI_RADIUS = 0;
private static Long sPerfectMills;
private static Long sFullActivityPerfectMills;
private static Integer sColorOrImageRes;
private static long getPerfectMills() {
if (sPerfectMills != null)
return sPerfectMills;
else
return PERFECT_MILLS;
}
private static long getFullActivityMills() {
if (sFullActivityPerfectMills != null)
return sFullActivityPerfectMills;
else
return PERFECT_MILLS;
}
private static int getColorOrImageRes() {
if (sColorOrImageRes != null)
return sColorOrImageRes;
else
return android.R.color.white;
}
public interface OnAnimationEndListener {
void onAnimationEnd();
}
#SuppressLint("NewApi")
public static class VisibleBuilder {
private View mAnimView, mTriggerView;
private Float mStartRadius, mEndRadius;
private long mDurationMills = getPerfectMills();
private boolean isShow;
private OnAnimationEndListener mOnAnimationEndListener;
public VisibleBuilder(View animView, boolean isShow) {
mAnimView = animView;
this.isShow = isShow;
if (isShow) {
mStartRadius = MINI_RADIUS + 0F;
} else {
mEndRadius = MINI_RADIUS + 0F;
}
}
public VisibleBuilder triggerView(View triggerView) {
mTriggerView = triggerView;
return this;
}
public VisibleBuilder startRadius(float startRadius) {
mStartRadius = startRadius;
return this;
}
public VisibleBuilder endRadius(float endRadius) {
mEndRadius = endRadius;
return this;
}
public VisibleBuilder duration(long durationMills) {
mDurationMills = durationMills;
return this;
}
#Deprecated //You can use method - go(OnAnimationEndListener onAnimationEndListener).
public VisibleBuilder onAnimationEndListener(OnAnimationEndListener onAnimationEndListener) {
mOnAnimationEndListener = onAnimationEndListener;
return this;
}
public void go() {
go(null);
}
public void go(OnAnimationEndListener onAnimationEndListener) {
mOnAnimationEndListener = onAnimationEndListener;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
doOnEnd();
return;
}
int rippleCX, rippleCY, maxRadius;
if (mTriggerView != null) {
int[] tvLocation = new int[2];
mTriggerView.getLocationInWindow(tvLocation);
final int tvCX = tvLocation[0] + mTriggerView.getWidth() / 2;
final int tvCY = tvLocation[1] + mTriggerView.getHeight() / 2;
int[] avLocation = new int[2];
mAnimView.getLocationInWindow(avLocation);
final int avLX = avLocation[0];
final int avTY = avLocation[1];
int triggerX = Math.max(avLX, tvCX);
triggerX = Math.min(triggerX, avLX + mAnimView.getWidth());
int triggerY = Math.max(avTY, tvCY);
triggerY = Math.min(triggerY, avTY + mAnimView.getHeight());
int avW = mAnimView.getWidth();
int avH = mAnimView.getHeight();
rippleCX = triggerX - avLX;
rippleCY = triggerY - avTY;
int maxW = Math.max(rippleCX, avW - rippleCX);
int maxH = Math.max(rippleCY, avH - rippleCY);
maxRadius = (int) Math.sqrt(maxW * maxW + maxH * maxH) + 1;
} else {
rippleCX = (mAnimView.getLeft() + mAnimView.getRight()) / 2;
rippleCY = (mAnimView.getTop() + mAnimView.getBottom()) / 2;
int w = mAnimView.getWidth();
int h = mAnimView.getHeight();
maxRadius = (int) Math.sqrt(w * w + h * h) + 1;
}
if (isShow && mEndRadius == null)
mEndRadius = maxRadius + 0F;
else if (!isShow && mStartRadius == null)
mStartRadius = maxRadius + 0F;
try {
Animator anim = ViewAnimationUtils.createCircularReveal(
mAnimView, rippleCX, rippleCY, mStartRadius, mEndRadius);
mAnimView.setVisibility(View.VISIBLE);
anim.setDuration(mDurationMills);
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
doOnEnd();
}
});
anim.start();
} catch (Exception e) {
e.printStackTrace();
doOnEnd();
}
}
private void doOnEnd() {
if (isShow)
mAnimView.setVisibility(View.VISIBLE);
else
mAnimView.setVisibility(View.INVISIBLE);
if (mOnAnimationEndListener != null)
mOnAnimationEndListener.onAnimationEnd();
}
}
#SuppressLint("NewApi")
public static class FullActivityBuilder {
private Activity mActivity;
private View mTriggerView;
private float mStartRadius = MINI_RADIUS;
private int mColorOrImageRes = getColorOrImageRes();
private Long mDurationMills;
private OnAnimationEndListener mOnAnimationEndListener;
private int mEnterAnim = android.R.anim.fade_in, mExitAnim = android.R.anim.fade_out;
public FullActivityBuilder(Activity activity, View triggerView) {
mActivity = activity;
mTriggerView = triggerView;
}
public FullActivityBuilder startRadius(float startRadius) {
mStartRadius = startRadius;
return this;
}
public FullActivityBuilder colorOrImageRes(int colorOrImageRes) {
mColorOrImageRes = colorOrImageRes;
return this;
}
public FullActivityBuilder duration(long durationMills) {
mDurationMills = durationMills;
return this;
}
public FullActivityBuilder overridePendingTransition(int enterAnim, int exitAnim) {
mEnterAnim = enterAnim;
mExitAnim = exitAnim;
return this;
}
public void go(OnAnimationEndListener onAnimationEndListener) {
mOnAnimationEndListener = onAnimationEndListener;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
doOnEnd();
return;
}
int[] location = new int[2];
mTriggerView.getLocationInWindow(location);
final int cx = location[0] + mTriggerView.getWidth() / 2;
final int cy = location[1] + mTriggerView.getHeight() / 2;
final ImageView view = new ImageView(mActivity);
view.setScaleType(ImageView.ScaleType.CENTER_CROP);
view.setImageResource(mColorOrImageRes);
final ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView();
int w = decorView.getWidth();
int h = decorView.getHeight();
decorView.addView(view, w, h);
int maxW = Math.max(cx, w - cx);
int maxH = Math.max(cy, h - cy);
final int finalRadius = (int) Math.sqrt(maxW * maxW + maxH * maxH) + 1;
try {
Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, mStartRadius, finalRadius);
int maxRadius = (int) Math.sqrt(w * w + h * h) + 1;
if (mDurationMills == null) {
double rate = 1d * finalRadius / maxRadius;
mDurationMills = (long) (getFullActivityMills() * Math.sqrt(rate));
}
final long finalDuration = mDurationMills;
anim.setDuration((long) (finalDuration * 0.9));
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
doOnEnd();
mActivity.overridePendingTransition(mEnterAnim, mExitAnim);
mTriggerView.postDelayed(new Runnable() {
#Override
public void run() {
if (mActivity.isFinishing()) return;
try {
Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy,
finalRadius, mStartRadius);
anim.setDuration(finalDuration);
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
try {
decorView.removeView(view);
} catch (Exception e) {
e.printStackTrace();
}
}
});
anim.start();
} catch (Exception e) {
e.printStackTrace();
try {
decorView.removeView(view);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}, 1000);
}
});
anim.start();
} catch (Exception e) {
e.printStackTrace();
doOnEnd();
}
}
private void doOnEnd() {
mOnAnimationEndListener.onAnimationEnd();
}
}
public static VisibleBuilder show(View animView) {
return new VisibleBuilder(animView, true);
}
public static VisibleBuilder hide(View animView) {
return new VisibleBuilder(animView, false);
}
public static FullActivityBuilder fullActivity(Activity activity, View triggerView) {
return new FullActivityBuilder(activity, triggerView);
}
public static void init(long perfectMills, long fullActivityPerfectMills, int colorOrImageRes) {
sPerfectMills = perfectMills;
sFullActivityPerfectMills = fullActivityPerfectMills;
sColorOrImageRes = colorOrImageRes;
}
}
Do it this way...
public class BaseService extends Service {
public Context mContext;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
} }
getApplicationContext() is Related to application and not to activity hence you should use activityname.this or getBaseContext() and you are trying to perform UI Thread operation using Application Context ,Activity UI related operation shold be perform using Activity Context ,not Application Context
If what you need is to access the Context of your activity from your service, another thing you can try to pass the Activity context in the constructor of the Service. For example:
Activity
public class BT_Client extends Activity{
private BtService mBTService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mBtService = new BtService(this, ...);
}
}
Service
public class BtService {
Context myActivityContext;
public BtService(Context context, ...) {
myActivityContext = context;
...
}
}

RecyclerView scrolled UP/DOWN listener

How do we know if user scrolled down or up in RecyclerView ?
I tried with RecyclerView#OnScrollListener , it gives the amount of vertical scroll and the scroll state. How do we get the last scroll position when started to dragging and scrolled position when scroll state idle.
The accepted answer works fine, but #MaciejPigulski gave more clear and neat solution in the comment below. I just putting it as an answer here. Here's my working code.
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
// Scrolling up
} else {
// Scrolling down
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
// Do something
} else if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
// Do something
} else {
// Do something
}
}
});
Try this way:
private static int firstVisibleInListview;
firstVisibleInListview = yourLayoutManager.findFirstVisibleItemPosition();
In your scroll listener:
public void onScrolled(RecyclerView recyclerView, int dx, int dy)
{
super.onScrolled(recyclerView, dx, dy);
int currentFirstVisible = yourLayoutManager.findFirstVisibleItemPosition();
if(currentFirstVisible > firstVisibleInListview)
Log.i("RecyclerView scrolled: ", "scroll up!");
else
Log.i("RecyclerView scrolled: ", "scroll down!");
firstVisibleInListview = currentFirstVisible;
}
I wanted to hide a layout if the recyclerview is scrolled down and then make it visible if the recyclerview is scrolled up. I did some thinking and came up with this logic.
Variable y is a global static int. Do not forget to declare y as static int y;
I hope it helps someone :)
mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(lLayout) {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// super.onScrolled(recyclerView, dx, dy);
y=dy;
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(mRecyclerView.SCROLL_STATE_DRAGGING==newState){
//fragProductLl.setVisibility(View.GONE);
}
if(mRecyclerView.SCROLL_STATE_IDLE==newState){
// fragProductLl.setVisibility(View.VISIBLE);
if(y<=0){
fragProductLl.setVisibility(View.VISIBLE);
}
else{
y=0;
fragProductLl.setVisibility(View.GONE);
}
}
}
});
Another simple solution that can detect scroll direction with the help of your adapter:
class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
int lastItemPosition = -1;
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (position > lastItemPosition) {
// Scrolled Down
}
else {
// Scrolled Up
}
lastItemPosition = position;
}
}
^ Helpful when doing item animations upon scrolling.
PS: This will tell you directions discontinuously until further onBindViewHolder calls.
this code work for me
private var nearmeListScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_SETTLING)
if (dy > 0) {
layout_vendros_list_header.hide()
layout_vendros_list_header.animate().translationY(1f)
} else if (dy < 0) {
layout_vendros_list_header.show()
layout_vendros_list_header.animate().translationY(0f)
}
}
}
```
There is my implementation of CustomRecyclerView with all type of scroll listeners
public class CustomRecyclerView extends RecyclerView
{
private boolean mIsScrolling;
private boolean mIsTouching;
private OnScrollListener mOnScrollListener;
private Runnable mScrollingRunnable;
private int y = 0;
public abstract static class OnScrollListener
{
void onScrollChanged(CustomRecyclerView RvView, int x, int y, int oldX, int oldY)
{
//if you need just override this method
}
void onEndScroll(CustomRecyclerView RvView)
{
//if you need just override this method
}
protected abstract void onGoUp();
protected abstract void onGoDown();
}
public CustomRecyclerView(final Context context)
{
super(context);
}
public CustomRecyclerView(final Context context, #Nullable final AttributeSet attrs)
{
super(context, attrs);
}
public CustomRecyclerView(final Context context, #Nullable final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public boolean dispatchTouchEvent(MotionEvent iEv)
{
if (isEnabled())
{
processEvent(iEv);
super.dispatchTouchEvent(iEv);
return true; //to keep receive event that follow down event
}
return super.dispatchTouchEvent(iEv);
}
private void processEvent(final MotionEvent iEv)
{
switch (iEv.getAction())
{
case MotionEvent.ACTION_DOWN:
y = (int) iEv.getY();
break;
case MotionEvent.ACTION_UP:
y = (int) iEv.getY();
if (mIsTouching && !mIsScrolling && mOnScrollListener != null)
{
mOnScrollListener.onEndScroll(this);
}
mIsTouching = false;
break;
case MotionEvent.ACTION_MOVE:
mIsTouching = true;
mIsScrolling = true;
int newY = (int) iEv.getY();
int difY = y - newY;
int MAX_VALUE = 200;
int MIN_VALUE = -200;
if (difY > MAX_VALUE)
{
if (mOnScrollListener != null)
{
mOnScrollListener.onGoDown();
}
y = newY;
}
else if (difY < MIN_VALUE)
{
if (mOnScrollListener != null)
{
mOnScrollListener.onGoUp();
}
y = newY;
}
break;
}
}
#Override
protected void onScrollChanged(int iX, int iY, int iOldX, int iOldY)
{
super.onScrollChanged(iX, iY, iOldX, iOldY);
if (Math.abs(iOldX - iX) > 0)
{
if (mScrollingRunnable != null)
{
removeCallbacks(mScrollingRunnable);
}
mScrollingRunnable = () ->
{
if (mIsScrolling && !mIsTouching && mOnScrollListener != null)
{
mOnScrollListener.onEndScroll(CustomRecyclerView.this);
}
mIsScrolling = false;
mScrollingRunnable = null;
};
postDelayed(mScrollingRunnable, 200);
}
if (mOnScrollListener != null)
{
mOnScrollListener.onScrollChanged(this, iX, iY, iOldX, iOldY);
}
}
public void scrollToView(final View iV)
{
// Get deepChild Offset
Point childOffset = new Point();
getDeepChildOffset(CustomRecyclerView.this, iV.getParent(), iV, childOffset);
// Scroll to child.
CustomRecyclerView.this.scrollToY(childOffset.y);
}
private void getDeepChildOffset(final ViewGroup mainParent, final ViewParent parent, final View child, final Point accumulatedOffset)
{
ViewGroup parentGroup = (ViewGroup) parent;
accumulatedOffset.x += child.getLeft();
accumulatedOffset.y += child.getTop();
if (parentGroup.equals(mainParent))
{
return;
}
getDeepChildOffset(mainParent, parentGroup.getParent(), parentGroup, accumulatedOffset);
}
public void scrollToY(final int iY)
{
CustomRecyclerView.this.postDelayed(() ->
{
int x = 0;
int y = iY;
ObjectAnimator xTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollX", x);
ObjectAnimator yTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollY", y);
AnimatorSet animators = new AnimatorSet();
animators.setDuration(500L);
animators.playTogether(xTranslate, yTranslate);
animators.addListener(new Animator.AnimatorListener()
{
#Override
public void onAnimationStart(Animator arg0)
{
// noting
}
#Override
public void onAnimationRepeat(Animator arg0)
{
// noting
}
#Override
public void onAnimationEnd(Animator arg0)
{
// noting
}
#Override
public void onAnimationCancel(Animator arg0)
{
// noting
}
});
animators.start();
}, 300);
}
public void scrollToTop()
{
scrollToY(0);
}
public void setOnRvScrollListener(OnScrollListener mOnEndScrollListener)
{
this.mOnScrollListener = mOnEndScrollListener;
}
}
And there is sample of usage
private void setRecyclerViewSettings()
{
mRv.setLayoutManager(new LinearLayoutManager(getActivity()));
mRv.setOnRvScrollListener(mScrollListener);
}
private CustomRecyclerView.OnScrollListener mScrollListener = new CustomRecyclerView.OnScrollListener()
{
#Override
protected void onGoUp()
{
AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
}
#Override
protected void onGoDown()
{
AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
}
};

Categories