I need to check the direction of the scroll when my listview is scroll up or down, I am getting it as:
int lastVisibleItem = 0;
boolean isScrollingDown = false;
void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > lastVisibleItem) {
isScrollingDown = true;
Log.e("logkey","down");
}
else {
Log.e("logkey","up");
isScrollingDown = false;
}
lastVisibleItem = firstVisibleItem;
}
The problem is when the visible items are equal to the screen or when there are items to the whole screen suppose that only 6 items fit in the screen and the last item is half visible, the log cat starts showing me the both down and up at the same time!
In simple words, in the above case, the scroll direction is ambiguous to get when there are items equal to the screen to fit in and the very last item is half visible and when I scroll I am getting this problem!
Can somebody please tell me what I am doing wrong? Thanks in advance!
Implement the listview ScrollListener
listview.setOnScrollListener(new OnScrollListener() {
private int LastVisibleItem;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(LastVisibleItem<firstVisibleItem){
Log.d("Tag","Scroll down");
}
if(LastVisibleItem>firstVisibleItem){
Log.d("Tag","Scroll up");
}
LastVisibleItem=firstVisibleItem;
}
});
So luckily i found something great on the GitHub! I have changed my simple native ListView to Observable List View listed here
https://github.com/ksoichiro/Android-ObservableScrollView
and it worked like a charm, as i want to work it as!
Related
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!
This question already has answers here:
Detect end of ScrollView
(13 answers)
Closed 4 years ago.
I want to detect the end of scroll event of a scrollView.
first,i implement the OnCrollChange method and i try to listen some values if they can help me to know the end of scroll.
Thank to help me.
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener(){
#Override
public void onScrollChange(View view, int i, int i1, int i2, int i3){
Toast.makeText(getApplicationContext(),"in SCroll ------->"+i+" "+i1+" "+i2+" "+i3,Toast.LENGTH_SHORT).show();
shadowView.setBackgroundResource(R.drawable.shadow);
if ((i3==0)){
Toast.makeText(getApplicationContext()," equality ----------------------> ",Toast.LENGTH_SHORT).show();
shadowView.setBackgroundResource(R.drawable.trans);
}
else {
// Toast.makeText(getApplicationContext()," NO ----------------------> ",Toast.LENGTH_SHORT).show();
}
}
});
This will help
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
if (scrollView != null) {
if (scrollView.getChildAt(0).getBottom() <= (scrollView.getHeight() + scrollView.getScrollY())) {
//scroll view is at bottom
} else {
//scroll view is not at bottom
}
}
}
});
Modify your onScrollChanged method as below
#Override
public void onScrollChanged(View view, int i, int i1, int i2, int i3){
View view = (View) getChildAt(getChildCount()-1);
int delta = (view.getBottom()-(getHeight()+getScrollY()));
if(delta == 0){
// You have reached bottom of the scroll view
}
}
Thank to all of you.
after some testes;i see that the values int i, int i1, int i2 take the same value egual to 0 at the real time so it solve my problem.
I will not use your suggestions now but i learn some important notion from them only by reading.
Is it possible to check if a ScrollView is scrolled all its way in the top?
I want to check this so I can enable a SwipeRefreshLayout, otherwise keeping it disabled.
With a ListView it could be done like this, but there's no setOnScrollListener for ScrollViews
listView.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
boolean enable = false;
if(listView != null && listView.getChildCount() > 0){
// check if the first item of the list is visible
boolean firstItemVisible = listView.getFirstVisiblePosition() == 0;
// check if the top of the first item is visible
boolean topOfFirstItemVisible = listView.getChildAt(0).getTop() == 0;
// enabling or disabling the refresh layout
enable = firstItemVisible && topOfFirstItemVisible;
}
swipeRefreshLayout.setEnabled(enable);
}
});
This link might be helpful to You. It shows, how to set scroll listener for ScrollView. Then, refer to #antonio answer.
For your case it would be:
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = mScrollView.getScrollY(); //for verticalScrollView
if (scrollY == 0)
swipeRefresh.setEnabled(true);
else
swipeRefresh.setEnabled(false);
}
});
You can use the getScrollY() method (from the View class)
In Kotlin:
scrollView.viewTreeObserver.addOnScrollChangedListener {
if (!scrollView.canScrollVertically(1)) {
// Bottom of scroll view.
}
if (!scrollView.canScrollVertically(-1)) {
// Top of scroll view.
}
}
When you remember a good tutorial for checkBoxes please let me know!
You're getting the State using:
boolean selected = checkBox.isChecked();
Then you can add the OnLayoutChangeListener on your View Object.
Example Usage:
View.addOnLayoutChangeListener(new OnLayoutChangeListener(){
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom){
boolean selected = ((CheckBox)v.findViewById(R.id.yourCheckBoxID)).isChecked();
//saveTheStateHere
}
});
i have this in my activity:
mylistCodelist.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
try {
if (codeAction == 1) {
if (Schedario.returnNewListCode().size() == 1) {
Schedario.returnListDimensionList()
.get(Schedario.parentPosition)
.setChecked(false);
} else {
Schedario.returnListDimensionList()
.get(Schedario.parentPosition)
.setChecked(true);
}
Schedario.returnNewListCode().get(position)
.setChecked(true);
}
synchronized (view) {
view.notifyAll();
}
I want that when I click on an item, the list is updated in the adapter.
I also tried to add this:
synchronized (mylistCodelist) {
mylistCodelist.notifyAll();
}
but does not work.
how can I solve this problem?
Thanks in advance
You need to call adapter.notifyDatasetChanged(). This will update your list view when new data has arrived.
What I grasp from your question is that when the button is clicked, you want your list to be updated based on some criteria, right?