Skip to content

Commit

Permalink
chore: onContentEndReached callback implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
azimgd committed May 21, 2024
1 parent a98fbf3 commit f72add1
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 20 deletions.
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,23 @@ import ShadowListContainer from 'shadowlist';
```

## API
| Prop | Type | Required | Description |
|----------------------------|--------------------------|----------|-------------------------------------------------|
| `data` | Array | Required | An array of data to be rendered in the list. |
| `contentContainerStyle` | ViewStyle | Optional | These styles will be applied to the scroll view content container which wraps all of the child views. |
| `ListHeaderComponent` | React component or null | Optional | A custom component to render at the top of the list. |
| `ListHeaderComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListHeaderComponent` |
| `ListFooterComponent` | React component or null | Optional | A custom component to render at the bottom of the list. |
| `ListFooterComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListFooterComponent` |
| `ListEmptyComponent` | React component or null | Optional | A custom component to render when the list is empty. |
| `ListEmptyComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListEmptyComponent` |
| `renderItem` | Function | Required | A function to render each item in the list. It receives an object with `item` and `index` properties. |
| `initialScrollIndex` | Number | Optional | The initial index of the item to scroll to when the list mounts. |
| `inverted` | Boolean | Optional | If true, the list will be rendered in an inverted order. |
| `horizontal` | Boolean | Optional | If true, renders items next to each other horizontally instead of stacked vertically. |
| Prop | Type | Required | Description |
|----------------------------|---------------------------|----------|-------------------------------------------------|
| `data` | Array | Required | An array of data to be rendered in the list. |
| `contentContainerStyle` | ViewStyle | Optional | These styles will be applied to the scroll view content container which wraps all of the child views. |
| `ListHeaderComponent` | React component or null | Optional | A custom component to render at the top of the list. |
| `ListHeaderComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListHeaderComponent` |
| `ListFooterComponent` | React component or null | Optional | A custom component to render at the bottom of the list. |
| `ListFooterComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListFooterComponent` |
| `ListEmptyComponent` | React component or null | Optional | A custom component to render when the list is empty. |
| `ListEmptyComponentStyle` | ViewStyle | Optional | Styling for internal View for `ListEmptyComponent` |
| `renderItem` | Function | Required | A function to render each item in the list. It receives an object with `item` and `index` properties. |
| `initialScrollIndex` | Number | Optional | The initial index of the item to scroll to when the list mounts. |
| `inverted` | Boolean | Optional | If true, the list will be rendered in an inverted order. |
| `horizontal` | Boolean | Optional | If true, renders items next to each other horizontally instead of stacked vertically. |
| `onBatchLayout` | `({ size: Int32 }) => void` | Optional | Called when a batch of layout calculations is complete. |
| `onEndReached` | `({ distanceFromEnd: Int32 }) => void` | Optional | Called when the end of the content is within `onEndReachedThreshold`. |
| `onEndReachedThreshold` | Double | Optional | The threshold (in content length units) at which `onEndReached` is triggered. |

## Methods
| Method | Type | Description |
Expand All @@ -78,3 +81,4 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
## License

MIT

Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ void ShadowListContainerEventEmitter::onBatchLayout(BatchLayout $event) const {
});
}

void ShadowListContainerEventEmitter::onEndReached(EndReached $event) const {
dispatchEvent("endReached", [$event = std::move($event)](jsi::Runtime &runtime) {
auto $payload = jsi::Object(runtime);
$payload.setProperty(runtime, "distanceFromEnd", $event.distanceFromEnd);
return $payload;
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ class ShadowListContainerEventEmitter : public ViewEventEmitter {
int size;
};

struct EndReached {
int distanceFromEnd;
};

void onVisibleChange(VisibleMetrics value) const;
void onBatchLayout(BatchLayout value) const;
void onEndReached(EndReached value) const;
};

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ ShadowListContainerProps::ShadowListContainerProps(
horizontal(convertRawProp(context, rawProps, "horizontal", sourceProps.horizontal, {false})),
hasListHeaderComponent(convertRawProp(context, rawProps, "hasListHeaderComponent", sourceProps.hasListHeaderComponent, {false})),
hasListFooterComponent(convertRawProp(context, rawProps, "hasListFooterComponent", sourceProps.hasListFooterComponent, {false})),
initialScrollIndex(convertRawProp(context, rawProps, "initialScrollIndex", sourceProps.initialScrollIndex, {0}))
initialScrollIndex(convertRawProp(context, rawProps, "initialScrollIndex", sourceProps.initialScrollIndex, {0})),
onEndReachedThreshold(convertRawProp(context, rawProps, "onEndReachedThreshold", sourceProps.onEndReachedThreshold, {0}))
{}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ShadowListContainerProps final : public ViewProps {
bool hasListHeaderComponent{false};
bool hasListFooterComponent{false};
int initialScrollIndex{0};
double onEndReachedThreshold{0};
};

}
17 changes: 17 additions & 0 deletions ios/ShadowListContainer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
const auto &props = static_cast<const ShadowListContainerProps &>(*_props);
const auto &eventEmitter = static_cast<const ShadowListContainerEventEmitter &>(*_eventEmitter);

auto distanceFromEnd = [self distanceFromEndRespectfully:props.onEndReachedThreshold];
if (distanceFromEnd > 0) {
eventEmitter.onEndReached({ distanceFromEnd = distanceFromEnd });
}

[self recycle];
}

Expand All @@ -123,6 +131,15 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
[self->_cachedComponentPool removeCachedComponentPoolItem:childComponentView poolIndex:index];
}

- (int)distanceFromEndRespectfully:(float)threshold {
auto visibleHeight = self->_scrollContainer.bounds.size.height;
auto contentHeight = self->_scrollContainer.contentSize.height;
auto offsetY = self->_scrollContainer.contentOffset.y;

auto triggerPoint = contentHeight - (threshold * visibleHeight);
return offsetY >= triggerPoint ? (int)(contentHeight - offsetY) : 0;
}

- (void)scrollRespectfully:(float)contentOffset animated:(BOOL)animated
{
if (self->_scrollContainerLayoutInverted) {
Expand Down
9 changes: 4 additions & 5 deletions src/ShadowListContainerNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ViewProps } from 'react-native';
import type {
Int32,
DirectEventHandler,
Double,
} from 'react-native/Libraries/Types/CodegenTypes';

export interface NativeProps extends ViewProps {
Expand All @@ -19,11 +20,9 @@ export interface NativeProps extends ViewProps {
end: Int32;
}>
>;
onBatchLayout?: DirectEventHandler<
Readonly<{
size: Int32;
}>
>;
onBatchLayout?: DirectEventHandler<Readonly<{ size: Int32 }>>;
onEndReached?: DirectEventHandler<Readonly<{ distanceFromEnd: Int32 }>>;
onEndReachedThreshold?: Double;
}

export interface NativeCommands {
Expand Down

0 comments on commit f72add1

Please sign in to comment.