📦 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!
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().onAppear {
hideKeyboard()
}// 😴 Before
MyView().overlay(RoundedRectangle(cornerRadius: 5.0).stroke(.red, lineWidth: 2.0))
// ✨ After
MyView().roundedBorder(.red, cornerRadius: 5.0, lineWidth: 2.0)- App Layout
- View Functionality
- Other Features
Most of the above features are cross-platform and are supported on both iOS and macOS.
Add ShinySwiftUI to your project using Swift Package Manager:
https://github.com/Flowductive/shiny-swift-ui
Improve code consistency with CGFloat spacing values:
MyView().padding(.m).cornerRadius(.xs)These values include: .xxs, .xs, .s, .m, .l. .xl, and .xxl.
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.
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()
}Use fixed-width spacers for consistent spacing:
// Large vertical spacer
Spacer.VL
// Extra-small vertical spacer
Spacer.HXSVertical spacer variants include .VXXS, .VXS, .VS, .VM, .VL, .VXL, and .VXXL.
Horizontal spacer variants include .HXXS, .HXS, .HS, .HM, .HL, .HXL, and .HXXL.
You can quickly group views using operators:
// Horizontal stack
MyViewA() + MyViewB()
// Vertical stack, center-aligned
MyViewA() / MyViewB()
// Vertical stack, left-aligned
MyViewA() /- MyViewB();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()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.
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)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
}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)Use the .debug() view modifier to randomly change the background color of the view for debugging:
MyView().debug()Take a screenshot of a view and save the image to path:
myView.snapshot()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)Track the relative position of the mouse pointer within the view:
MyView().trackingMouse { pos in
// ...
}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.
Easily add SwiftUI wraps of UIVisualEffectView:
VisualEffectView().png)