Skip to content

Commit

Permalink
basic scrollview on the native side
Browse files Browse the repository at this point in the history
  • Loading branch information
haileyok committed Oct 10, 2024
1 parent ad896cb commit df86081
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 119 deletions.
1 change: 0 additions & 1 deletion modules/bottom-sheet/ios/BottomSheetModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class BottomSheetModule: Module {
}

AsyncFunction("updateLayout") { (view: SheetView) in
view.updateLayout()
}

Prop("containerBackgroundColor") { (view: SheetView, prop: UIColor) in
Expand Down
79 changes: 73 additions & 6 deletions modules/bottom-sheet/ios/BottomSheetScrollView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,97 @@
//

class BottomSheetScrollView: UIScrollView, UIScrollViewDelegate {
private let sheetView: SheetView
private var previousHeight: CGFloat?
private var beganDraggingY: CGFloat?

init() {
init(sheetView: SheetView) {
self.sheetView = sheetView
super.init(frame: .zero)
if let window = Util.getWindow() {
self.frame = window.bounds
self.contentInset = UIEdgeInsets(top: 0,
left: 0,
bottom: window.safeAreaInsets.bottom,
right: 0)
let offset = window.safeAreaInsets.bottom * 3
self.contentInset.bottom = offset
self.verticalScrollIndicatorInsets.top = 20
self.verticalScrollIndicatorInsets.bottom = offset
}

self.delegate = self

NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

deinit {
NotificationCenter.default.removeObserver(self)
}

override func layoutSubviews() {
super.layoutSubviews()

if let height = self.subviews.first?.frame.size.height,
self.previousHeight != height,
let window = self.window {
self.contentSize = CGSize(width: window.bounds.width, height: height + window.safeAreaInsets.bottom)
let newDetent = self.sheetView.sheetVc.updateDetents(contentHeight: self.sheetView.clampHeight(height),
preventExpansion: self.sheetView.preventExpansion)
self.sheetView.selectedDetentIdentifier = newDetent
self.contentSize = CGSize(width: window.bounds.width, height: height)
self.previousHeight = height
}
}

@objc func keyboardWillShow(notification: Notification) {
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
let keyboardHeight = keyboardFrame.height
let newOffset = self.contentInset.bottom + keyboardHeight

// We purposefully add keyboard height to content inset and only update
// the scroll indicator inset
self.contentInset.bottom = newOffset
self.verticalScrollIndicatorInsets.bottom = keyboardHeight

if let firstResponder = self.findFirstResponder(),
let window = self.window {
let position = firstResponder.convert(firstResponder.bounds,
to: window)

if position.minY > window.bounds.height - keyboardHeight {
self.setContentOffset(CGPoint(x: 0, y: self.contentOffset.y + keyboardHeight),
animated: true)
}
}
}
}

@objc func keyboardWillHide(notification: Notification) {
if let window = Util.getWindow() {
let offset = window.safeAreaInsets.bottom * 3
self.contentInset.bottom = offset
self.verticalScrollIndicatorInsets.bottom = offset
}
}

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.beganDraggingY = self.contentOffset.y
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let beganDraggingY = self.beganDraggingY,
self.contentOffset.y < beganDraggingY {
if let firstResponder = self.findFirstResponder() {
firstResponder.resignFirstResponder()
}
self.beganDraggingY = nil
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// UIView+findFirstResponder.swift
// Pods
//
// Created by Hailey on 10/9/24.
//

extension UIView {
func findFirstResponder() -> UIView? {
if self.isFirstResponder {
return self
}
for subview in subviews {
if let responder = subview.findFirstResponder() {
return responder
}
}
return nil
}
}
29 changes: 7 additions & 22 deletions modules/bottom-sheet/ios/SheetView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ import UIKit

class SheetView: ExpoView, UISheetPresentationControllerDelegate {
// Views
private var sheetVc: SheetViewController!
var sheetVc: SheetViewController!
private var innerView: UIView?
private var contentHeight: CGFloat? {
get {
self.innerView?.frame.height
}
}

// Scroll view
private var scrollView: BottomSheetScrollView!
Expand Down Expand Up @@ -59,6 +54,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
}
}
}

private var isClosing = false {
didSet {
if isClosing {
Expand All @@ -68,7 +64,8 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
}
}
}
private var selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier? {

var selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier? {
didSet {
if selectedDetentIdentifier == .large {
onSnapPointChange([
Expand All @@ -89,12 +86,12 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
required init (appContext: AppContext? = nil) {
super.init(appContext: appContext)

self.scrollView = BottomSheetScrollView()

self.sheetVc = SheetViewController()
if let sheet = self.sheetVc.sheetPresentationController {
sheet.delegate = self
}

self.scrollView = BottomSheetScrollView(sheetView: self)
self.sheetVc.view.addSubview(self.scrollView)

self.touchHandler = RCTTouchHandler(bridge: appContext?.reactBridge)
Expand Down Expand Up @@ -132,12 +129,10 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
guard !self.isOpen,
!self.isOpening,
!self.isClosing,
let contentHeight = self.contentHeight,
let rvc = self.reactViewController() else {
return
}

self.sheetVc.setDetents(contentHeight: self.clampHeight(contentHeight), preventExpansion: self.preventExpansion)
if let sheet = sheetVc.sheetPresentationController {
sheet.preferredCornerRadius = self.cornerRadius
self.selectedDetentIdentifier = sheet.selectedDetentIdentifier
Expand All @@ -151,16 +146,6 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
}
}

func updateLayout() {
if self.prevLayoutDetentIdentifier == self.selectedDetentIdentifier,
let contentHeight = self.contentHeight {
self.sheetVc.updateDetents(contentHeight: self.clampHeight(contentHeight),
preventExpansion: self.preventExpansion)
self.selectedDetentIdentifier = self.sheetVc.getCurrentDetentIdentifier()
}
self.prevLayoutDetentIdentifier = self.selectedDetentIdentifier
}

func dismiss() {
self.isClosing = true
self.sheetVc.dismiss(animated: true) { [weak self] in
Expand All @@ -170,7 +155,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {

// MARK: - Utils

private func clampHeight(_ height: CGFloat) -> CGFloat {
func clampHeight(_ height: CGFloat) -> CGFloat {
if height < self.minHeight {
return self.minHeight
} else if height > self.maxHeight {
Expand Down
11 changes: 7 additions & 4 deletions modules/bottom-sheet/ios/SheetViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class SheetViewController: UIViewController {
}
}

func setDetents(contentHeight: CGFloat, preventExpansion: Bool) {
func setDetents(contentHeight: CGFloat, preventExpansion: Bool) -> UISheetPresentationController.Detent.Identifier? {
guard let sheet = self.sheetPresentationController else {
return
return nil
}

if contentHeight > Util.getScreenHeight() - 100 {
Expand All @@ -48,17 +48,20 @@ class SheetViewController: UIViewController {
}
sheet.selectedDetentIdentifier = .medium
}
return sheet.selectedDetentIdentifier
}

func updateDetents(contentHeight: CGFloat, preventExpansion: Bool) {
func updateDetents(contentHeight: CGFloat, preventExpansion: Bool) -> UISheetPresentationController.Detent.Identifier? {
var newDetent: UISheetPresentationController.Detent.Identifier?
if let sheet = self.sheetPresentationController {
sheet.animateChanges {
self.setDetents(contentHeight: contentHeight, preventExpansion: preventExpansion)
newDetent = self.setDetents(contentHeight: contentHeight, preventExpansion: preventExpansion)
if #available(iOS 16.0, *) {
sheet.invalidateDetents()
}
}
}
return newDetent
}

func getCurrentDetentIdentifier() -> UISheetPresentationController.Detent.Identifier? {
Expand Down
16 changes: 0 additions & 16 deletions modules/bottom-sheet/src/BottomSheetNativeComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import * as React from 'react'
import {
Dimensions,
NativeSyntheticEvent,
Platform,
ScrollView,
StyleProp,
View,
ViewStyle,
} from 'react-native'
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'
Expand Down Expand Up @@ -66,7 +63,6 @@ export class BottomSheetNativeComponent extends React.Component<

render() {
const {children, ...rest} = this.props
const cornerRadius = rest.cornerRadius ?? 0

if (!this.state.open) {
return null
Expand All @@ -82,19 +78,7 @@ export class BottomSheetNativeComponent extends React.Component<
height: screenHeight,
width: '100%',
}}>
{/*<View*/}
{/* style={[*/}
{/* {*/}
{/* flex: 1,*/}
{/* backgroundColor,*/}
{/* },*/}
{/* Platform.OS === 'android' && {*/}
{/* borderTopLeftRadius: cornerRadius,*/}
{/* borderTopRightRadius: cornerRadius,*/}
{/* },*/}
{/* ]}>*/}
<BottomSheetPortalProvider>{children}</BottomSheetPortalProvider>
{/*</View>*/}
</NativeView>
)
}
Expand Down
Loading

0 comments on commit df86081

Please sign in to comment.