Compare commits
2 Commits
df65b785ef
...
f79d5a6b59
Author | SHA1 | Date |
---|---|---|
Shadowfacts | f79d5a6b59 | |
Shadowfacts | c34938a03d |
|
@ -7,6 +7,7 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
D6055E46234D1B31007BEF52 /* ContentTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6055E45234D1B31007BEF52 /* ContentTableViewController.swift */; };
|
||||||
D610D2D6233945AF009EB06A /* SheetImagePicker.h in Headers */ = {isa = PBXBuildFile; fileRef = D610D2D4233945AF009EB06A /* SheetImagePicker.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D610D2D6233945AF009EB06A /* SheetImagePicker.h in Headers */ = {isa = PBXBuildFile; fileRef = D610D2D4233945AF009EB06A /* SheetImagePicker.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D610D2E3233945B9009EB06A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D610D2E2233945B9009EB06A /* AppDelegate.swift */; };
|
D610D2E3233945B9009EB06A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D610D2E2233945B9009EB06A /* AppDelegate.swift */; };
|
||||||
D610D2E5233945B9009EB06A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D610D2E4233945B9009EB06A /* SceneDelegate.swift */; };
|
D610D2E5233945B9009EB06A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D610D2E4233945B9009EB06A /* SceneDelegate.swift */; };
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
D6055E45234D1B31007BEF52 /* ContentTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTableViewController.swift; sourceTree = "<group>"; };
|
||||||
D610D2D1233945AF009EB06A /* SheetImagePicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SheetImagePicker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D610D2D1233945AF009EB06A /* SheetImagePicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SheetImagePicker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D610D2D4233945AF009EB06A /* SheetImagePicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SheetImagePicker.h; sourceTree = "<group>"; };
|
D610D2D4233945AF009EB06A /* SheetImagePicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SheetImagePicker.h; sourceTree = "<group>"; };
|
||||||
D610D2D5233945AF009EB06A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D610D2D5233945AF009EB06A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
@ -124,6 +126,7 @@
|
||||||
D610D2E2233945B9009EB06A /* AppDelegate.swift */,
|
D610D2E2233945B9009EB06A /* AppDelegate.swift */,
|
||||||
D610D2E4233945B9009EB06A /* SceneDelegate.swift */,
|
D610D2E4233945B9009EB06A /* SceneDelegate.swift */,
|
||||||
D610D2E6233945B9009EB06A /* ViewController.swift */,
|
D610D2E6233945B9009EB06A /* ViewController.swift */,
|
||||||
|
D6055E45234D1B31007BEF52 /* ContentTableViewController.swift */,
|
||||||
D610D2E8233945B9009EB06A /* Main.storyboard */,
|
D610D2E8233945B9009EB06A /* Main.storyboard */,
|
||||||
D610D2EB233945BB009EB06A /* Assets.xcassets */,
|
D610D2EB233945BB009EB06A /* Assets.xcassets */,
|
||||||
D610D2ED233945BB009EB06A /* LaunchScreen.storyboard */,
|
D610D2ED233945BB009EB06A /* LaunchScreen.storyboard */,
|
||||||
|
@ -267,6 +270,7 @@
|
||||||
files = (
|
files = (
|
||||||
D610D2E7233945B9009EB06A /* ViewController.swift in Sources */,
|
D610D2E7233945B9009EB06A /* ViewController.swift in Sources */,
|
||||||
D610D2E3233945B9009EB06A /* AppDelegate.swift in Sources */,
|
D610D2E3233945B9009EB06A /* AppDelegate.swift in Sources */,
|
||||||
|
D6055E46234D1B31007BEF52 /* ContentTableViewController.swift in Sources */,
|
||||||
D610D2E5233945B9009EB06A /* SceneDelegate.swift in Sources */,
|
D610D2E5233945B9009EB06A /* SceneDelegate.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -478,13 +482,13 @@
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
DEVELOPMENT_TEAM = 46G5674823;
|
||||||
INFOPLIST_FILE = SheetImagePickerTest/Info.plist;
|
INFOPLIST_FILE = SheetImagePickerTest/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.SheetImagePickerTest;
|
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.dev.SheetImagePickerTest;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
@ -497,13 +501,13 @@
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
DEVELOPMENT_TEAM = 46G5674823;
|
||||||
INFOPLIST_FILE = SheetImagePickerTest/Info.plist;
|
INFOPLIST_FILE = SheetImagePickerTest/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.SheetImagePickerTest;
|
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.dev.SheetImagePickerTest;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
|
|
@ -11,6 +11,8 @@ import UIKit
|
||||||
public protocol SheetContainerViewControllerDelegate {
|
public protocol SheetContainerViewControllerDelegate {
|
||||||
func sheetContainer(_ sheetContainer: SheetContainerViewController, willSnapToDetent detent: Detent) -> Bool
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, willSnapToDetent detent: Detent) -> Bool
|
||||||
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent)
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent)
|
||||||
|
func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView?
|
||||||
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
// default no-op implementation
|
// default no-op implementation
|
||||||
|
@ -19,13 +21,19 @@ public extension SheetContainerViewControllerDelegate {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent) {}
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, didSnapToDetent detent: Detent) {}
|
||||||
|
func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SheetContainerViewController: UIViewController {
|
public class SheetContainerViewController: UIViewController {
|
||||||
|
|
||||||
public var delegate: SheetContainerViewControllerDelegate?
|
public var delegate: SheetContainerViewControllerDelegate?
|
||||||
|
|
||||||
let content: UIViewController
|
public let content: UIViewController
|
||||||
|
|
||||||
public var detents: [Detent] = [.bottom, .middle, .top]
|
public var detents: [Detent] = [.bottom, .middle, .top]
|
||||||
var topDetent: (detent: Detent, offset: CGFloat) {
|
var topDetent: (detent: Detent, offset: CGFloat) {
|
||||||
|
@ -45,6 +53,10 @@ public class SheetContainerViewController: UIViewController {
|
||||||
public var minimumDimmingAlpha: CGFloat = 0
|
public var minimumDimmingAlpha: CGFloat = 0
|
||||||
public var maximumDimmingAlpha: CGFloat = 0.75
|
public var maximumDimmingAlpha: CGFloat = 0.75
|
||||||
|
|
||||||
|
var contentScrollView: UIScrollView? {
|
||||||
|
delegate?.sheetContainerContentScrollView(self) ?? content.view as? UIScrollView
|
||||||
|
}
|
||||||
|
|
||||||
public init(content: UIViewController) {
|
public init(content: UIViewController) {
|
||||||
self.content = content
|
self.content = content
|
||||||
|
|
||||||
|
@ -85,7 +97,12 @@ public class SheetContainerViewController: UIViewController {
|
||||||
])
|
])
|
||||||
|
|
||||||
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
|
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
|
||||||
|
panGesture.delegate = self
|
||||||
content.view.addGestureRecognizer(panGesture)
|
content.view.addGestureRecognizer(panGesture)
|
||||||
|
|
||||||
|
if let scrollView = contentScrollView {
|
||||||
|
scrollView.panGestureRecognizer.addTarget(self, action: #selector(scrollViewPanGestureRecognized))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
@objc func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||||
|
@ -95,44 +112,88 @@ public class SheetContainerViewController: UIViewController {
|
||||||
|
|
||||||
case .changed:
|
case .changed:
|
||||||
let translation = recognizer.translation(in: content.view)
|
let translation = recognizer.translation(in: content.view)
|
||||||
var realOffset = initialConstant + translation.y
|
let realOffset = initialConstant + translation.y
|
||||||
let topOffset = topDetent.offset
|
setTopOffset(realOffset)
|
||||||
if realOffset < topOffset {
|
|
||||||
let smoothed = smoothstep(value: realOffset, from: topOffset, to: 0)
|
|
||||||
realOffset = topOffset - smoothed * maximumStretchDistance
|
|
||||||
|
|
||||||
}
|
|
||||||
topConstraint.constant = realOffset
|
|
||||||
dimmingView.alpha = lerp(realOffset, min: topOffset, max: bottomDetent.offset, from: maximumDimmingAlpha, to: minimumDimmingAlpha)
|
|
||||||
|
|
||||||
case .ended:
|
case .ended:
|
||||||
let velocity = recognizer.velocity(in: view)
|
let velocity = recognizer.velocity(in: view)
|
||||||
|
springToNearestDetent(verticalVelocity: velocity.y)
|
||||||
|
|
||||||
let springToDetent: (Detent, CGFloat)
|
|
||||||
if abs(velocity.y) > minimumDetentJumpVelocity,
|
|
||||||
let detentInVelocityDirection = nearestDetentOffset(currentOffset: topConstraint.constant, direction: velocity.y) {
|
|
||||||
springToDetent = detentInVelocityDirection
|
|
||||||
} else if let nearestDetent = nearestDetentOffset(currentOffset: topConstraint.constant) {
|
|
||||||
springToDetent = nearestDetent
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if delegate?.sheetContainer(self, willSnapToDetent: springToDetent.0) ?? true {
|
|
||||||
let springDistance = abs(topConstraint.constant - springToDetent.1)
|
|
||||||
self.topConstraint.constant = springToDetent.1
|
|
||||||
let springVelocity = velocity.y / springDistance
|
|
||||||
|
|
||||||
UIView.animate(withDuration: 0.35, delay: 0, usingSpringWithDamping: 0.75, initialSpringVelocity: springVelocity, animations: {
|
|
||||||
self.view.layoutIfNeeded()
|
|
||||||
self.dimmingView.alpha = lerp(springToDetent.1, min: self.topDetent.offset, max: self.bottomDetent.offset, from: self.maximumDimmingAlpha, to: self.minimumDimmingAlpha)
|
|
||||||
}, completion: { (finished) in
|
|
||||||
self.delegate?.sheetContainer(self, didSnapToDetent: springToDetent.0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func scrollViewPanGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||||
|
guard let scrollView = recognizer.view as? UIScrollView else { return }
|
||||||
|
|
||||||
|
let velocity = recognizer.velocity(in: scrollView)
|
||||||
|
|
||||||
|
let topContentOffset: CGFloat = delegate?.sheetContainer(self, topContentOffsetForScrollView: scrollView) ?? 0
|
||||||
|
let shouldMoveSheetDown = scrollView.contentOffset.y <= topContentOffset && velocity.y > 0 // scrolled to top and dragging down
|
||||||
|
let shouldMoveSheetUp = topConstraint.constant > topDetent.offset && velocity.y < 0 // not fully expanded and dragging up
|
||||||
|
|
||||||
|
let shouldMoveSheet = shouldMoveSheetDown || shouldMoveSheetUp
|
||||||
|
if shouldMoveSheet {
|
||||||
|
scrollView.bounces = false
|
||||||
|
scrollView.setContentOffset(CGPoint(x: 0, y: topContentOffset), animated: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch recognizer.state {
|
||||||
|
case .changed:
|
||||||
|
if shouldMoveSheet {
|
||||||
|
let translation = recognizer.translation(in: scrollView)
|
||||||
|
setTopOffset(topConstraint.constant + translation.y)
|
||||||
|
recognizer.setTranslation(.zero, in: scrollView)
|
||||||
|
}
|
||||||
|
|
||||||
|
case .ended:
|
||||||
|
scrollView.bounces = true
|
||||||
|
if shouldMoveSheet {
|
||||||
|
springToNearestDetent(verticalVelocity: velocity.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTopOffset(_ offset: CGFloat) {
|
||||||
|
var offset = offset
|
||||||
|
|
||||||
|
let topOffset = topDetent.offset
|
||||||
|
if offset < topOffset {
|
||||||
|
let smoothed = smoothstep(value: offset, from: topOffset, to: 0)
|
||||||
|
offset = topOffset - smoothed * maximumStretchDistance
|
||||||
|
|
||||||
|
}
|
||||||
|
topConstraint.constant = offset
|
||||||
|
dimmingView.alpha = lerp(offset, min: topOffset, max: bottomDetent.offset, from: maximumDimmingAlpha, to: minimumDimmingAlpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
func springToNearestDetent(verticalVelocity velocity: CGFloat) {
|
||||||
|
let springToDetent: (Detent, CGFloat)
|
||||||
|
if abs(velocity) > minimumDetentJumpVelocity,
|
||||||
|
let detentInVelocityDirection = nearestDetentOffset(currentOffset: topConstraint.constant, direction: velocity) {
|
||||||
|
springToDetent = detentInVelocityDirection
|
||||||
|
} else if let nearestDetent = nearestDetentOffset(currentOffset: topConstraint.constant) {
|
||||||
|
springToDetent = nearestDetent
|
||||||
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if delegate?.sheetContainer(self, willSnapToDetent: springToDetent.0) ?? true {
|
||||||
|
let springDistance = abs(topConstraint.constant - springToDetent.1)
|
||||||
|
self.topConstraint.constant = springToDetent.1
|
||||||
|
let springVelocity = velocity / springDistance
|
||||||
|
|
||||||
|
UIView.animate(withDuration: 0.35, delay: 0, usingSpringWithDamping: 0.75, initialSpringVelocity: springVelocity, animations: {
|
||||||
|
self.view.layoutIfNeeded()
|
||||||
|
self.dimmingView.alpha = lerp(springToDetent.1, min: self.topDetent.offset, max: self.bottomDetent.offset, from: self.maximumDimmingAlpha, to: self.minimumDimmingAlpha)
|
||||||
|
}, completion: { (finished) in
|
||||||
|
self.delegate?.sheetContainer(self, didSnapToDetent: springToDetent.0)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func nearestDetentOffset(currentOffset: CGFloat) -> (Detent, CGFloat)? {
|
func nearestDetentOffset(currentOffset: CGFloat) -> (Detent, CGFloat)? {
|
||||||
|
@ -154,6 +215,15 @@ public class SheetContainerViewController: UIViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SheetContainerViewController: UIGestureRecognizerDelegate {
|
||||||
|
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
if topConstraint.constant <= topDetent.offset {
|
||||||
|
return (gestureRecognizer as! UIPanGestureRecognizer).translation(in: gestureRecognizer.view!).y > 0
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension SheetContainerViewController: UIViewControllerTransitioningDelegate {
|
extension SheetContainerViewController: UIViewControllerTransitioningDelegate {
|
||||||
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
return SheetContainerPresentationAnimationController()
|
return SheetContainerPresentationAnimationController()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -15,18 +15,44 @@
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tfd-T0-fMO">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="hIF-hV-InX">
|
||||||
<rect key="frame" x="184" y="433" width="46" height="30"/>
|
<rect key="frame" x="173" y="388" width="68" height="120"/>
|
||||||
<state key="normal" title="Button"/>
|
<subviews>
|
||||||
<connections>
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tfd-T0-fMO">
|
||||||
<action selector="buttonPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="tmi-VL-j61"/>
|
<rect key="frame" x="0.0" y="0.0" width="68" height="30"/>
|
||||||
</connections>
|
<state key="normal" title="Plain"/>
|
||||||
</button>
|
<connections>
|
||||||
|
<action selector="plainPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="tmi-VL-j61"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fT8-yG-J2R">
|
||||||
|
<rect key="frame" x="0.0" y="30" width="68" height="30"/>
|
||||||
|
<state key="normal" title="Table"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="tablePressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="PZl-oC-0t4"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="39x-b2-4Hx">
|
||||||
|
<rect key="frame" x="0.0" y="60" width="68" height="30"/>
|
||||||
|
<state key="normal" title="Nav"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="navPressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Jc9-R9-VZW"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eUF-7N-Qgr">
|
||||||
|
<rect key="frame" x="0.0" y="90" width="68" height="30"/>
|
||||||
|
<state key="normal" title="Nav Table"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="navTablePressed:" destination="BYZ-38-t0r" eventType="touchUpInside" id="fSY-4h-jE3"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
</stackView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="tfd-T0-fMO" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="Cpn-cM-hYr"/>
|
<constraint firstItem="hIF-hV-InX" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="MT3-wG-T9R"/>
|
||||||
<constraint firstItem="tfd-T0-fMO" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="YJH-oX-yBz"/>
|
<constraint firstItem="hIF-hV-InX" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="Unx-Jo-GQK"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||||
</view>
|
</view>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// ContentTableViewController.swift
|
||||||
|
// SheetImagePickerTest
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 10/8/19.
|
||||||
|
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class ContentTableViewController: UITableViewController {
|
||||||
|
init() {
|
||||||
|
super.init(style: .plain)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "testCell")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Table view data source
|
||||||
|
|
||||||
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return 40
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "testCell", for: indexPath)
|
||||||
|
|
||||||
|
cell.textLabel!.text = "\(indexPath.row)"
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
guard let navController = navigationController else { return }
|
||||||
|
|
||||||
|
let vc = UIViewController()
|
||||||
|
vc.view.backgroundColor = .systemBackground
|
||||||
|
let label = UILabel()
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
label.text = "\(indexPath.row)"
|
||||||
|
vc.view.addSubview(label)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor),
|
||||||
|
label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
navController.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,12 +17,9 @@ class ViewController: UIViewController {
|
||||||
view.backgroundColor = .green
|
view.backgroundColor = .green
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func buttonPressed(_ sender: Any) {
|
@IBAction func plainPressed(_ sender: Any) {
|
||||||
let content = UIViewController()
|
let content = UIViewController()
|
||||||
content.view.translatesAutoresizingMaskIntoConstraints = false
|
content.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
content.view.layer.masksToBounds = true
|
|
||||||
content.view.layer.cornerRadius = view.bounds.width * 0.02
|
|
||||||
|
|
||||||
let blurEffect = UIBlurEffect(style: .systemChromeMaterial)
|
let blurEffect = UIBlurEffect(style: .systemChromeMaterial)
|
||||||
let blurView = UIVisualEffectView(effect: blurEffect)
|
let blurView = UIVisualEffectView(effect: blurEffect)
|
||||||
blurView.translatesAutoresizingMaskIntoConstraints = false
|
blurView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -47,6 +44,57 @@ class ViewController: UIViewController {
|
||||||
present(sheet, animated: true)
|
present(sheet, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func tablePressed(_ sender: Any) {
|
||||||
|
let content = ContentTableViewController()
|
||||||
|
content.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
content.view.layer.masksToBounds = true
|
||||||
|
content.view.layer.cornerRadius = view.bounds.width * 0.02
|
||||||
|
|
||||||
|
let sheet = SheetContainerViewController(content: content)
|
||||||
|
sheet.delegate = self
|
||||||
|
sheet.detents = [.bottom, .middle, .top]
|
||||||
|
|
||||||
|
present(sheet, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func navPressed(_ sender: Any) {
|
||||||
|
let root = UIViewController()
|
||||||
|
root.view.backgroundColor = .systemBackground
|
||||||
|
let label = UILabel()
|
||||||
|
label.text = "Root VC"
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
root.view.addSubview(label)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
label.centerXAnchor.constraint(equalTo: root.view.centerXAnchor),
|
||||||
|
label.centerYAnchor.constraint(equalTo: root.view.centerYAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
let nav = UINavigationController(rootViewController: root)
|
||||||
|
nav.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
nav.view.layer.masksToBounds = true
|
||||||
|
nav.view.layer.cornerRadius = view.bounds.width * 0.02
|
||||||
|
|
||||||
|
let sheet = SheetContainerViewController(content: nav)
|
||||||
|
sheet.delegate = self
|
||||||
|
sheet.detents = [.bottom, .middle, .top]
|
||||||
|
|
||||||
|
present(sheet, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func navTablePressed(_ sender: Any) {
|
||||||
|
let table = ContentTableViewController()
|
||||||
|
|
||||||
|
let nav = UINavigationController(rootViewController: table)
|
||||||
|
nav.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
nav.view.layer.masksToBounds = true
|
||||||
|
nav.view.layer.cornerRadius = view.bounds.width * 0.02
|
||||||
|
|
||||||
|
let sheet = SheetContainerViewController(content: nav)
|
||||||
|
sheet.delegate = self
|
||||||
|
sheet.detents = [.bottom, .middle, .top]
|
||||||
|
|
||||||
|
present(sheet, animated: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ViewController: SheetContainerViewControllerDelegate {
|
extension ViewController: SheetContainerViewControllerDelegate {
|
||||||
|
@ -57,4 +105,18 @@ extension ViewController: SheetContainerViewControllerDelegate {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
func sheetContainerContentScrollView(_ sheetContainer: SheetContainerViewController) -> UIScrollView? {
|
||||||
|
if let navController = sheetContainer.content as? UINavigationController, let scrollView = navController.visibleViewController?.view as? UIScrollView {
|
||||||
|
return scrollView
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func sheetContainer(_ sheetContainer: SheetContainerViewController, topContentOffsetForScrollView scrollView: UIScrollView) -> CGFloat {
|
||||||
|
if let navController = sheetContainer.content as? UINavigationController, navController.visibleViewController?.view is UIScrollView {
|
||||||
|
return -navController.navigationBar.bounds.height
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue