Skip to content

Commit

Permalink
Updates to ItemCoordinator to properly support animations driven by B…
Browse files Browse the repository at this point in the history
…lueprint-backed item content.
  • Loading branch information
kyleve committed Mar 3, 2021
1 parent d777ba0 commit eda97ec
Show file tree
Hide file tree
Showing 17 changed files with 260 additions and 138 deletions.
9 changes: 9 additions & 0 deletions BlueprintUILists/Sources/BlueprintHeaderFooterContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ public extension BlueprintHeaderFooterContent
views.content.element = self.elementRepresentation.wrapInBlueprintEnvironmentFrom(environment: info.environment)
views.background.element = self.background?.wrapInBlueprintEnvironmentFrom(environment: info.environment)
views.pressed.element = self.pressedBackground?.wrapInBlueprintEnvironmentFrom(environment: info.environment)

/// `BlueprintView` does not update its content until the next layout cycle.
/// Force that layout cycle within this method if we're updating an already on-screen
/// `ItemContent`, to ensure that we inherit any animation blocks we may be within.
if reason == .wasUpdated {
views.content.layoutIfNeeded()
views.background.layoutIfNeeded()
views.pressed.layoutIfNeeded()
}
}

static func createReusableContentView(frame: CGRect) -> ContentView {
Expand Down
9 changes: 9 additions & 0 deletions BlueprintUILists/Sources/BlueprintItemContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ public extension BlueprintItemContent
views.content.element = self.element(with: info).wrapInBlueprintEnvironmentFrom(environment: info.environment)
views.background.element = self.backgroundElement(with: info)?.wrapInBlueprintEnvironmentFrom(environment: info.environment)
views.selectedBackground.element = self.selectedBackgroundElement(with: info)?.wrapInBlueprintEnvironmentFrom(environment: info.environment)

/// `BlueprintView` does not update its content until the next layout cycle.
/// Force that layout cycle within this method if we're updating an already on-screen
/// `ItemContent`, to ensure that we inherit any animation blocks we may be within.
if reason == .wasUpdated {
views.content.layoutIfNeeded()
views.background.layoutIfNeeded()
views.selectedBackground.layoutIfNeeded()
}
}

/// Creates the `BlueprintView` used to render the content of the item.
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Changed

