Skip to content

Instantly share code, notes, and snippets.

View PimCoumans's full-sized avatar
thinking about making coffee

Pim PimCoumans

thinking about making coffee
View GitHub Profile
@PimCoumans
PimCoumans / PrimaryActionHandler.swift
Last active February 8, 2024 09:57
Set primary action handler on UIButton and UIBarButtonItem
import UIKit
public extension UIAction.Identifier {
static let primary = UIAction.Identifier(rawValue: "PrimaryAction")
}
fileprivate extension UIAction {
var handler: UIActionHandler? {
// Tiny bit sketchy: cast UIAction's "handler" value to a ObjC block
typealias ActionHandlerBlock = @convention(block) (UIAction) -> Void
@PimCoumans
PimCoumans / ClosureConfigurable.swift
Last active May 24, 2023 08:52
Easier initializer with special infix operator
import Foundation
protocol ClosureConfigurable { }
extension ClosureConfigurable {
typealias Configurator = (Self) throws -> Void
/// Configures the receiver with a closure that is executed with `Self` as a parameter
/// - Parameter configurator: Closure executed immediately with `Self` as a parameter
/// - Returns: Instance after closure is applied
@discardableResult public func setup(with configurator: Configurator) rethrows -> Self {
@PimCoumans
PimCoumans / TappableLabel.swift
Last active November 16, 2022 11:30
UILabel subclass that handles touches on parts of its contents marked with custom attributed string key
import UIKit
/// Handles taps on tappable parts in the attributed string marked with the `.tappable` attributed string key
extension NSAttributedString.Key {
public static let tappable = NSAttributedString.Key("TappableContent")
}
/// UILabel that allows tapping on parts of its contents marked with the `.tappable` key, with touch highlighting
/// while the touch is on the tappable range.
/// The ``tapHandler`` closure is called when the text is successfully tapped. The value set on the attributed
@PimCoumans
PimCoumans / TouchCancellingScrollView.swift
Created August 2, 2022 16:20
ScrollView subclass that forces touch cancellation in UIControl views
import UIKit
/// Custom scrollView that can forces touch cancellation, even in `UIControl`s
/// - Note: Make sure to set `canCancelContentTouches` to `true`
class TouchCancellingScrollView: UIScrollView {
/// Set to `false` to allow drags in`UIControls`
var canCancelControlContentTouches: Bool = true
/// Cancels all touches, even when touch is in a `UIControl`.
@PimCoumans
PimCoumans / TimingFunction.swift
Created July 12, 2022 09:09
Calculated timing function for manual interpolation
import QuartzCore
struct TimingFunction {
private let function: (Double) -> Double
init(_ function: @escaping (Double) -> Double) {
self.function = function
}
}
@PimCoumans
PimCoumans / ModelView.swift
Last active May 24, 2023 08:51
Idea for basic ViewModel - View - ViewController structure with property wrappers
import UIKit
/// Any model struct used as a ViewModel. Must at least conform to `Equatable` to do some diffing
public protocol ViewModellable: Equatable { }
/// Protocol declaring `ModelView` behavior
public protocol ModelViewable<Model>: UIView {
associatedtype Model: ViewModellable
var model: Model { get }
@PimCoumans
PimCoumans / Swift+SkinToneModifier.swift
Last active July 6, 2022 19:36
Swift String adding random skin tone modifier
import Foundation
public extension String {
private static let skinToneModifiers = ["🏻", "🏼", "🏽", "🏾", "🏿"]
private static var lastUsedModifier: String?
static var randomSkinToneModifier: String {
var randomModifier: String
repeat {
randomModifier = skinToneModifiers.randomElement()!
@PimCoumans
PimCoumans / TapAreaButton.swift
Last active May 13, 2022 09:51
Extended tap area for UIButton
// Methods to extend tap area to a minimal size
extension UIView {
// Golden standard of minimal tap sizes [citation needed]
static let minimalTapSize: CGSize = CGSize(width: 44, height: 44)
/// Extends the rect to be at least as big as ``minimalTapSize``
class func extendedTapArea(from rect: CGRect) -> CGRect {
rect.insetBy(
dx: min(0, (rect.width - minimalTapSize.width) / 2),
@PimCoumans
PimCoumans / AnimationSequece.swift
Last active January 17, 2024 09:32
Simple way to chain and group multiple UIView animations
import UIKit
protocol StepAnimatable {
/// Start a sequence where you add each step in the `addSteps` closure. Use the provided `AnimationSequence` object
/// to add each step which should either be an actual animation or a delay.
/// The `completion` closure is executed when the last animation has finished.
/// - Parameters:
/// - addSteps: Closure used to add steps to the provided `AnimationSequence` object
/// - completion: Executed when the last animation has finished.
@PimCoumans
PimCoumans / Make.swift
Last active November 4, 2021 13:34
Generic replacement for assigning values with self-executing closures
/// Executes a closure and returns resulting generic value
/// Idea to replace 'executing closure pattern' used to assign values with some logic.
/// Example:
/// ```
/// let image: UIImage? = make {
/// if #available(iOS 13.0, *) {
/// return UIImage(systemName: "plus.square.fill.on.square.fill")
/// }
/// return UIImage(named: "fallbackImage")
/// }