diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..3eb199e
Binary files /dev/null and b/.swiftpm/xcode/package.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Configs/ScrollStackController.plist b/Configs/ScrollStackController.plist
index 9dcce24..5eb0141 100644
--- a/Configs/ScrollStackController.plist
+++ b/Configs/ScrollStackController.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 1.0
+ $(MARKETING_VERSION)
CFBundleSignature
????
CFBundleVersion
diff --git a/Package.swift b/Package.swift
index 8b1477f..148940d 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:4.0
+// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
diff --git a/README.md b/README.md
index 1dcabf6..62fc46c 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ You can think of it as `UITableView` but with several differences:
|--- |--------------------------------------------------------------------------------- |
| 🕺 | Create complex layout without the boilerplate required by view recyling of `UICollectionView` or `UITableView`. |
| 🧩 | Simplify your architecture by thinking each screen as a separate-indipendent `UIVIewController`. |
-| 🌈 | Animate show/hide and resize of rows easily! |
+| 🌈 | Animate show/hide and resize of rows easily even with custom animations! |
| ⏱ | Compact code base, less than 1k LOC with no external dependencies. |
| 🎯 | Easy to use and extensible APIs set. |
| 🧬 | It uses standard UIKit components at its core. No magic, just a combination of `UIScrollView`+`UIStackView`. |
@@ -42,6 +42,7 @@ You can think of it as `UITableView` but with several differences:
- [Removing / Replacing Rows](#removingreplacingrows)
- [Move Rows](#moverows)
- [Hide / Show Rows](#hideshowrows)
+ - [Hide / Show Rows with custom animations](#customanimations)
- [Reload Rows](#reloadrows)
- [Sizing Rows](#sizingrows)
- [Fixed Row Size](#fixedrowsize)
@@ -232,6 +233,63 @@ Keep in mind: when you hide a rows the row still part of the stack and it's not
[↑ Back To Top](#index)
+
+
+### Hide / Show Rows with custom animations
+
+You can easily show or hide rows with any custom transition; your view controller just need to be conform to the `ScrollStackRowAnimatable` protocol.
+This protocol defines a set of animation infos (duration, delay, spring etc.) and two events you can override to perform actions:
+
+```swift
+public protocol ScrollStackRowAnimatable {
+ /// Animation main info.
+ var animationInfo: ScrollStackAnimationInfo { get }
+
+ /// Animation will start to hide or show the row.
+ func willBeginAnimationTransition(toHide: Bool)
+
+ /// Animation to hide/show the row did end.
+ func didEndAnimationTransition(toHide: Bool)
+
+ /// Animation transition.
+ func animateTransition(toHide: Bool)
+}
+```
+
+So for example you can replicate the following animation:
+
+![](./Resources/custom_transition.gif)
+
+by using the following code:
+
+```swift
+extension WelcomeVC: ScrollStackRowAnimatable {
+ public var animationInfo: ScrollStackAnimationInfo {
+ return ScrollStackAnimationInfo(duration: 1, delay: 0, springDamping: 0.8)
+ }
+
+ public func animateTransition(toHide: Bool) {
+ switch toHide {
+ case true:
+ self.view.transform = CGAffineTransform(translationX: -100, y: 0)
+ self.view.alpha = 0
+
+ case false:
+ self.view.transform = .identity
+ self.view.alpha = 1
+ }
+ }
+
+ public func willBeginAnimationTransition(toHide: Bool) {
+ if toHide == false {
+ self.view.transform = CGAffineTransform(translationX: -100, y: 0)
+ self.view.alpha = 0
+ }
+ }
+
+}
+```
+
### Reload Rows
diff --git a/Resources/custom_transition.gif b/Resources/custom_transition.gif
new file mode 100644
index 0000000..5b9b6ae
Binary files /dev/null and b/Resources/custom_transition.gif differ
diff --git a/ScrollStackController.podspec b/ScrollStackController.podspec
index e0ba712..48e7161 100644
--- a/ScrollStackController.podspec
+++ b/ScrollStackController.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "ScrollStackController"
- s.version = "1.0.3"
+ s.version = "1.1.0"
s.summary = "Create complex scrollable layout using UIViewController and simplify your code"
s.homepage = "https://github.com/malcommac/ScrollStackController"
s.license = { :type => "MIT", :file => "LICENSE" }
diff --git a/ScrollStackController.xcodeproj/project.pbxproj b/ScrollStackController.xcodeproj/project.pbxproj
index 3a1e2e7..5d7dbe6 100644
--- a/ScrollStackController.xcodeproj/project.pbxproj
+++ b/ScrollStackController.xcodeproj/project.pbxproj
@@ -11,6 +11,8 @@
6402E1F22347A8540087963C /* Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6402E1F12347A8540087963C /* Extension.swift */; };
647C77B32348EA1600CAEB9F /* PricingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647C77B22348EA1600CAEB9F /* PricingVC.swift */; };
6489C0612349C571003E5344 /* NotesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6489C0602349C571003E5344 /* NotesVC.swift */; };
+ 649B1E9223B1251400BD6BFD /* ScrollStackRowAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649B1E9123B1251400BD6BFD /* ScrollStackRowAnimator.swift */; };
+ 649B1E9323B1251900BD6BFD /* ScrollStackRowAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649B1E9123B1251400BD6BFD /* ScrollStackRowAnimator.swift */; };
64A8E8B32348CCCE00E893FB /* WelcomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A8E8B02348CCCE00E893FB /* WelcomeVC.swift */; };
64C02255234735A800A6D844 /* ScrollStackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C0224F234735A800A6D844 /* ScrollStackViewController.swift */; };
64C02257234735A800A6D844 /* ScrollStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C02250234735A800A6D844 /* ScrollStack.swift */; };
@@ -50,6 +52,7 @@
6402E1F12347A8540087963C /* Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extension.swift; sourceTree = ""; };
647C77B22348EA1600CAEB9F /* PricingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PricingVC.swift; sourceTree = ""; };
6489C0602349C571003E5344 /* NotesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesVC.swift; sourceTree = ""; };
+ 649B1E9123B1251400BD6BFD /* ScrollStackRowAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollStackRowAnimator.swift; sourceTree = ""; };
64A8E8B02348CCCE00E893FB /* WelcomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeVC.swift; sourceTree = ""; };
64C0224F234735A800A6D844 /* ScrollStackViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollStackViewController.swift; sourceTree = ""; };
64C02250234735A800A6D844 /* ScrollStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollStack.swift; sourceTree = ""; };
@@ -131,6 +134,7 @@
children = (
64C0228523475A0E00A6D844 /* ScrollStack+Protocols.swift */,
64C02253234735A800A6D844 /* UIView+AutoLayout_Extensions.swift */,
+ 649B1E9123B1251400BD6BFD /* ScrollStackRowAnimator.swift */,
);
path = Support;
sourceTree = "";
@@ -346,6 +350,7 @@
64C02259234735A800A6D844 /* ScrollStackRow.swift in Sources */,
64C02255234735A800A6D844 /* ScrollStackViewController.swift in Sources */,
64C02257234735A800A6D844 /* ScrollStack.swift in Sources */,
+ 649B1E9223B1251400BD6BFD /* ScrollStackRowAnimator.swift in Sources */,
64C0225D234735A800A6D844 /* UIView+AutoLayout_Extensions.swift in Sources */,
64C0225B234735A800A6D844 /* ScrollStackSeparator.swift in Sources */,
);
@@ -371,6 +376,7 @@
64C0226C2347360800A6D844 /* ViewController.swift in Sources */,
64C022812347582D00A6D844 /* ScrollStackSeparator.swift in Sources */,
64C0227E2347582D00A6D844 /* ScrollStack.swift in Sources */,
+ 649B1E9323B1251900BD6BFD /* ScrollStackRowAnimator.swift in Sources */,
64C022682347360800A6D844 /* AppDelegate.swift in Sources */,
647C77B32348EA1600CAEB9F /* PricingVC.swift in Sources */,
6402E1F22347A8540087963C /* Extension.swift in Sources */,
@@ -529,6 +535,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+ CURRENT_PROJECT_VERSION = 0;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -537,6 +544,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MARKETING_VERSION = 1.1.0;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.ScrollStackController.ScrollStackController-iOS";
PRODUCT_NAME = ScrollStackController;
@@ -552,6 +560,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+ CURRENT_PROJECT_VERSION = 0;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@@ -560,6 +569,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.ScrollStackController.ScrollStackController-iOS";
PRODUCT_NAME = ScrollStackController;
SKIP_INSTALL = YES;
diff --git a/ScrollStackController.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate b/ScrollStackController.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate
index 0503094..6c7f08b 100644
Binary files a/ScrollStackController.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate and b/ScrollStackController.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/ScrollStackController.xcodeproj/xcshareddata/xcschemes/ScrollStackController-tvOS.xcscheme b/ScrollStackController.xcodeproj/xcshareddata/xcschemes/ScrollStackController-tvOS.xcscheme
deleted file mode 100644
index ee49815..0000000
--- a/ScrollStackController.xcodeproj/xcshareddata/xcschemes/ScrollStackController-tvOS.xcscheme
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ScrollStackController.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist b/ScrollStackController.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist
index daa61db..0bfd023 100644
--- a/ScrollStackController.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/ScrollStackController.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -9,15 +9,10 @@
orderHint
0
- ScrollStackController-tvOS.xcscheme_^#shared#^_
-
- orderHint
- 1
-
ScrollStackControllerDemo.xcscheme_^#shared#^_
orderHint
- 2
+ 1
diff --git a/ScrollStackControllerDemo/Base.lproj/Main.storyboard b/ScrollStackControllerDemo/Base.lproj/Main.storyboard
index 45831c3..fc3ee39 100644
--- a/ScrollStackControllerDemo/Base.lproj/Main.storyboard
+++ b/ScrollStackControllerDemo/Base.lproj/Main.storyboard
@@ -1,8 +1,8 @@
-
+
-
+
@@ -165,8 +165,8 @@
-
-
+
+
@@ -233,20 +233,20 @@
-
-
+
+
-
-
-
-
+
+
+
+
-
+
@@ -261,8 +261,8 @@
-
-
+
+
@@ -275,7 +275,7 @@
-
+
@@ -357,21 +357,21 @@
-
-
+
+
-
+
-
+
-
-
+
+
-
+
@@ -386,8 +386,8 @@
-
-
+
+
@@ -420,19 +420,19 @@
-
-
+
+
-
+
-
+
-
+
-
+
@@ -446,8 +446,8 @@
-
-
+
+
@@ -536,23 +536,23 @@
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
-
+
@@ -566,8 +566,8 @@
-
-
+
+
@@ -599,18 +599,18 @@ Set in the heart of the Culture Village, less than 15 minutes away from Dubai In
-
+
-
-
+
+
-
+
-
+
diff --git a/ScrollStackControllerDemo/Child View Controllers/TagsVC.swift b/ScrollStackControllerDemo/Child View Controllers/TagsVC.swift
index 9385900..e7b53e9 100644
--- a/ScrollStackControllerDemo/Child View Controllers/TagsVC.swift
+++ b/ScrollStackControllerDemo/Child View Controllers/TagsVC.swift
@@ -49,7 +49,8 @@ public class TagsVC: UIViewController, ScrollStackContainableController {
}
public func scrollStackRowSizeForAxis(_ axis: NSLayoutConstraint.Axis, row: ScrollStackRow, in stackView: ScrollStack) -> ScrollStack.ControllerSize? {
- return (isExpanded == false ? .fixed(170) : .fixed(170 + collectionView.contentSize.height + 20))
+ collectionView.layoutIfNeeded()
+ return (isExpanded == false ? .fixed(130) : .fixed(130 + collectionView.contentSize.height + 20))
}
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
diff --git a/ScrollStackControllerDemo/Child View Controllers/WelcomeVC.swift b/ScrollStackControllerDemo/Child View Controllers/WelcomeVC.swift
index 466927e..b442127 100644
--- a/ScrollStackControllerDemo/Child View Controllers/WelcomeVC.swift
+++ b/ScrollStackControllerDemo/Child View Controllers/WelcomeVC.swift
@@ -24,7 +24,34 @@ public class WelcomeVC: UIViewController, ScrollStackContainableController {
}
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
+
+ }
+
+}
+
+extension WelcomeVC: ScrollStackRowAnimatable {
+
+ public var animationInfo: ScrollStackAnimationInfo {
+ return ScrollStackAnimationInfo(duration: 1, delay: 0, springDamping: 0.8)
+ }
+ public func animateTransition(toHide: Bool) {
+ switch toHide {
+ case true:
+ self.view.transform = CGAffineTransform(translationX: -100, y: 0)
+ self.view.alpha = 0
+
+ case false:
+ self.view.transform = .identity
+ self.view.alpha = 1
+ }
+ }
+
+ public func willBeginAnimationTransition(toHide: Bool) {
+ if toHide == false {
+ self.view.transform = CGAffineTransform(translationX: -100, y: 0)
+ self.view.alpha = 0
+ }
}
}
diff --git a/Sources/ScrollStackController/ScrollStack.swift b/Sources/ScrollStackController/ScrollStack.swift
index e9a2ab7..0ae5081 100644
--- a/Sources/ScrollStackController/ScrollStack.swift
+++ b/Sources/ScrollStackController/ScrollStack.swift
@@ -209,7 +209,7 @@ open class ScrollStack: UIScrollView, UIScrollViewDelegate {
internal var onChangeRow: ((_ row: ScrollStackRow, _ isRemoved: Bool) -> Void)?
/// Innert stack view.
- private let stackView = UIStackView()
+ public let stackView = UIStackView()
/// Constraints to manage the main axis set.
private var axisConstraint: NSLayoutConstraint?
@@ -446,10 +446,11 @@ open class ScrollStack: UIScrollView, UIScrollViewDelegate {
return
}
- row.layoutIfNeeded()
- UIView.execute({
+ let coordinator = ScrollStackRowAnimator(row: row, toHidden: isHidden, internalHandler: {
row.isHidden = isHidden
- }, completion: completion)
+ row.layoutIfNeeded()
+ })
+ coordinator.execute()
}
/// Hide/Show selected rows.
diff --git a/Sources/ScrollStackController/Support/ScrollStackRowAnimator.swift b/Sources/ScrollStackController/Support/ScrollStackRowAnimator.swift
new file mode 100644
index 0000000..a543b8a
--- /dev/null
+++ b/Sources/ScrollStackController/Support/ScrollStackRowAnimator.swift
@@ -0,0 +1,151 @@
+/*
+ * ScrollStackController
+ * Create complex scrollable layout using UIViewController and simplify your code
+ *
+ * Created by: Daniele Margutti
+ * Email: hello@danielemargutti.com
+ * Web: http://www.danielemargutti.com
+ * Twitter: @danielemargutti
+ *
+ * Copyright © 2019 Daniele Margutti
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+import UIKit
+
+// MARK: - ScrollStackRowAnimatable
+
+public protocol ScrollStackRowAnimatable {
+
+ /// Animation main info.
+ var animationInfo: ScrollStackAnimationInfo { get }
+
+ /// Animation will start to hide or show the row.
+ /// - Parameter toHide: hide or show transition.
+ func willBeginAnimationTransition(toHide: Bool)
+
+ /// Animation to hide/show the row did end.
+ /// - Parameter toHide: hide or show transition.
+ func didEndAnimationTransition(toHide: Bool)
+
+ /// Animation transition.
+ /// - Parameter toHide: hide or show transition.
+ func animateTransition(toHide: Bool)
+
+}
+
+// MARK: - ScrollStackRowAnimatable Extension
+
+public extension ScrollStackRowAnimatable where Self: UIViewController {
+
+ var animationInfo: ScrollStackAnimationInfo {
+ return ScrollStackAnimationInfo()
+ }
+
+ func animateTransition(toHide: Bool) {
+
+ }
+
+ func willBeginAnimationTransition(toHide: Bool) {
+
+ }
+
+ func didEndAnimationTransition(toHide: Bool) {
+
+ }
+
+}
+
+
+// MARK: - ScrollStackAnimationInfo
+
+public struct ScrollStackAnimationInfo {
+
+ /// Duration of the animation. By default is set to `0.25`.
+ var duration: TimeInterval
+
+ /// Delay before start animation.
+ var delay: TimeInterval
+
+ /// The springDamping value used to determine the amount of `bounce`.
+ /// Default Value is `0.8`.
+ var springDamping: CGFloat
+
+ public init(duration: TimeInterval = 0.25, delay: TimeInterval = 0, springDamping: CGFloat = 0.8) {
+ self.duration = duration
+ self.delay = delay
+ self.springDamping = springDamping
+ }
+
+}
+
+// MARK: - ScrollStackRowAnimator
+
+internal class ScrollStackRowAnimator {
+
+ /// Row to animate.
+ private let targetRow: ScrollStackRow
+
+ /// Final state after animation, hidden or not.
+ private let toHidden: Bool
+
+ /// Animation handler, used to perform actions for animation in `ScrollStack`.
+ private let internalHandler: () -> Void
+
+ /// Completion handler.
+ private let completion: ((Bool) -> Void)?
+
+ /// Target row if animatable.
+ private var animatableRow: ScrollStackRowAnimatable? {
+ return targetRow.controller as? ScrollStackRowAnimatable
+ }
+
+ // MARK: - Initialization
+
+ init(row: ScrollStackRow, toHidden: Bool,
+ internalHandler: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
+ self.targetRow = row
+ self.toHidden = toHidden
+ self.internalHandler = internalHandler
+ self.completion = completion
+ }
+
+ /// Execute animation.
+ func execute() {
+ animatableRow?.willBeginAnimationTransition(toHide: toHidden)
+
+ let duration = animatableRow?.animationInfo.duration ?? 0.25
+ UIView.animate(withDuration: duration,
+ delay: 0,
+ usingSpringWithDamping: animatableRow?.animationInfo.springDamping ?? 1,
+ initialSpringVelocity: 0,
+ options: [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState],
+ animations: {
+ self.animatableRow?.animateTransition(toHide: self.toHidden)
+ self.internalHandler()
+ }) { finished in
+ self.animatableRow?.didEndAnimationTransition(toHide: self.toHidden)
+ self.completion?(finished)
+ }
+ }
+
+}