Skip to content

Commit

Permalink
feat(iOS): sheetInitialDetent support (software-mansion#2367)
Browse files Browse the repository at this point in the history
## Description

This PR adds `sheetInitialDetent` support to iOS and fixes detents logic
on iOS < 16.

This functionality depends on changes made in this PR:
react-navigation/react-navigation#12032

## Changes

- supporting `sheetInitialDetent` on iOS
- modified `Test2002.tsx` repro
- updated README definition to match types
- fixed `sheetAllowedDetents` on iOS < 16

<!--

## Screenshots / GIFs

Here you can add screenshots / GIFs documenting your change.

You can add before / after section if you're changing some behavior.

### Before

### After

-->

## Test code and steps to reproduce

- Use `Test2002.tsx` repro

## Checklist

- [x] Included code example that can be used to test this change
- [x] Updated documentation: <!-- For adding new props to native-stack
-->
- [x]
https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md
- [x] Ensured that CI passes
  • Loading branch information
alduzy authored and ja1ns committed Oct 9, 2024
1 parent df51418 commit 2958d79
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 8 deletions.
31 changes: 26 additions & 5 deletions apps/src/tests/Test2002.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@ import {
DefaultTheme,
NavigationContainer,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import {
createNativeStackNavigator,
NativeStackNavigationProp,
} from '@react-navigation/native-stack';

type StackParamList = {
Home: undefined;
formSheet: undefined;
fullScreenModal: undefined;
};

function HomeScreen({ navigation }) {
function HomeScreen({
navigation,
}: {
navigation: NativeStackNavigationProp<StackParamList>;
}) {
return (
<View style={styles.container}>
<Button
Expand All @@ -22,15 +35,19 @@ function HomeScreen({ navigation }) {
);
}

function ModalScreen({ navigation }) {
function ModalScreen({
navigation,
}: {
navigation: NativeStackNavigationProp<StackParamList>;
}) {
return (
<View style={styles.container}>
<Button onPress={() => navigation.goBack()} title="Dismiss" />
</View>
);
}

const RootStack = createNativeStackNavigator();
const RootStack = createNativeStackNavigator<StackParamList>();

export default function App() {
const scheme = useColorScheme();
Expand All @@ -42,7 +59,11 @@ export default function App() {
<RootStack.Screen
name="formSheet"
component={ModalScreen}
options={{ presentation: 'formSheet' }}
options={{
presentation: 'formSheet',
sheetAllowedDetents: [0.3, 0.5, 0.8],
sheetInitialDetent: 1,
}}
/>
<RootStack.Screen
name="fullScreenModal"
Expand Down
1 change: 1 addition & 0 deletions ios/RNSScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace react = facebook::react;
@property (nonatomic) NSNumber *sheetLargestUndimmedDetent;
@property (nonatomic) BOOL sheetGrabberVisible;
@property (nonatomic) CGFloat sheetCornerRadius;
@property (nonatomic) NSInteger sheetInitialDetent;
@property (nonatomic) BOOL sheetExpandsWhenScrolledToEdge;
#endif // !TARGET_OS_TV

Expand Down
29 changes: 27 additions & 2 deletions ios/RNSScreen.mm
Original file line number Diff line number Diff line change
Expand Up @@ -889,8 +889,8 @@ - (void)updateFormSheetPresentationStyle
sheet.delegate = self;
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_16_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0
if (_sheetAllowedDetents.count > 0) {
if (@available(iOS 16.0, *)) {
if (@available(iOS 16.0, *)) {
if (_sheetAllowedDetents.count > 0) {
if (_sheetAllowedDetents.count == 1 && [_sheetAllowedDetents[0] integerValue] == SHEET_FIT_TO_CONTENTS) {
// This is `fitToContents` case, where sheet should be just high to display its contents.
// Paper: we do not set anything here, we will set once React computed layout of our React's children, namely
Expand Down Expand Up @@ -944,6 +944,26 @@ - (void)updateFormSheetPresentationStyle
}
}

if (_sheetInitialDetent > 0 && _sheetInitialDetent < _sheetAllowedDetents.count) {
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_16_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0
if (@available(iOS 16.0, *)) {
UISheetPresentationControllerDetent *detent = sheet.detents[_sheetInitialDetent];
[self setSelectedDetentForSheet:sheet to:detent.identifier animate:YES];
} else
#endif // Check for iOS >= 16
{
if (_sheetInitialDetent < 2) {
[self setSelectedDetentForSheet:sheet to:UISheetPresentationControllerDetentIdentifierLarge animate:YES];
} else {
RCTLogError(
@"[RNScreens] sheetInitialDetent out of bounds, on iOS versions below 16 sheetAllowedDetents is ignored in favor of an array of two system-defined detents");
}
}
} else if (_sheetInitialDetent != 0) {
RCTLogError(@"[RNScreens] sheetInitialDetent out of bounds for sheetAllowedDetents array");
}

sheet.prefersScrollingExpandsWhenScrolledToEdge = _sheetExpandsWhenScrolledToEdge;
[self setGrabberVisibleForSheet:sheet to:_sheetGrabberVisible animate:YES];
[self setCornerRadiusForSheet:sheet to:_sheetCornerRadius animate:YES];
Expand Down Expand Up @@ -1151,6 +1171,10 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props::
[self setSheetAllowedDetents:[RNSConvert detentFractionsArrayFromVector:newScreenProps.sheetAllowedDetents]];
}

if (newScreenProps.sheetInitialDetent != oldScreenProps.sheetInitialDetent) {
[self setSheetInitialDetent:newScreenProps.sheetInitialDetent];
}

if (newScreenProps.sheetLargestUndimmedDetent != oldScreenProps.sheetLargestUndimmedDetent) {
[self setSheetLargestUndimmedDetent:[NSNumber numberWithInt:newScreenProps.sheetLargestUndimmedDetent]];
}
Expand Down Expand Up @@ -1864,6 +1888,7 @@ @implementation RNSScreenManager
RCT_EXPORT_VIEW_PROPERTY(sheetLargestUndimmedDetent, NSNumber *);
RCT_EXPORT_VIEW_PROPERTY(sheetGrabberVisible, BOOL);
RCT_EXPORT_VIEW_PROPERTY(sheetCornerRadius, CGFloat);
RCT_EXPORT_VIEW_PROPERTY(sheetInitialDetent, NSInteger);
RCT_EXPORT_VIEW_PROPERTY(sheetExpandsWhenScrolledToEdge, BOOL);
#endif

Expand Down
4 changes: 3 additions & 1 deletion native-stack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,11 @@ Defaults to system default.

#### `sheetInitialDetent`

Initial detent for the sheet.
Index of the detent the sheet should expand to after being opened.
Works only when `presentation` is set to `formSheet`.

Defaults to `0` - which represents first detent in the detents array.

#### `sheetGrabberVisible` (iOS only)

Boolean indicating whether the sheet shows a grabber at the top.
Expand Down
1 change: 1 addition & 0 deletions src/fabric/ModalScreenNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export interface NativeProps extends ViewProps {
sheetGrabberVisible?: WithDefault<boolean, false>;
sheetCornerRadius?: WithDefault<Float, -1.0>;
sheetExpandsWhenScrolledToEdge?: WithDefault<boolean, false>;
sheetInitialDetent?: WithDefault<Int32, 0>;
customAnimationOnSwipe?: boolean;
fullScreenSwipeEnabled?: boolean;
fullScreenSwipeShadowEnabled?: boolean;
Expand Down

0 comments on commit 2958d79

Please sign in to comment.