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.
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
How to Use Scrollview in Android
How to Check If My Edittext Fields Are Empty
How to Use "Share Image Using" Sharing Intent to Share Images in Android
Android Drawing Separator/Divider Line in Layout
Disable Scrolling in All Mobile Devices
How to Pass Arraylist<Customeobject> from One Activity to Another
Put Constant Text Inside Edittext Which Should Be Non-Editable - Android
Clear the Entire History Stack and Start a New Activity on Android
Taking Picture from Camera Without Preview
How to Add a Button Dynamically in Android
Set Icon For Android Application
Android Chrome Ignoring -Webkit-Text-Size-Adjust:None Property. Text Is Being Scaled When Zoomed Out
How to Connect to More Than One Firebase Database from an Android App