Skip to content

Commit 81f1787

Browse files
authored
Implement Opacity Effect (#572)
1 parent 581a7e0 commit 81f1787

File tree

12 files changed

+582
-16
lines changed

12 files changed

+582
-16
lines changed

Example/HostingExample/ViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ class ViewController: NSViewController {
6666

6767
struct ContentView: View {
6868
var body: some View {
69-
DynamicLayoutViewExample()
69+
MyViewThatFitsExample()
7070
}
7171
}
File renamed without changes.

Example/SharedExample/Layout/MyViewThatFitsByLayout.swift renamed to Example/SharedExample/Layout/CustomLayout/MyViewThatFitsByLayout.swift

File renamed without changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// MyViewThatFitsExample.swift
3+
// SharedExample
4+
5+
#if OPENSWIFTUI
6+
import OpenSwiftUI
7+
#else
8+
import SwiftUI
9+
#endif
10+
11+
// The DL does not fully align since we have not implement canonicalize API yet.
12+
// See https://github.com/OpenSwiftUIProject/OpenSwiftUI/issues/349
13+
struct MyViewThatFitsExample: View {
14+
@State private var showRed = false
15+
var body: some View {
16+
MyViewThatFitsByLayout {
17+
Color.red.frame(width: 100, height: 200)
18+
Color.blue.frame(width: 200, height: 100)
19+
}
20+
.frame(width: 100, height: showRed ? 200 : 100)
21+
.onAppear {
22+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
23+
showRed.toggle()
24+
}
25+
}
26+
.id(showRed)
27+
}
28+
}

Example/SharedExample/Layout/MyZStackLayout.swift renamed to Example/SharedExample/Layout/CustomLayout/MyZStackLayout.swift

File renamed without changes.

Sources/OpenSwiftUICore/Animation/Animatable/Animatable.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package import OpenAttributeGraphShims
1111
// MARK: - Animatable
1212

1313
/// A type that describes how to animate a property of a view.
14+
@available(OpenSwiftUI_v1_0, *)
1415
public protocol Animatable {
1516
/// The type defining the data to animate.
1617
associatedtype AnimatableData: VectorArithmetic
@@ -25,13 +26,15 @@ public protocol Animatable {
2526

2627
// MARK: - Animateble + Extension
2728

29+
@available(OpenSwiftUI_v1_0, *)
2830
extension Animatable where Self: VectorArithmetic {
2931
public var animatableData: Self {
3032
get { self }
3133
set { self = newValue }
3234
}
3335
}
3436

37+
@available(OpenSwiftUI_v1_0, *)
3538
extension Animatable where AnimatableData == EmptyAnimatableData {
3639
public var animatableData: EmptyAnimatableData {
3740
@inlinable
@@ -59,6 +62,7 @@ extension Attribute where Value: Animatable {
5962
}
6063
}
6164

65+
@available(OpenSwiftUI_v1_0, *)
6266
extension Animatable {
6367
public static func _makeAnimatable(value: inout _GraphValue<Self>, inputs: _GraphInputs) {
6468
guard MemoryLayout<AnimatableData>.size != 0,
@@ -84,6 +88,7 @@ extension Animatable {
8488
///
8589
/// This type is suitable for use as the `animatableData` property of
8690
/// types that do not have any animatable properties.
91+
@available(OpenSwiftUI_v1_0, *)
8792
@frozen
8893
public struct EmptyAnimatableData: VectorArithmetic {
8994
@inlinable
@@ -113,10 +118,12 @@ public struct EmptyAnimatableData: VectorArithmetic {
113118
public static func == (_: EmptyAnimatableData, _: EmptyAnimatableData) -> Bool { true }
114119
}
115120

121+
@available(OpenSwiftUI_v5_0, *)
116122
extension Double: Animatable {
117123
public typealias AnimatableData = Double
118124
}
119125

126+
@available(OpenSwiftUI_v5_0, *)
120127
extension CGFloat: Animatable {
121128
public typealias AnimatableData = CGFloat
122129
}

Sources/OpenSwiftUICore/Animation/Transition/ContentTransition.swift

Lines changed: 196 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
// TODO
66

7+
public import OpenCoreGraphicsShims
8+
package import OpenRenderBoxShims
9+
710
@available(OpenSwiftUI_v4_0, *)
811
public struct ContentTransition: Equatable, Sendable {
912
package enum Storage: Equatable, @unchecked Sendable {
@@ -72,8 +75,199 @@ public struct ContentTransition: Equatable, Sendable {
7275

7376
// TODO: NumericTextConfiguration
7477

78+
@_spi(Private)
79+
public struct EffectType: Equatable, Sendable {
80+
package enum Arg: Equatable, Sendable {
81+
case none
82+
case float(Float)
83+
case int(UInt32)
84+
}
85+
86+
package var type: ORBTransitionEffectType
87+
package var arg0: ContentTransition.EffectType.Arg, arg1: ContentTransition.EffectType.Arg
88+
89+
package init(
90+
type: ORBTransitionEffectType,
91+
arg0: ContentTransition.EffectType.Arg = .none,
92+
arg1: ContentTransition.EffectType.Arg = .none
93+
) {
94+
self.type = type
95+
self.arg0 = arg0
96+
self.arg1 = arg1
97+
}
98+
99+
public static var opacity: ContentTransition.EffectType {
100+
self.init(type: .opacity, arg0: .none, arg1: .none)
101+
}
102+
103+
@available(*, deprecated, message: "use opacity variable")
104+
public static func opacity(_ opacity: Double = 0) -> ContentTransition.EffectType {
105+
self.init(type: .opacity, arg0: .none, arg1: .none)
106+
}
107+
108+
public static func blur(radius: CGFloat) -> ContentTransition.EffectType {
109+
self.init(type: .blur, arg0: .float(Float(radius)), arg1: .none)
110+
}
111+
112+
@available(OpenSwiftUI_v6_0, *)
113+
public static func relativeBlur(scale: CGSize) -> ContentTransition.EffectType {
114+
self.init(type: .relativeBlur, arg0: .float(Float(scale.width)), arg1: .float(Float(scale.height)))
115+
}
116+
117+
public static func scale(_ scale: CGFloat = 0) -> ContentTransition.EffectType {
118+
self.init(type: .scale, arg0: .float(Float(scale)), arg1: .none)
119+
}
120+
121+
public static func translation(_ size: CGSize) -> ContentTransition.EffectType {
122+
self.init(type: .translationSize, arg0: .float(Float(size.width)), arg1: .float(Float(size.height)))
123+
}
124+
125+
@available(OpenSwiftUI_v6_0, *)
126+
public static func translation(scale: CGSize) -> ContentTransition.EffectType {
127+
self.init(type: .translationScale, arg0: .float(Float(scale.width)), arg1: .float(Float(scale.height)))
128+
}
129+
130+
public static var matchMove: ContentTransition.EffectType {
131+
self.init(type: .matchMove, arg0: .none, arg1: .none)
132+
}
133+
}
134+
135+
@_spi(Private)
136+
@available(OpenSwiftUI_v6_0, *)
137+
public enum SequenceDirection: Hashable, Sendable {
138+
case leading, trailing, up, down
139+
case forwards, backwards
140+
}
141+
142+
@_spi(Private)
143+
public struct Effect: Equatable, Sendable {
144+
package var type: ContentTransition.EffectType
145+
package var begin: Float
146+
package var duration: Float
147+
package var events: ORBTransitionEvents
148+
package var flags: ORBTransitionEffectFlags
149+
150+
package init(
151+
type: ContentTransition.EffectType,
152+
begin: Float = 0,
153+
duration: Float = 1,
154+
events: ORBTransitionEvents = .addRemove,
155+
flags: ORBTransitionEffectFlags = .init()
156+
) {
157+
self.type = type
158+
self.begin = begin
159+
self.duration = duration
160+
self.events = events
161+
self.flags = flags
162+
}
163+
164+
public init(
165+
_ type: ContentTransition.EffectType,
166+
timeline: ClosedRange<Float> = 0 ... 1,
167+
appliesOnInsertion: Bool = true,
168+
appliesOnRemoval: Bool = true
169+
) {
170+
self.type = type
171+
self.begin = timeline.lowerBound
172+
self.duration = timeline.upperBound - timeline.lowerBound
173+
self.events = [
174+
appliesOnInsertion ? .add : [],
175+
appliesOnRemoval ? .remove : [],
176+
]
177+
self.flags = []
178+
}
179+
180+
@available(OpenSwiftUI_v6_0, *)
181+
public static func sequence(
182+
direction: ContentTransition.SequenceDirection,
183+
delay: Double,
184+
maxAllowedDurationMultiple: Double = .infinity,
185+
appliesOnInsertion: Bool = true,
186+
appliesOnRemoval: Bool = true
187+
) -> ContentTransition.Effect {
188+
_openSwiftUIUnimplementedFailure()
189+
}
190+
191+
@available(OpenSwiftUI_v6_0, *)
192+
public func removeInverts(_ state: Bool) -> ContentTransition.Effect {
193+
_openSwiftUIUnimplementedFailure()
194+
}
195+
}
196+
197+
@_spi(Private)
198+
public struct Method: Equatable, Sendable {
199+
package var method: ORBTransitionMethod
200+
201+
package init(method: ORBTransitionMethod) {
202+
self.method = method
203+
}
204+
205+
public static let diff: ContentTransition.Method = .init(method: .diff)
206+
207+
public static let forwards: ContentTransition.Method = .init(method: .forwards)
208+
209+
public static let backwards: ContentTransition.Method = .init(method: .backwards)
210+
211+
public static let prefix: ContentTransition.Method = .init(method: .prefix)
212+
213+
public static let suffix: ContentTransition.Method = .init(method: .suffix)
214+
215+
public static let prefixAndSuffix: ContentTransition.Method = .init(method: .prefixAndSuffix)
216+
217+
public static let binary: ContentTransition.Method = .init(method: .binary)
218+
219+
public static let none: ContentTransition.Method = .init(method: .none)
220+
221+
public static func == (a: ContentTransition.Method, b: ContentTransition.Method) -> Bool {
222+
a.method == b.method
223+
}
224+
}
225+
75226
// TODO
76-
package enum Effect {}
227+
package struct State {}
228+
}
229+
230+
// FIXME: ORB
231+
232+
package enum ORBTransitionMethod: Int {
233+
case empty
234+
case diff
235+
case forwards
236+
case backwards
237+
case prefix
238+
case suffix
239+
case binary
240+
case none
241+
case prefixAndSuffix
242+
}
243+
244+
// ProtobufEnum
245+
package struct ORBTransitionEvents: OptionSet {
246+
package let rawValue: UInt32
247+
248+
package init(rawValue: UInt32) {
249+
self.rawValue = rawValue
250+
}
251+
252+
public static let add: ORBTransitionEvents = .init(rawValue: 1)
253+
public static let remove: ORBTransitionEvents = .init(rawValue: 2)
254+
public static let addRemove: ORBTransitionEvents = .init(rawValue: 3)
255+
}
256+
257+
package struct ORBTransitionEffectFlags: OptionSet {
258+
package let rawValue: UInt32
259+
260+
package init(rawValue: UInt32) {
261+
self.rawValue = rawValue
262+
}
263+
}
77264

78-
package enum State {}
265+
package enum ORBTransitionEffectType: UInt32, Equatable {
266+
case opacity = 1
267+
case scale = 2
268+
case translationSize = 3
269+
case blur = 4
270+
case matchMove = 5
271+
case translationScale = 15
272+
case relativeBlur = 16
79273
}

Sources/OpenSwiftUICore/Render/DisplayList/DisplayList.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ extension PreferencesOutputs {
477477

478478
extension DisplayList.Item {
479479
package mutating func canonicalize(options: DisplayList.Options = .init()) {
480-
// TODO
480+
// TODO eg. .opacity(1.0) -> .identity
481481
}
482482

483483
// package func matchesTopLevelStructure(of other: DisplayList.Item) -> Bool

0 commit comments

Comments
 (0)