shiny-swift-ui
shiny-swift-ui copied to clipboard
✨ Write cleaner, conciser, and more consistent SwiftUI code with a suite of pre-made extensions, view modifiers, and components.
.png)
SwiftUI extensions and components that just make sense.
📦 Lightweight, Swift-y looking code for modern SwiftUI developers
⚙️ Dozens of view modifiers to add expected functionality
💨 Custom, built-in transitions & animations for views
💻 Cross-platform Support for iOS, macOS, watchOS
🧩 Pre-made components that look great in any app
💕 This package works great with and is inspired by SwiftUIX!
🚧 Wiki under construction. Read below to get started!
What is ShinySwiftUI?
ShinySwiftUI aims to turn messy Swift + SwiftUI code into cleaner, Swift-ier code. It also aims to provide a library of useful modifiers, components, and extensions to create consistent, good-looking apps.
// 😴 Before
HStack {
ViewA()
ViewB()
}
// ✨ After
ViewA() + ViewB()
// 😴 Before
MyView().frame(width: 30.0, height: 30.0)
MyView().frame(maxWidth: 40.0, maxHeight: 40.0)
// ✨ After
MyView().frame(30.0)
MyView().frame(max: 40.0)
// 😴 Before
MyView().onAppear {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
// ✨ After
MyView().hideKeyboard()
// 😴 Before
MyView().overlay(RoundedRectangle(cornerRadius: 5.0).stroke(.red, lineWidth: 2.0))
// ✨ After
MyView().roundedBorder(.red, cornerRadius: 5.0, lineWidth: 2.0)
Completed Features
- App Layout
- View Functionality
- Other Features
Most of the above features are cross-platform and are supported on both iOS and macOS.
Get Started
Add ShinySwiftUI to your project using Swift Package Manager:
https://github.com/Flowductive/shiny-swift-ui
📐 App Layout Features
Pre-defined spacing values
Improve code consistency with CGFloat spacing values:
MyView().padding(.m).cornerRadius(.xs)
These values include: .xxs, .xs, .s, .m, .l. .xl, and .xxl.
Layout using Generic Stack
You can use a generic stack, or GStack, to position items vertically or horizontally using a Bool input:
GStack(platform == .iOS ? .vertical : .horizontal) {
MyViewA()
MyViewB()
}
A typical use case of GStack is for changing display layout on macOS vs. iOS devices.
Layout using Shove View
Use a ShoveView to quickly push inner content to one side/corner:
// Position MyView right
ShoveView(.trailing) {
MyView()
}
// Position MyView top-left
ShoveView(.topLeading) {
MyView()
}
Fixed-width spacers
Use fixed-width spacers for consistent spacing:
// Large vertical spacer
Spacer.VL
// Extra-small vertical spacer
Spacer.HXS
Vertical spacer variants include .VXXS, .VXS, .VS, .VM, .VL, .VXL, and .VXXL.
Horizontal spacer variants include .HXXS, .HXS, .HS, .HM, .HL, .HXL, and .HXXL.
⚙️ View Functionality
Operations on views
You can quickly group views using operators:
// Horizontal stack
MyViewA() + MyViewB()
// Vertical stack, center-aligned
MyViewA() / MyViewB()
// Vertical stack, left-aligned
MyViewA() /- MyViewB();
View frame modifiers
Easily set the dimensions of a square frame:
// Sets MyView's frame to width = 30.0, height = 30.0
MyView().frame(30.0)
Stretch the view:
// Stretch horizontally
MyViewA().stretchH()
// Stretch vertically
MyViewB().stretchV()
// Stretch in both directions
MyViewC().stretch()
View refresh modifier
Use a @State boolean to refresh a view quickly:
@State var refresh: Bool = false
var body {
MyView().refreshable(with: refresh)
}
Updating the view would require that refresh.toggle() is called.
View styling modifiers
Set the relative opacity of a view:
MyView().opacity(.half)
You can choose from (in order of opacity) .opaque, .most, .half, .quarter, .almostInvisible, .invisible.
Add a rounded border to any view:
MyViewA().roundedBorder(.green)
MyViewB().roundedBorder(.red, cornerRadius: .s, lineWidth: 2.0)
View timing modifiers
Repeat an action in a specified interval:
MyView().every(3.0) {
print("Hello") // Runs every 3 seconds
}
Perform an action after a specified delay:
MyView().after(3.0) {
print("Hello") // Runs 3 seconds after the view appears
}
Custom animation/transitions
Add a slick transition to a view using .slickAnimation(value:):
MyViewA().slickAnimation()
MyViewB().slickAnimation(value: myVal)
Add a custom built-in animation; i.e. .slickEaseOut, .slickEaseIn, .rampEaseOut, .rampEaseIn, .bounce, .lightBounce, or .page:
MyViewA().animation(.rampEaseOut)
MyViewB().animation(.slickEaseOut(duration: 1.0), value: myVal)
Add a custom built-in transition; i.e. .turn, .swipe, .pop:
MyViewA().transition(.turn)
Debugging view modifier
Use the .debug() view modifier to randomly change the background color of the view for debugging:
MyView().debug()
Screenshot view method
Take a screenshot of a view and save the image to path:
myView.snapshot()
Hover tooltip modifier (macOS)
Add a tooltip upon hover to a view:
MyView()
.withTooltip(present: $showTooltip) {
Text("This is a tooltip!")
}
Add a keyboard shortcut, which automatically adds the shortcut tooltip:
MyViewA().shortcut("c", modifiers: [.shift, .command])
MyViewB().shortcut(.defaultAction)
View mouse position checking (macOS)
Track the relative position of the mouse pointer within the view:
MyView().trackingMouse { pos in
// ...
}
🎁 Other Features
Color features
Take advantage of color utilities:
// Init color from hex code
var color = Color(hex: "#ffffff")
// If bindingBool.wrappedValue is true, show the color
MyView().foregroundColor(.red.if($bindingBool))
// Get a lighter version of a color
lighter = color.ligher(by: 0.3)
// Colors also have relative opacities, just like views
halfColor = color.opacity(.half)
When importing ShinySwiftUI, colors will also conform to Codable.
Visual effects
Easily add SwiftUI wraps of UIVisualEffectView:
VisualEffectView()