SwiftUI Backports - Introducing a collection of SwiftUI backports to make your iOS development easier

Overview

watchOS macOS tvOS ios swift

SwiftUI Backports

Introducing a collection of SwiftUI backports to make your iOS development easier.

Many backports support iOS 13+ but where UIKIt features were introduced in later versions, the same will be applicable to these backports, to keep parity with UIKit.

In some cases, I've also included additional APIs that bring more features to your SwiftUI development.

Note, all backports will be API-matching to Apple's offical APIs, any additional features will be provided separately.

All backports are fully documented, in most cases using Apple's own documentation for consistency. Please refer to the header docs or Apple's original documentation for more details.

There is also a Demo project available where you can see full demonstrations of all backports and additional features, including reference code to help you get started.

Lastly, I hope this repo also serves as a great resource for how you can backport effectively with minimal hacks 👍

Sponsor

Building useful libraries like these, takes time away from my family. I build these tools in my spare time because I feel its important to give back to the community. Please consider Sponsoring me as it helps keep me working on useful libraries like these 😬

You can also give me a follow and a 'thanks' anytime.

Twitter

Usage

The library adopts a backport design by Dave DeLong that makes use of a single type to improve discoverability and maintainability when the time comes to remove your backport implementations, in favour of official APIs.

Backports of pure types, can easily be discovered under the Backport namespace. Similarly, modifiers are discoverable under the .backport namespace.

Unfortuantely Environment backports cannot be access this way, in those cases the Apple API values will be prefixed with backport to simplify discovery.

Types:

@Backport.AppStorage("filter-enabled")
private var filterEnabled: Bool = false

Modifier:

Button("Show Prompt") {
    showPrompt = true
}
.sheet(isPresented: $showPrompt) {
    Prompt()
        .backport.presentationDetents([.medium, .large])
}

Environment:

@Environment(\.backportRefresh) private var refreshAction

Backports

SwiftUI

  • AsyncImage
  • AppStorage
  • background – ViewBuilder API – Label
  • NavigationDestination – uses a standard NavigationView
  • navigationTitle – newer API
  • overlay – ViewBuilder API
  • onChange
  • ProgressView
  • presentationDetents
  • presentationDragIndicator
  • Refreshable
  • ScaledMetric
  • StateObject
  • Section(_ header:)
  • task – async/await modifier

UIKit

  • UIHostingConfiguration – simplifies embedding SwiftUI in UICollectionViewCell's

Extras

Modal Presentations

Adding this to your presented view, you can use the provided closure to present an ActionSheet to a user when they attempt to dismiss interactively. You can also use this to disable interactive dismissals entirely.

presentation(isModal: true) { /* attempt */ }

FittingGeometryReader

A custom GeometryReader implementation that correctly auto-sizes itself to its content. This is useful in many cases where you need a GeometryReader but don't want it to implicitly take up its parent View's bounds.

FittingScrollView

A custom ScrollView that respects Spacer's when the content is not scrollable. This is useful when you need to place a view at the edges of your scrollview while its content is small enough to not require scrolling. Another great use case is vertically centered content that becomes top aligned once the content requires scrolling.

PageView

A pure SwiftUI implementation of a page-based view, using the native TabView and my custom FittingGeometryReader to size itself correctly. Since this uses a TabView under-the-hood, this allows you to use the same APIs and features from that view.

Installation

You can install manually (by copying the files in the Sources directory) or using Swift Package Manager (preferred)

To install using Swift Package Manager, add this to the dependencies section of your Package.swift file:

.package(url: "https://github.com/shaps80/SwiftUIBackports.git", .upToNextMinor(from: "1.0.0"))

