Detect End of Scrollview

Detect end of ScrollView

Did it!

Aside of the fix Alexandre kindly provide me, I had to create an Interface:

public interface ScrollViewListener {
void onScrollChanged(ScrollViewExt scrollView,
int x, int y, int oldx, int oldy);
}

Then, i had to override the OnScrollChanged method from ScrollView in my ScrollViewExt:

public class ScrollViewExt extends ScrollView {
private ScrollViewListener scrollViewListener = null;
public ScrollViewExt(Context context) {
super(context);
}

public ScrollViewExt(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public ScrollViewExt(Context context, AttributeSet attrs) {
super(context, attrs);
}

public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
}
}
}

Now, as Alexandre said, put the package name in the XML tag (my fault), make my Activity class implement the interface created before, and then, put it all together:

scroll = (ScrollViewExt) findViewById(R.id.scrollView1);
scroll.setScrollViewListener(this);

And in the method OnScrollChanged, from the interface...

@Override
public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) {
// We take the last son in the scrollview
View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1);
int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));

// if diff is zero, then the bottom has been reached
if (diff == 0) {
// do stuff
}
}

And it worked!

Thank you very much for your help, Alexandre!

I want to detect the end of scroll event

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.

Detect ScrollView has reached the end

I did it like this:

import React from 'react';
import {ScrollView, Text} from 'react-native';

const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};

const MyCoolScrollViewComponent = ({enableSomeButton}) => (
<ScrollView
onScroll={({nativeEvent}) => {
if (isCloseToBottom(nativeEvent)) {
enableSomeButton();
}
}}
scrollEventThrottle={400}
>
<Text>Here is very long lorem ipsum or something...</Text>
</ScrollView>
);

export default MyCoolScrollViewComponent;

I wanted to add paddingToBottom because usually it is not needed that ScrollView is scrolled to the bottom till last pixel. But if you want that set paddingToBottom to zero.

How do I detect when User has reached the bottom of the ScrollView?

Wrap your whole ScrollView in your ChildSizeReader, so you can get the height of the ScrollView itself.

Because the offset starts at zero at the top, when at the bottom of the scroll view the end isn't at the top of the screen, but rather the bottom. This difference is the height of the scroll view. This means the ScrollView starts at offset 0 and goes to total content height - scroll view height.

Code:

struct ContentView: View {
let spaceName = "scroll"

@State var wholeSize: CGSize = .zero
@State var scrollViewSize: CGSize = .zero

var body: some View {
ChildSizeReader(size: $wholeSize) {
ScrollView {
ChildSizeReader(size: $scrollViewSize) {
VStack {
ForEach(0..<100) { i in
Text("\(i)")
}
}
.background(
GeometryReader { proxy in
Color.clear.preference(
key: ViewOffsetKey.self,
value: -1 * proxy.frame(in: .named(spaceName)).origin.y
)
}
)
.onPreferenceChange(
ViewOffsetKey.self,
perform: { value in
print("offset: \(value)") // offset: 1270.3333333333333 when User has reached the bottom
print("height: \(scrollViewSize.height)") // height: 2033.3333333333333

if value >= scrollViewSize.height - wholeSize.height {
print("User has reached the bottom of the ScrollView.")
} else {
print("not reached.")
}
}
)
}
}
.coordinateSpace(name: spaceName)
}
.onChange(
of: scrollViewSize,
perform: { value in
print(value)
}
)
}
}

Note your already existing scrollViewSize variable is the content's size, not the scroll view's size.

Also notice that I changed the == to >= - this is so you don't have to be exactly at the height, can be over-scrolled where it rubber-bands back.

How to determine end of the scrollView React Native

Okay, after some digging I found

Detect ScrollView has reached the end

It is working like a charm.

How do I know that the scrollview is already scrolled to the bottom?

I found a way to make it work. I needed to check the measured height of the child to the ScrollView, in this case a LinearLayout. I use the <= because it also should do something when scrolling isn't necessary. I.e. when the LinearLayout is not as high as the ScrollView. In those cases getScrollY is always 0.

ScrollView scrollView = (ScrollView) findViewById(R.id.ScrollView);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.LinearLayout);
if(linearLayout.getMeasuredHeight() <= scrollView.getScrollY() +
scrollView.getHeight()) {
//do something
}
else {
//do nothing
}

Detect scroll end event when calling scrollTo on ScrollView

Try this solution, i've modified your snack

I've used onSroll listener with the function :

 const scrollDirection = (event) => {
const offsetX = event.nativeEvent.contentOffset.x
const dif = offsetX - (offset || 0);
console.log('dif',dif)
if (dif == 200) {
alert('destination reached')
}

setOffset(offsetX);

};

SwiftUI - Detect when ScrollView has finished scrolling?

Here is a demo of possible approach - use publisher with changed scrolled content coordinates with debounce, so event reported only after coordinates stopped changing.

Tested with Xcode 12.1 / iOS 14.1

UPDATE: verified as worked with Xcode 13.3 / iOS 15.4

Note: you can play with debounce period to tune it for your needs.

demo

import Combine

struct ContentView: View {
let detector: CurrentValueSubject<CGFloat, Never>
let publisher: AnyPublisher<CGFloat, Never>

init() {
let detector = CurrentValueSubject<CGFloat, Never>(0)
self.publisher = detector
.debounce(for: .seconds(0.2), scheduler: DispatchQueue.main)
.dropFirst()
.eraseToAnyPublisher()
self.detector = detector
}

var body: some View {
ScrollView {
VStack(spacing: 20) {
ForEach(0...100, id: \.self) { i in
Rectangle()
.frame(width: 200, height: 100)
.foregroundColor(.green)
.overlay(Text("\(i)"))
}
}
.frame(maxWidth: .infinity)
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self,
value: -$0.frame(in: .named("scroll")).origin.y)
})
.onPreferenceChange(ViewOffsetKey.self) { detector.send($0) }
}.coordinateSpace(name: "scroll")
.onReceive(publisher) {
print("Stopped on: \($0)")
}
}
}

struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}



Related Topics



Leave a reply



Submit