- [Updates to `ItemContentCoordinator`](https://github.com/kyleve/Listable/pull/274) to properly support animations in Blueprint-backed rows. This change also generalizes the contained animation type to `ViewAnimation`, for use in both scrolling and content updates.

### Misc

# Past Releases
Expand Down
4 changes: 4 additions & 0 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
0AA4D9C8248064A300CF95A5 /* ReorderingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA4D9B7248064A300CF95A5 /* ReorderingViewController.swift */; };
0AA4D9C9248064A300CF95A5 /* CollectionViewBasicDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA4D9B8248064A300CF95A5 /* CollectionViewBasicDemoViewController.swift */; };
0AC2A1962489F93E00779459 /* PagedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC2A1952489F93E00779459 /* PagedViewController.swift */; };
0AC839A525EEAD110055CEF5 /* OnTapItemAnimationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC839A425EEAD110055CEF5 /* OnTapItemAnimationViewController.swift */; };
0ACF96D624A0094D0090EAC4 /* ItemInsertAndRemoveAnimationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACF96D524A0094D0090EAC4 /* ItemInsertAndRemoveAnimationsViewController.swift */; };
0AD6767A25423BE500A49315 /* MultiSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD6767925423BE500A49315 /* MultiSelectViewController.swift */; };
0ADC3B3524907C80008DF2C0 /* XcodePreviewDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ADC3B3424907C80008DF2C0 /* XcodePreviewDemo.swift */; };
Expand Down Expand Up @@ -74,6 +75,7 @@
0AA4D9B7248064A300CF95A5 /* ReorderingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReorderingViewController.swift; sourceTree = "<group>"; };
0AA4D9B8248064A300CF95A5 /* CollectionViewBasicDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewBasicDemoViewController.swift; sourceTree = "<group>"; };
0AC2A1952489F93E00779459 /* PagedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagedViewController.swift; sourceTree = "<group>"; };
0AC839A425EEAD110055CEF5 /* OnTapItemAnimationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnTapItemAnimationViewController.swift; sourceTree = "<group>"; };
0ACF96D524A0094D0090EAC4 /* ItemInsertAndRemoveAnimationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemInsertAndRemoveAnimationsViewController.swift; sourceTree = "<group>"; };
0AD6767925423BE500A49315 /* MultiSelectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiSelectViewController.swift; sourceTree = "<group>"; };
0ADC3B3424907C80008DF2C0 /* XcodePreviewDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodePreviewDemo.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -153,6 +155,7 @@
2B8804642490844A003BB351 /* SpacingCustomizationViewController.swift */,
0AA4D9B5248064A300CF95A5 /* SwipeActionsViewController.swift */,
0AA4D9AE248064A300CF95A5 /* WidthCustomizationViewController.swift */,
0AC839A425EEAD110055CEF5 /* OnTapItemAnimationViewController.swift */,
);
path = "Demo Screens";
sourceTree = "<group>";
Expand Down Expand Up @@ -443,6 +446,7 @@
0A66420B254A317A007F6B2F /* AutoLayoutDemoViewController.swift in Sources */,
0AEB96E222FBCC1D00341DFF /* AppDelegate.swift in Sources */,
0A793B5824E4B53500850139 /* ManualSelectionManagementViewController.swift in Sources */,
0AC839A525EEAD110055CEF5 /* OnTapItemAnimationViewController.swift in Sources */,
0AA4D9C9248064A300CF95A5 /* CollectionViewBasicDemoViewController.swift in Sources */,
0AA4D9BC248064A300CF95A5 /* KeyboardTestingViewController.swift in Sources */,
0AA4D9C1248064A300CF95A5 /* CoordinatorViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,15 @@ fileprivate struct PodcastElement : BlueprintItemContent, Equatable

let actions: CoordinatorActions
let info: CoordinatorInfo

var view : View?


init(actions: CoordinatorActions, info: CoordinatorInfo)
{
self.actions = actions
self.info = info
}

func wasSelected() {
self.actions.update(animated: true) {
self.actions.update(animation: .default) {
$0.content.showBottomBar = true
}

Expand Down Expand Up @@ -157,7 +155,7 @@ fileprivate struct PodcastElement : BlueprintItemContent, Equatable
}

func wasDeselected() {
self.actions.update(animated: true) {
self.actions.update(animation: .default) {
$0.content.showBottomBar = false
}
}
Expand Down
112 changes: 112 additions & 0 deletions Demo/Sources/Demos/Demo Screens/OnTapItemAnimationViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//
// OnTapItemAnimationViewController.swift
// Demo
//
// Created by Kyle Van Essen on 3/2/21.
// Copyright © 2021 Kyle Van Essen. All rights reserved.
//

import ListableUI
import BlueprintUI
import BlueprintUICommonControls
import BlueprintUILists

final class OnTapItemAnimationViewController : ListViewController {

override func configure(list: inout ListProperties) {

list.layout = .demoLayout

list("items") { section in

section += items.map { item in
Item(item) { item in
item.selectionStyle = .tappable
}
}

}
}
}

fileprivate struct ItemRow : BlueprintItemContent, Equatable {

var name : String
var price : String
var onTapText : String = "Added"

var isShowingPrice : Bool = true

var identifier: Identifier<ItemRow> {
.init(name)
}

func element(with info: ApplyItemContentInfo) -> Element {

Row { row in
row.verticalAlignment = .center

row.addFlexible(child: Label(text: self.name) { label in
label.font = .systemFont(ofSize: 18.0, weight: .semibold)
})

row.addFlexible(child: Overlay { overlay in
overlay.add(
Label(text: self.price) { label in
label.font = .systemFont(ofSize: 16.0, weight: .semibold)
}
.opacity(isShowingPrice ? 1 : 0)
)

overlay.add(
Label(text: self.onTapText) { label in
label.font = .systemFont(ofSize: 16.0, weight: .semibold)
}
.opacity(isShowingPrice ? 0 : 1)
)
})
}
.inset(uniform: 10.0)
.box(background: .white(0.95), corners: .rounded(radius: 10))
}

func makeCoordinator(
actions: CoordinatorActions,
info: CoordinatorInfo
) -> OnTapCoordinator
{
OnTapCoordinator(actions: actions, info: info)
}
}

fileprivate final class OnTapCoordinator : ItemContentCoordinator {
var actions: ItemRow.CoordinatorActions
var info: ItemRow.CoordinatorInfo

init(actions: ItemRow.CoordinatorActions, info: ItemRow.CoordinatorInfo) {
self.actions = actions
self.info = info
}

typealias ItemContentType = ItemRow

func wasSelected() {
self.actions.update { item in
item.content.isShowingPrice = false
}

self.actions.update(after: 1.0) { item in
item.content.isShowingPrice = true
}
}
}


fileprivate let items : [ItemRow] = [
.init(name: "Coffee", price: "$4.00"),
.init(name: "Cold Brew", price: "$5.00"),
.init(name: "Espresso", price: "$6.00"),
.init(name: "Flat White", price: "$5.00"),
.init(name: "Iced Coffee", price: "$5.00"),
.init(name: "Latte", price: "$6.00")
]
29 changes: 22 additions & 7 deletions Demo/Sources/Demos/DemosRootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,6 @@ public final class DemosRootViewController : ListViewController
self.push(LocalizedCollationViewController())
})

section += Item(
DemoItem(text: "Item Content Coordinator"),
selectionStyle: .selectable(),
onSelect : { _ in
self.push(CoordinatorViewController())
})

section += Item(
DemoItem(text: "Item Insert & Remove Animations"),
selectionStyle: .selectable(),
Expand Down Expand Up @@ -168,6 +161,28 @@ public final class DemosRootViewController : ListViewController
})
}

list("coordinator") { section in

section.header = HeaderFooter(
DemoHeader(title: "Item Coordinator")
)

section += Item(
DemoItem(text: "Expand / Collapse Items"),
selectionStyle: .selectable(),
onSelect : { _ in
self.push(CoordinatorViewController())
})

section += Item(
DemoItem(text: "Animating On Tap"),
selectionStyle: .selectable(),
onSelect : { _ in
self.push(OnTapItemAnimationViewController())
})

}

list("layouts") { section in

section.header = HeaderFooter(
Expand Down
4 changes: 2 additions & 2 deletions ListableUI/Sources/AutoScrollAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public enum AutoScrollAction {
_ destination : ScrollDestination? = nil,
onInsertOf insertedIdentifier: AnyIdentifier,
position: ScrollPosition,
animation: ScrollAnimation = .none,
animation: ViewAnimation = .none,
shouldPerform : @escaping (ListScrollPositionInfo) -> Bool = { _ in true },
didPerform : @escaping (ListScrollPositionInfo) -> () = { _ in }
) -> AutoScrollAction
Expand Down Expand Up @@ -115,7 +115,7 @@ extension AutoScrollAction
/// ----
/// The action will only be animated if it is animated, **and** the list update itself is
/// animated. Otherwise, no animation occurs.
public var animation : ScrollAnimation
public var animation : ViewAnimation

/// An additional check you may provide to approve or reject the scroll action.
public var shouldPerform : (ListScrollPositionInfo) -> Bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ protocol AnyPresentationItemState : AnyObject

protocol ItemContentCoordinatorDelegate : AnyObject
{
func coordinatorUpdated(for item : AnyItem, animated : Bool)
func coordinatorUpdated(for item : AnyItem)
}


Expand Down Expand Up @@ -155,16 +155,17 @@ extension PresentationState

weak var coordinatorDelegate = dependencies.coordinatorDelegate

self.coordination.actions.updateCallback = { [weak self, weak coordinatorDelegate] new, animated in
self.coordination.actions.updateCallback = { [weak self, weak coordinatorDelegate] new, animation in
guard let self = self, let delegate = coordinatorDelegate else {
return
}

self.setNew(item: new, reason: .updateFromItemCoordinator, updateCallbacks: UpdateCallbacks(.immediate))

delegate.coordinatorUpdated(for: self.anyModel, animated: animated)

self.applyToVisibleCell(with: dependencies.environmentProvider())
animation.perform {
self.applyToVisibleCell(with: dependencies.environmentProvider())
delegate.coordinatorUpdated(for: self.anyModel)
}
}

self.storage.didSetState = { [weak self] old, new in
Expand Down Expand Up @@ -398,15 +399,10 @@ extension PresentationState
}

if old.visibleCell != new.visibleCell {
if let cell = new.visibleCell {
let contentView = cell.contentContainer.contentView

coordinator.view = contentView
coordinator.willDisplay(with: contentView)
if new.visibleCell != nil {
coordinator.willDisplay()
} else {
if let view = old.visibleCell?.contentContainer.contentView {
coordinator.didEndDisplay(with: view)
}
coordinator.didEndDisplay()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion ListableUI/Sources/Item/ItemContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ public extension ItemContent where Coordinator == DefaultItemContentCoordinator<
{
func makeCoordinator(actions : ItemContentCoordinatorActions<Self>, info : ItemContentCoordinatorInfo<Self>) -> Coordinator
{
DefaultItemContentCoordinator(actions: actions, info: info, view: nil)
DefaultItemContentCoordinator(actions: actions, info: info)
}
}

Expand Down
Loading

0 comments on commit eda97ec

Please sign in to comment.