Comments
  • Infinite loop in UIView parentController property on iOS 14.0-14.4

    Infinite loop in UIView parentController property on iOS 14.0-14.4

    General Information

    See attached project

    • Project version: 1.6.3

    • Platform/OS version: iOS 14.0-14.4

    • IDE version: Xcode 13

    • Devices:

    • Any related GitHub issues:

    Describe the bug

    Uninited tab body causes infinite loop in UIView parentController property

    Steps to reproduce

    1. Run attached project on iOS 14.0-14.4
    2. Tap "Show modal" on tab A
    3. Select TextField

    Expected behavior

    No infinite loop in OwningController.swift

    Stack trace, compiler error, code snippets

    Archive.zip

    Additional context

    If tab B were opened before Modal, all works fine.

    bug 
    opened by anivaros 17
  • Push Transition

    Push Transition

    Describe your changes

    This pr adds a new push transition from SwiftUI 4 lifecycle

    • Added func push(from edge: Edge) -> AnyTransition

    Question: Is there an example how to add it to Backport?

    opened by drucelweisse 6
  • Refreshable not enabling pull-to-refresh

    Refreshable not enabling pull-to-refresh

    Have you read the Contributing Guidelines?

    General Information

    • Project version: 1.0.9

    • Platform/OS version: iOS 14.0.1, iOS 15.5, iOS 16

    • IDE version: Xcode 13.4.1, Xcode 14 beta 2

    • Devices: iPhone Simulator

    • Any related GitHub issues: N/A

    Describe the bug

    Using .backport.refreshable does not add pull-to-refresh to a list.

    Steps to reproduce

    Add .backport.refreshable to a List.

    Expected behavior

    Should add pull-to-refresh to the list.

    Stack trace, compiler error, code snippets

    struct RootView: View {
        var body: some View {
            TabView {
                NavigationView {
                    List {
                        Text("1")
                        Text("2")
                        Text("3")
                    }
                    .navigationTitle("Native")
                    .refreshable {
                        print("Refresh!")
                    }
                }
                .tabItem {
                    Text("Native")
                }
    
                NavigationView {
                    List {
                        Text("1")
                        Text("2")
                        Text("3")
                    }
                    .navigationTitle("Backport")
                    .backport.refreshable {
                        print("Refresh!")
                    }
                }
                .tabItem {
                    Text("Backport")
                }
            }
        }
    }
    

    Screenshots

    Simulator Screen Shot - iPhone 12 mini - 2022-06-30 at 21 03 35 Simulator Screen Shot - iPhone 12 mini - 2022-06-30 at 21 03 28

    Additional context

    It could be argued that the backport is complete; it does set the environment value. But not adding the pull-to-refresh was a surprise to me. It does look to be possible (https://github.com/Geri-Borbas/iOS.Package.Refreshable) so maybe something similar could be added?

    enhancement 
    opened by JosephDuffy 5
  • Add StateObject backport

    Add StateObject backport

    Describe your changes

    This adds a @StateObject backport.

    Screenshots

    The implementation was manually checked with some test code.

    • init for the ObservableObject is called only once, unless the view identity changes
    • Updates in the parent view don't reset the StateObject backport state
    • Updates to @Published properties propagate to the view
    • Binding created from this backport behaves as expected

    https://user-images.githubusercontent.com/38748295/176349845-8b1fa23d-50bd-4c8f-bc71-2a375ff55fdd.mp4

    (Gist: https://gist.github.com/auramagi/4a810e2c64b1be04a40e0c2d775a3529)

    opened by auramagi 5
  • Not Dismissing

    Not Dismissing

    Have you read the Contributing Guidelines?

    General Information

    • Project version:

    1.2.0

    • Platform/OS version:

    iOS 16.1

    • IDE version:

    Xcode 14.1

    • Devices:

    Real iPhone 13, Simulator iPhone 14 Pro Max

    • Any related GitHub issues:

    Describe the bug

    Clearly and concisely describe the bug. I am using ActivityView in one of my Apps. I have noticed that if you bring up the activity view and choose to email or text or anything else. If you cancel the email or text the activity view doesn’t dismiss it stays on top of the screen. I can’t seem to figure out why this is not dismissing. Any help or advice would be appreciated….

    Steps to reproduce

    Provide numbered steps to follow that reproduce the bug.

    1. Bring up an activity view
    2. Choose to email
    3. Then hit cancel when MailView comes up
    4. You'll notice the MailVIew goes away but the share sheet stays on the screen

    Expected behavior

    Clearly and concisely describe what you expected to happen. I would expect that if you canceled whatever activity you've chosen the share sheet should dismiss and go away

    Stack trace, compiler error, code snippets

    Paste the full output of any stack trace or compiler error. Include a code snippet that reproduces the described behavior, if applicable

    Screenshots

    If applicable, add screenshots, gifs, or videos to help explain your problem.

    Additional context

    Add any other useful information about the problem here.

    bug 
    opened by tazmancoder 4
  • Reset `tintAdjustmentMode` for `presentationUndimmed`

    Reset `tintAdjustmentMode` for `presentationUndimmed`

    Have you read the Contributing Guidelines?

    Yes! 🎉

    ~~Issue #~~

    Describe your changes

    As discussed here: https://danielsaidi.com/blog/2022/06/21/undimmed-presentation-detents-in-swiftui tintAdjustmentMode should be set to .normal in order to "undimm" the underlying view otherwise it stays dimmed even when the sheet is dismissed (at least in a NavigationView context).

    opened by schiewe 4
  • Fix: cannot drag to medium presentation dentent

    Fix: cannot drag to medium presentation dentent

    Presentation detent interactive drag didn't work well when created without selection parameter. It often jumps back to large detent.

    Fixed this by making selection an optional parameter.

    opened by larryonoff 4
  • Fix configuredView doesn’t removed from cell when reuse

    Fix configuredView doesn’t removed from cell when reuse

    Issue #

    Describe your changes

    The configuredView never removed from cell so it created and add to cell many many times when scroll,

    the reasons:

    • the key #function is different between get and set
    (lldb) po #function
    "$__lldb_wrapped_expr_10(_:)"
    
    (lldb) po #function
    "$__lldb_wrapped_expr_12(_:)"
    
    • Backport as a value type can not store value by objc_setAssociatedObject
    opened by strangeliu 4
  • Does .backports.onChange {} really work on macOS 10.15 Catalina?

    Does .backports.onChange {} really work on macOS 10.15 Catalina?

    Have you read the Contributing Guidelines?

    General Information

    I tried this on my macOS 10.15 virtual machine but find that it doesn't execute the {}-bracketed contents at all.

    • Project version: v1.8.2

    • Platform/OS version: macOS 10.15 Catalina.

    • IDE version: Xcode 14.

    • Devices: VMWare Fusion 13 running on mac mini (macOS 13).

    • Any related GitHub issues:

    Describe the bug

    (See general information.)


    I have no way to create a standalone project demonstrating this issue due to the failure of compiling this package in a new project (targeting macOS 10.15). Once this compilation issue gets solved, I can provide a bare-bone project demonstrating this issue. image


    Steps to reproduce

    Provide numbered steps to follow that reproduce the bug.

    Expected behavior

    Clearly and concisely describe what you expected to happen.

    Stack trace, compiler error, code snippets

    Paste the full output of any stack trace or compiler error. Include a code snippet that reproduces the described behavior, if applicable

    Screenshots

    If applicable, add screenshots, gifs, or videos to help explain your problem.

    Additional context

    Add any other useful information about the problem here.

    bug 
    opened by ShikiSuen 3
  • Mac Catalyst app build fails on Xcode 14 RC

    Mac Catalyst app build fails on Xcode 14 RC

    General Information

    Catalyst app build fails on Xcode 14 RC with redefinition of module 'QuickLook' error

    • Project version: 1.4.0-1.6.3

    • Platform/OS version: macOS Catalyst

    • IDE version: Xcode 14 RC

    bug 
    opened by anivaros 3
  • Adds support for ToolbarPlacement

    Adds support for ToolbarPlacement

    Have you read the Contributing Guidelines?

    Issue #

    Describe your changes

    Clearly and concisely describe what's in this pull request. Include screenshots, if necessary.

    opened by mmllr 3
  • ShareLink with an iPad

    ShareLink with an iPad

    Hi,

    Thanks for the library. I've been using your ActivityView library! I'm posting this issue here since the ShareLink code will have the same issue I encountered with ActivityView.

    I had a question / issue when presenting an acitivtysheet in iPadOS. The activitySheet is called from my main view, and not from a button like this:

    NavigationView { Color.white } .activitySheet($activityItem)

    In order to get this to work, I had to modify the ActivitySheet code to add the following:

    controller.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY,width: 0,height: 0)

    This is based on this thread:

    https://stackoverflow.com/questions/32889680/uiactivityviewcontroller-on-ipad

    Is this something you can add to this library, or is there something that I need to configure to get this to work on an iPad?

    Thanks,

    bug 
    opened by jtressle 1
  • Should enhancement APIs be moved to SwiftUI+?

    Should enhancement APIs be moved to SwiftUI+?

    @schiewe made a great point on one of my APIs that including non-backport API alongside the real backport could make it difficult to continue using the enhancement once the back port is dropped and no longer required.

    Putting it in one modifier allowed me to properly implement the back port and the additional feature in most cases.

    Tbh this hasn't come up often yet but I have a couple 'additions' that are not really backports, I wonder if it's just a bad idea to include these in this library at all.

    Perhaps I should move these to my SwiftUI+ package instead since these are enhancements. Removes this specific concern too.

    Thoughts?

    opened by shaps80 0
  • Work in progress

    Work in progress

    In order to keep everyone up-to-date with what I'm working on and to avoid duplication, here's a list of the currently planned additions/backports. Some just require documentation and cleanup (since they were developed some time ago), others are not yet in development. If you need a feature and want to know if you should start on it yourself, please check with me first to ensure we reach a similar solution.

    In progress

    Up next

    Version 1.9.0

    • [x] ImageRenderer
    • [x] ShareLink

    Version 1.5.0

    • [x] Table Hosting

    Version 1.5.0

    • [x] LabelledContent
    • [x] quickLookPreview

    Version 1.4.0

    • [x] ScrollDismissesKeyboard
    • [x] ScrollIndicators
    • [x] ScrollEnabled

    Version 1.3.1

    • [x] List Pull-to-Refresh

    Version 1.2.0

    • [x] Dismiss (environment)
    • [x] DynamicTypeSize
    • [x] AppStore Review
    • [x] OpenURL modifier

    Note, not all of the above will actually end up being back ported, as occasionally an implementation proves difficult or impossible to reproduce reliably. Also the list above is in no particular order.

    enhancement 
    opened by shaps80 13
Releases(1.9.0)
Owner
Shaps
Engineer @thirdfort and @EverythingSet ● Open source @SwiftUI-Plus ● I love to build tools for the world
Shaps
iOS Trakt Client - Keep track of your favorite TV shows and movies on your iPhone. (Under development)

CouchTracker Keep track of your favorite movies and tv shows on your iPhone Setup for development You will need Xcode 11.2.1 Swift 5.1.2 Run the follo

Pietro Caselani 42 Apr 19, 2022
An iOS app to make your love for Pokemon real.

An iOS app to make your love for Pokemon real.Which offers to make your pokemon cards live as if they were pokeballs. Each card has its own pokemon stored in it as a picturised but what if you had the powers of god to make it real and enjoyable. Don't worry now you do.Use our Poke3D and you're the god of pokemons.

Dishant Nagpal 1 Feb 27, 2022
A demo app to showcase testable, modern iOS development with SwiftUI and Combine on MVVM-C architecture.

Coinz_App_iOS A demo app to showcase testable, modern iOS development with SwiftUI and Combine on MVVM-C architecture. Tech Stack: Swift, SwiftUI, Com

Burhan Aras 0 Dec 26, 2021
iOS mobile development using Swift - Online Shopping Application

iOS mobile development using Swift - Online Shopping Application - yr4_sem1 This is an application developed as an individual project for Mobile Appli

Madhawa Jayagoda 2 Nov 10, 2021
Swift UI features and general iOS development coding lab

SwiftUI & iOS development concepts code lab Contains sample projects with documentation Overview SwiftUI provides views, controls and layout structure

Samuel Owino 4 Dec 14, 2022
Tongji Univ. SSE IOS Application Development coursework (final project)

HandTalk Tongji Univ. SSE IOS Application Development coursework (final project) : An Demo based on American Sign Language Classfier Development infor

Kaixin Chen 2 Sep 4, 2022
Recipe app for IOS Development class

NutriRecipes Recipe app for IOS Development class. User Stories A user can Land

null 0 Dec 20, 2021
Development of the TUM Campus App for iOS devices - for and from students at Technical University of Munich.

Development of the TUM Campus App for iOS devices - for and from students at Technical University of Munich.

TUM Developers 93 Dec 16, 2022
Nextflix - Integrating project of the IOS development course by Digital House

nextflix Projeto integrador do curso de desenvolvimento IOS pela Digital House A

Thiago Leite 2 Feb 1, 2022
The demo project to show how to organize code to make SwiftUI apps easy to be test.

TestableApp I combined the idea to use functional programming instead of an loader instance in ModelView(I prefer to think of it as a service) and Res

VictorK 2 Jan 7, 2022
A set of SwiftUI custom modifiers to make the ScrollView snappable.

Snappable A set of SwiftUI custom modifiers to make the ScrollView snappable. The goal of this library is to provide an easy way to implement Views su

hugehoge 22 Nov 30, 2022
Native iOS app built in SwiftUI, displays a collection of user's books.

Native iOS app built in SwiftUI, displays a collection of user's books.

Matthew Eilar 1 May 23, 2022
ToDoList - An ios app that help users to set their todos and make it easy to remember this todos

An ios app that help users to set their todos and make it easy to remember this todos by reminders them when todo time's up, this app make sure that you don't forget any todos that you want to do just give it to the app and let the app hundle it for you.

Ahmed Mahrous 1 Apr 25, 2022
App which lets two people share their social media details by simply putting one phone on top of the other ("tapping"). Currently in development by Nikita Mounier.

Tap It Tap It enables two people to seamlessly share their social media information (e.g. Instagram, Snapchat, phone number) by simply placing one scr

Nikita Mounier 24 Oct 21, 2022
Safety Score App Development

Safety Score App Development Saftey Score is an app intended to make nights out safer. Locations will be given a score out of 5 based on user reported

Josh Vasey 0 Oct 26, 2021
Implemented MVVM-C (Coordinator) architecture pattern for the project. Which is satisfying SOLID principles altogether. Protocol oriented development has been followed.

BreakingBad BreakingBad API doc Implemented MVVM-C (Coordinator) architecture pattern for the project. Which is satisfying SOLID principples altogethe

Dhruvik Rao 2 Mar 10, 2022
Visualize your dividend growth. DivRise tracks dividend prices of your stocks, gives you in-depth information about dividend paying stocks like the next dividend date and allows you to log your monthly dividend income.

DivRise DivRise is an iOS app written in Pure SwiftUI that tracks dividend prices of your stocks, gives you in-depth information about dividend paying

Kevin Li 78 Oct 17, 2022
A collection of missing SwiftUI components

SwiftUIKit A collection of components that will simplify and accelerate your iOS development. Components CurrencyTextField AdaptToKeyboard (not needed

youjinp 239 Nov 18, 2022
A collection of Swift functions, extensions, and SwiftUI and UIKit Views.

J's Helper A collection of Swift functions, extensions, and SwiftUI and UIKit Views. Legend: ?? UIKit ?? SwiftUI ?? Shared Installation In XCode 12 go

Jem Alvarez 3 Oct 1, 2022