All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Fixed an issue where
Label
andAttributedLabel
were not accessibility elements.
-
The
Environment
is now automatically propagated through to nestedBlueprintViews
within a displayedElement
hierarchy. This means that if your view-backedElements
themselves contain aBlueprintView
(eg to manage their own state), that nested view will now automatically receive the correctEnvironment
acrossBlueprintView
boundaries. If you were previously manually propagatingEnvironment
values you may remove this code. If you would like to opt-out of this behavior; you can setview.automaticallyInheritsEnvironmentFromContainingBlueprintViews = false
on yourBlueprintView
. -
Lifecycle hooks. You can hook into lifecycle events when an element's visibility changes.
element .onAppear { // runs when `element` appears } .onDisappear { // runs when `element` disappears }
0.27.0 - 2021-06-22
- The signature of
Element.backingViewDescription(bounds: CGRect, subtreeExtent: CGRect?) -> ViewDescription?
has changed tobackingViewDescription(with context: ViewDescriptionContext) -> ViewDescription?
(square#231). This is a large breaking change, but is worth it as it allows us to pass additional context tobackingViewDescription
in the future in a non-breaking way. TheViewDescriptionContext
contains thebounds
andsubtreeExtent
, as well as theEnvironment
the element is rendered in.
0.26.0 - 2021-06-02
- Add
ScrollTrigger
, which adds the ability set the content offset of aScrollView
- Add
UIViewElementContext
toUIViewElement.updateUIView
. The context currently has one property,isMeasuring
, which tells you if the view being updated is the static measuring instance.
0.25.0 - 2021-05-5
- Expose
contentInsetAdjustmentBehavior
onScrollView
.
0.24.0 - 2021-04-16
-
Add
Keyed
element, which can be used to help differentiate elements during the diff and update process, eg to assist with proper animation transitions. -
Introduce
GridRow
, aRow
alternative suited for columnar layout.GridRow
supports the following:- spacing
- vertical alignment
- children with absolutely-sized widths
- children with proportionally-sized widths¹
¹Proportional width in this case always means "a proportion of available layout space after spacing and absolutely-sized children are laid out."
Example:
GridRow { row in row.spacing = 8 row.verticalAlignment = .center row.add(width: .absolute(50), child: authorLabel) row.add(width: .proportional(0.75), child: bodyLabel) row.add(width: .proportional(0.25), child: dateLabel) }
-
Added support to
LayoutWriter
to allow specifying keys for childElement
s. -
Blueprint can now emit signpost logs during its render pass, which you can use for performance tuning. (#209)
Signpost logs are disabled by default. To enable them, set
BlueprintLogging.enabled = true
.
- The layout system now uses a caching system to improve performance by eliminating redundant measurements. (#209)
0.23.0 - 2021-03-26
- Introduce
UserInteractionEnabled
, an element which conditionally enables user interaction of wrapped elements.
searchField
.userInteractionEnabled(canBeginSearch)
-
Change
ProxyElement
to directly return the content of a child. This significantly speeds up deeper element hierarchies that are made up of proxy elements, by reducing the duplicate calculation work that needs to be done to layout an element tree. -
Change backing view of
TransitionContainer
to not directly receive touches while still allowing subviews to do so.
0.22.0 - 2021-03-15
- Introduce
Decorate
to allow placing a decoration element in front or behind of anElement
, without affecting its layout. This is useful for rendering tap or selection states which should overflow the natural bounds of theElement
, similar to a shadow, or useful for adding a badge to anElement
.
0.21.0 - 2021-02-17
- Introduce conditionals on
Element
to allow you to perform inline checks likeif
,if let
, andmap
when buildingElement
trees.
- Introduce additional APIs on
Overlay
to ease conditional construction theOverlay
elements.
0.20.0 - 2021-01-12
- Add
Transformed
element to apply aCATransform3D
to a wrapped element.
0.19.1 - 2021-01-06
- Remove compile time validation from
Element
s, since it caused compile-time errors in certain cases when extensions andwhere
clauses were used.
0.19.0 - 2021-01-05
Ensure thatElement
s are a value type. This is generally assumed by Blueprint, but was previously not validated. This is only validated inDEBUG
builds, to avoid otherwise affecting performance.
- Add
LayoutWriter
, which makes creating custom / arbitrary layouts much simpler. You no longer need to define a customLayout
type; instead, you can just utilizeLayoutWriter
and configure and place your children within its builder initializer.
0.18.0 - 2020-12-08
- Add
AccessibilityContainer.identifier
([#180])
0.17.1 - 2020-10-30
-
Fixed an issue where view descriptions were applied with unintentional animations while creating backing views. This could happen if an element was added during a transition. (#175)
-
Fixed pull-to-refresh inset for iOS 13+. (#176)
0.17.0 - 2020-10-21
-
Add alignment guides to stacks. (#153)
Alignment guides let you fine-tune the cross axis alignment. You can specifying a guide value for any child in that element's coordinate space. Children are aligned relatively to each other so that the guide values line up, and then the content as a whole is aligned to the stack's bounds.
In this example, the center of one element is aligned 10 points from the bottom of another element, and the contents are collectively aligned to the bottom of the row:
Row { row in row.verticalAlignment = .bottom row.add( alignmentGuide: { d in d[VerticalAlignment.center] }, child: element1 ) row.add( alignmentGuide: { d in d.height - 10 }, child: element2 ) }
- Removed support for iOS 10. Future releases will only support iOS 11 and later.
Row
alignmentsleading
andtrailing
are deprecated. Usetop
andbottom
instead. (#153)
0.16.0 - 2020-09-22
- Fixed
EqualStack
to properly constrain children when measuring. (#157)
-
Add a new
TransitionContainer.init
that supports further customization during initialization and has the same defaults asViewDescription
. (#155, #158) -
Add
transition(onAppear:onDisappear:onLayout)
andtransition(_:)
methods toElement
to describe transition animations. (#155, #158)
- Remove
GridLayout
; it's incomplete and was never really intended to be consumed widely. The intended replacement is puttingEqualStacks
inside of aColumn
, orRows
inside aColumn
.
TransitionContainer(wrapping:)
is deprecated. Use the newTransitionContainer(transitioning:)
instead. (#158)
- Removed some redundant work being done during rendering. (#154)
0.15.1 - 2020-09-16
- Fixes a crash that can occur in
Box
when specifying a corner radius and shadow. (#149)
0.15.0 - 2020-09-14
-
Add
addFixed(child:)
andaddFlexible(child:)
methods toStackElement
for adding children with a grow & shrink priority of 0.0 and 1.0 respectively. (#143) -
Add
capsule
case toBox.CornerStyle
(#145). This addition sugars the following pattern:GeometryReader { geometry in Box(cornerStyle: .rounded(geometry.constraint.height.maximum / 2.0)) }
into
Box(cornerStyle: .capsule)
-
Add
accessibilityFrameSize
toAccessibilityElement
for manually specifying a size for the frame rendered by Voice Over. (#144) -
Add
Opacity
element for modifying the opacity of a wrapped element. (#147)
BlueprintView
will calllayoutIfNeeded
on backing views during its layout pass. This allows backing views' subviews that are laid out duringlayoutSubviews
to participate in animations. (#139)
0.14.0 - 2020-08-12
-
Add
textColor
property on TextField (#133). -
Add the
windowSize
environment key. (#134) -
Add
GeometryReader
. (#135)This element allow you to compose elements whose contents depend on the amount of space available.
Here is an example that dynamically chooses an image based on the width available:
GeometryReader { (geometry) -> Element in let image: UIImage switch geometry.constraint.width.maximum { case ..<100: image = UIImage(named: "small")! case 100..<500: image = UIImage(named: "medium")! default: image = UIImage(named: "large")! } return Image(image: image) }
- Default
ScrollView.delaysContentTouches
totrue
(#132)
- Set an explicit shadow path on
Box
(#137)
0.13.1 - 2020-07-30
-
Introduce
AccessibilityContainer
element for wrapping an element with multiple sub-elements that should be in a voice over container. -
Add
font
property on TextField (#127).
0.13.0 - 2020-07-20
-
Update the scroll indicator inset when adjusting the content inset.
-
Label
&AttributedLabel
use an internalUILabel
for measurement. This fixes measurement when there is a line limit set. However, it also means that the screen scale cannot be specified and is always assumed to beUIScreen.main.scale
. These elements may not be measured correctly if they are placed on a screen other thanUIScreen.main
. (#120)
-
Introduce MeasurementCachingKey, to allow for elements to provide a way to cache their measurement during layout passes. This provides performance optimizations for elements whose layout and measurement is expensive to calculate.
-
Introduce
UIViewElement
to make wrapping self-sizing UIViews easier.You can now write a
UIViewElement
like this:struct Switch : UIViewElement { var isOn : Bool typealias UIViewType = UISwitch static func makeUIView() -> UISwitch { UISwitch() } func updateUIView(_ view: UISwitch) { view.isOn = self.isOn } }
And the elements will be sized and presented correctly based on the view's
sizeThatFits
. -
Add
isAccessibilityElement
toLabel
andAttributedLabel
. (#120) -
Add
lineHeight
toLabel
for specifying custom line heights.AttributedLabel
has atextRectOffset
property to support this. (#120)
- Update Demo app to support more demo screen types.
0.12.2 - 2020-06-08
- Fix erroneous use of
frame
instead ofbounds
when laying outBlueprintView
.
- Add delaysContentTouches to the
ScrollView
element.
0.12.1 - 2020-06-05
- Use default environment when measuring
BlueprintView
.
0.12.0 - 2020-06-04
-
Add support for the iPhone SE 2 in
ElementPreview
. -
Added
tintColor
andcontentMode
into the initializer forImage
. (#100) -
Added an Empty element, to mirror
EmptyView
in SwiftUI. It is an element with no size and draws no content. -
Environment (#101).
You can now read and write values from an
Environment
that is automatically propagated down the element tree. You can use these values to dynamically build the contents of an element, without having to explicitly pass every value through the tree yourself.You can read these values with
EnvironmentReader
:struct Foo: ProxyElement { var elementRepresentation: Element { EnvironmentReader { environment -> Element in Label(text: "value from environment: \(environment.foo)") } } }
And set them with
AdaptedEnvironment
:struct Bar: ProxyElement { var elementRepresentation: Element { ComplicatedElement() .adaptedEnvironment { environment in environment.foo = "bar" } } }
Several enviroment keys are available by default (#102):
- calendar
- display scale
- layout direction
- locale
- safe area insets
- time zone
You can create your own by making a type that conforms to
EnvironmentKey
, and extendingEnvironment
with a new property:extension Environment { private enum FooKey: EnvironmentKey { static let defaultValue: String = "default value" } /// The current Foo that elements should use. public var foo: String { get { self[FooKey.self] } set { self[FooKey.self] = newValue } } }
0.11.0 - 2020-05-10
-
Fixed
ConstrainedSize
to ensure that the measurement of its inner element respects theConstrainedSize
's maximum size, which matters for measuring elements which re-flow based on width, such as elements containing text. -
Changed BlueprintView.sizeThatFits(:) to treat width and height separately when determining if measurement should be unconstrained in a given axis.
-
Added support for
SwiftUI
-style element building withinBlueprintUI
andBlueprintUICommonControls
.This allows you to replace this code:
ScrollView(.fittingHeight) ( wrapping: Box( backgroundColor .lightGrey, wrapping: Inset( uniformInset: 10.0, wrapping: ConstrainedSize( height: .atLeast(20.0), wrapping: Label( text: "Hello, world!" ) ) ) ) )
With this code:
Label(text: "Hello, World!") .constrainedTo(height: .atLeast(20.0)) .inset(by: 20.0) .box(background: .lightGrey) .scrollable(.fittingHeight)
Improving readability and conciseness of your elements.
0.10.0 - 2020-04-27
- BlueprintView will align view frames to pixel boundaries after layout (#64).
0.9.2 - 2020-04-27
- Don't try to build
SwiftUI
previews on 32 bit ARM devices –SwiftUI
does not exist on these devices.
0.9.1 - 2020-04-17
- Weak link
SwiftUI
so if an app is not already linkingSwiftUI
, it will build correctly.
0.9.0 - 2020-04-17
- Add support for previewing Blueprint elements in Xcode / SwiftUI previews.
- Add accessibilityIdentifier support to
AccessibilityElement
.
0.8.0 - 2020-04-03
- Properly measure the child of
ScrollView
to allow for unconstrained measurement. - Fix stack layout during underflow (#72)
- ScrollView can automatically adjust its content inset for the keyboard (#55)
- Improved element diffing (#56)
0.7.0 - 2020-03-30
- Xcode 11 and Swift 5.1 support (#67).
- Change how stack layouts are measured to resolve an issue where text would be truncated.
- Raise minimum deployment target from iOS 9.3 to iOS 10 (#66).
0.6.0 - 2020-02-24
- Add
keyboardDismissMode
property on ScrollView (#57). - Add
textAlignment
property on TextField (#53).
0.5.0 - 2020-01-24
- Prevent divide-by-zero when a stack contains zero-size elements (#52).
- Add
fill
alignment to Aligned (#42).
0.4.0 - 2019-12-04
- Public init on Aligned (#41).
- Guarantee that subviews are ordered the same as their associated elements (#32).
0.3.1 - 2019-11-15
- Do not run snapshot tests from CocoaPods (#40).
- Make tests with float comparisons more lenient for 32-bit (#35).
- Add Swift Package Manager support (#37).
- Add Getting Started section to README (#38).
0.3.0 - 2019-11-12
- Add Stack alignment options
justifyToStart
,justifyToCenter
, andjustifyToEnd
(#24). - Add ConstrainedAspectRatio element (#23).
- Add EqualStack element (#26).
- Add Rule element (#22).
- Add Aligned element (#21).
- Add a screen scale property to some elements (#18).
- Swift 5 support (#15).
- Reorder the parameters of ConstrainedSize, Inset, Button, and Tappapble, so that the wrapped element is the last parameter (#19).
0.2.2 - 2019-03-29
- First stable release.