Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make pager controlled #693

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on:
pull_request:
branches:
- master
- next
push:
branches:
- master
- next

concurrency:
group: ${{ github.ref }}-js
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ For advanced usage please take a look into our [example project](https://github.

| Prop | Description | Platform |
| -------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------: |
| `page: number` | Index of page to be displayed | both |
| `animated: boolean` | Should transition between pages be animated | both |
| `initialPage` | Index of initial page that should be selected | both |
| `scrollEnabled: boolean` | Should pager view scroll, when scroll enabled | both |
| `onPageScroll: (e: PageScrollEvent) => void` | Executed when transitioning between pages (ether because the animation for the requested page has changed or when the user is swiping/dragging between pages) | both |
Expand All @@ -184,8 +186,8 @@ For advanced usage please take a look into our [example project](https://github.

| Method | Description | Platform |
| ------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------: |
| `setPage(index: number)` | Function to scroll to a specific page in the PagerView. Invalid index is ignored. | both |
| `setPageWithoutAnimation(index: number)` | Function to scroll to a specific page in the PagerView. Invalid index is ignored. | both |
| `setPage(index: number)` | Function to scroll to a specific page in the PagerView. Invalid index is ignored. The recommended way is using the `page` and `animated` props | both |
krozniata marked this conversation as resolved.
Show resolved Hide resolved
| `setPageWithoutAnimation(index: number)` | Function to scroll to a specific page in the PagerView. Invalid index is ignored. The recommended way is using the `page` and `animated` props | both |
| `setScrollEnabled(scrollEnabled: boolean)` | A helper function to enable/disable scroll imperatively. The recommended way is using the scrollEnabled prop, however, there might be a case where a imperative solution is more useful (e.g. for not blocking an animation) | both |

## Contributing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
return PagerViewViewManagerImpl.needsCustomLayoutForChildren()
}

@ReactProp(name = "page")
override fun setPage(view: NestedScrollableHost?, value: Int) {
goTo(view, value, PagerViewViewManagerImpl.animated)
}

@ReactProp(name = "animated", defaultBoolean = true)
override fun setAnimated(view: NestedScrollableHost?, value: Boolean) {
PagerViewViewManagerImpl.animated = value
}

@ReactProp(name = "scrollEnabled", defaultBoolean = true)
override fun setScrollEnabled(view: NestedScrollableHost?, value: Boolean) {
if (view != null) {
Expand Down Expand Up @@ -181,7 +191,7 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
}
}

override fun setPage(view: NestedScrollableHost?, selectedPage: Int) {
override fun setPageWithAnimation(view: NestedScrollableHost?, selectedPage: Int) {
goTo(view, selectedPage, true)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import com.facebook.react.uimanager.PixelUtil
object PagerViewViewManagerImpl {
const val NAME = "RNCViewPager"

var animated = true
krozniata marked this conversation as resolved.
Show resolved Hide resolved

fun getViewPager(view: NestedScrollableHost): ViewPager2 {
if (view.getChildAt(0) is ViewPager2) {
return view.getChildAt(0) as ViewPager2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,25 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>() {
return PagerViewViewManagerImpl.needsCustomLayoutForChildren()
}

@ReactProp(name = "page")
fun setPage(host: NestedScrollableHost, pageIndex: Int) {
val view = PagerViewViewManagerImpl.getViewPager(host)
Assertions.assertNotNull(view)
Assertions.assertNotNull(pageIndex)
val childCount = view.adapter?.itemCount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val childCount = view.adapter?.itemCount
val childCount = view.adapter?.itemCount ?: -1

val animated = PagerViewViewManagerImpl.animated
val canScroll = childCount != null && childCount > 0 && pageIndex >= 0 && pageIndex < childCount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val canScroll = childCount != null && childCount > 0 && pageIndex >= 0 && pageIndex < childCount
val canScroll = childCount > 0 && pageIndex >= 0 && pageIndex < childCount

if (canScroll) {
PagerViewViewManagerImpl.setCurrentItem(view, pageIndex, animated)
eventDispatcher.dispatchEvent(PageSelectedEvent(host.id, pageIndex))
}
}

@ReactProp(name = "animated", defaultBoolean = true)
fun setAnimated(host: NestedScrollableHost, value: Boolean) {
PagerViewViewManagerImpl.animated = value
}

@ReactProp(name = "scrollEnabled", defaultBoolean = true)
fun setScrollEnabled(host: NestedScrollableHost, value: Boolean) {
PagerViewViewManagerImpl.setScrollEnabled(host, value)
Expand Down Expand Up @@ -165,7 +184,7 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>() {
}

companion object {
private const val COMMAND_SET_PAGE = "setPage"
private const val COMMAND_SET_PAGE = "setPageWithAnimation"
private const val COMMAND_SET_PAGE_WITHOUT_ANIMATION = "setPageWithoutAnimation"
private const val COMMAND_SET_SCROLL_ENABLED = "setScrollEnabledImperatively"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "RNCViewPagerShadowNode.h"
#include <react/renderer/core/ConcreteComponentDescriptor.h>

namespace facebook {
namespace react {

using RNCViewPagerComponentDescriptor = ConcreteComponentDescriptor<RNCViewPagerShadowNode>;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "RNCViewPagerShadowNode.h"

#include <react/debug/react_native_assert.h>
#include <react/renderer/core/LayoutMetrics.h>

namespace facebook {
namespace react {

const char RNCViewPagerComponentName[] = "RNCViewPager";

void RNCViewPagerShadowNode::updateStateIfNeeded() {
ensureUnsealed();

auto contentBoundingRect = Rect{};
for (const auto &childNode : getLayoutableChildNodes()) {
contentBoundingRect.unionInPlace(childNode->getLayoutMetrics().frame);
}

auto state = getStateData();

if (state.contentBoundingRect != contentBoundingRect) {
state.contentBoundingRect = contentBoundingRect;
setStateData(std::move(state));
}
}

#pragma mark - LayoutableShadowNode

void RNCViewPagerShadowNode::layout(LayoutContext layoutContext) {
ConcreteViewShadowNode::layout(layoutContext);
updateStateIfNeeded();
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <react/renderer/components/RNCViewPager/EventEmitters.h>
#include <react/renderer/components/RNCViewPager/Props.h>
#include <react/renderer/components/RNCViewPager/RNCViewPagerState.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/core/LayoutContext.h>

namespace facebook {
namespace react {

extern const char RNCViewPagerComponentName[];

class RNCViewPagerShadowNode final : public ConcreteViewShadowNode<
RNCViewPagerComponentName,
RNCViewPagerProps,
RNCViewPagerEventEmitter,
RNCViewPagerState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;

#pragma mark - LayoutableShadowNode

void layout(LayoutContext layoutContext) override;

private:
void updateStateIfNeeded();
};

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "RNCViewPagerState.h"

namespace facebook {
namespace react {

Size RNCViewPagerState::getContentSize() const {
return contentBoundingRect.size;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <react/renderer/graphics/Geometry.h>

namespace facebook {
namespace react {

class RNCViewPagerState final {
public:
Point contentOffset;
Rect contentBoundingRect;

Size getContentSize() const;

};

}
}
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ PODS:
- React-jsinspector (0.70.5)
- React-logger (0.70.5):
- glog
- react-native-pager-view (6.1.1):
- react-native-pager-view (6.1.2):
- React-Core
- react-native-safe-area-context (3.4.1):
- React-Core
Expand Down Expand Up @@ -617,7 +617,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 31564fa6912459921568e8b0e49024285a4d584b
React-jsinspector: badd81696361249893a80477983e697aab3c1a34
React-logger: fdda34dd285bdb0232e059b19d9606fa0ec3bb9c
react-native-pager-view: 3c66c4e2f3ab423643d07b2c7041f8ac48395f72
react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43
react-native-safe-area-context: 9e40fb181dac02619414ba1294d6c2a807056ab9
React-perflogger: e68d3795cf5d247a0379735cbac7309adf2fb931
React-RCTActionSheet: 05452c3b281edb27850253db13ecd4c5a65bc247
Expand Down
2 changes: 2 additions & 0 deletions example/src/BasicPagerViewExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export function BasicPagerViewExample() {
//@ts-ignore
testID="pager-view"
ref={ref}
page={navigationPanel.page}
animated={navigationPanel.animated}
style={styles.PagerView}
initialPage={0}
layoutDirection="ltr"
Expand Down
17 changes: 10 additions & 7 deletions example/src/NestPagerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ export function NestPagerView() {
>
<View
key="1"
style={{ backgroundColor: BGCOLOR[0] }}
style={[styles.page, { backgroundColor: BGCOLOR[0] }]}
collapsable={false}
>
<LikeCount />
</View>
<View key="2" collapsable={false}>
<View style={styles.page} key="2" collapsable={false}>
<Text style={styles.title}>
There has two Nest PagerView with horizontal and vertical.
</Text>
Expand All @@ -39,15 +39,15 @@ export function NestPagerView() {
>
<View
key="1"
style={{ backgroundColor: BGCOLOR[1] }}
style={[styles.page, { backgroundColor: BGCOLOR[1] }]}
collapsable={false}
>
<LikeCount />
<Text>Horizontal</Text>
</View>
<View
key="2"
style={{ backgroundColor: BGCOLOR[2] }}
style={[styles.page, { backgroundColor: BGCOLOR[2] }]}
collapsable={false}
>
<LikeCount />
Expand All @@ -64,15 +64,15 @@ export function NestPagerView() {
>
<View
key="1"
style={{ backgroundColor: BGCOLOR[3] }}
style={[styles.page, { backgroundColor: BGCOLOR[3] }]}
collapsable={false}
>
<LikeCount />
<Text>Vertical</Text>
</View>
<View
key="2"
style={{ backgroundColor: BGCOLOR[4] }}
style={[styles.page, { backgroundColor: BGCOLOR[4] }]}
collapsable={false}
>
<LikeCount />
Expand All @@ -82,7 +82,7 @@ export function NestPagerView() {
</View>
<View
key="3"
style={{ backgroundColor: BGCOLOR[3] }}
style={[styles.page, { backgroundColor: BGCOLOR[3] }]}
collapsable={false}
>
<LikeCount />
Expand All @@ -105,5 +105,8 @@ const styles = StyleSheet.create({
PagerView: {
flex: 1,
},
page: {
flex: 1,
},
title: { fontSize: 22, paddingVertical: 10 },
});
4 changes: 2 additions & 2 deletions example/src/OnPageScrollExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);

export function OnPageScrollExample() {
const { ref, ...navigationPanel } = useNavigationPanel(5);
const { activePage, setPage, progress, pages } = navigationPanel;
const { page, setPage, progress, pages } = navigationPanel;

return (
<SafeAreaView style={styles.flex}>
Expand All @@ -22,7 +22,7 @@ export function OnPageScrollExample() {
<Text
style={[
styles.touchableTitle,
activePage === index && styles.touchableTitleActive,
page === index && styles.touchableTitleActive,
]}
>
Page {index}
Expand Down
1 change: 1 addition & 0 deletions example/src/PaginationDotsExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ const styles = StyleSheet.create({
},
progressContainer: { flex: 0.1, backgroundColor: '#63a4ff' },
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignContent: 'center',
Expand Down
Loading