HypeUI

October 14, 2025 Β· View on GitHub

πŸš€ HypeUI is a implementation of Apple's SwiftUI DSL style based on UIKit Want to enjoy SwiftUI syntax with UIKit? It's time to use HypeUI 😊

Awesome Swift

Why to use HypeUI?
πŸ“±Support iOS 12+
✨HypeUI is compatible with UIKit based project using SwiftUI style syntax
πŸ„β€β™‚οΈReduce UI & Autolayout codes more than 30%
⛳️Provide UI binding extension with RxSwift and RxCocoa
πŸ¦„Easy to use!
✈️Improve readability and intuitiveness of complex layouts
🀩Have a blast
β›·Customize reusable component, design system
❄️Test with accessibility Identifier

Contents

Requirements

  • iOS 12.0+
  • XCode 13.0+
  • Swift 5.0+

Installation

Swift Package Manager

Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Xcode 13+ is required to build HypeUI using Swift Package Manager.

To integrate HypeUI into your Xcode project using Swift Package Manager, add it to the dependencies value of your Package.swift:

dependencies: [
    .package(url: "https://github.com/hyperconnect/HypeUI", .upToNextMajor(from: "0.3.0"))
]

CocoaPod

The preferred installation method is with CocoaPods. Add the following to your Podfile:

pod 'HypeUI'

Supported Features

Supported Features
HStackβœ…
VStackβœ…
ZStackβœ…
Buttonβœ…
Textβœ…
Imageβœ…
ScrollViewβœ…
Behaviorβœ…
Spacerβœ…
LinearGradientβœ…
AlignmentViewβœ…
ViewBuildableβœ…
View Modifierβœ…
Text Modifierβœ…
Stack Modifierβœ…
ScrollView Modifierβœ…
Image Modifierβœ…
UIKit Extensionsβœ…

View Modifier

nameDescription
setHContentHuggingAdjusts the priority for a view to resist growing beyond its intrinsic size horizontally.
setVContentHuggingAdjusts the priority for a view to resist growing beyond its intrinsic size vertically.
setHContentCompressionResistanceAdjusts the priority for a view to resist shrinking below its intrinsic size horizontally.
setVContentCompressionResistanceAdjusts the priority for a view to resist shrinking below its intrinsic size vertically.
makeRatioSets the aspect ratio constraint for the view's size.
cornerRadiusApplies a corner radius to the view to create rounded corners.
borderAdds a border with specified color and width to the view.
backgroundSets the background color of the view.
makeContentModeSets the content mode of the view.
framePositions the view within a specified frame size.
paddingAdds padding around specific edges of the view.
allowsHitTestingEnables or disables the view's interaction with touch events.
masksToBoundsClips the view's sublayers to its boundaries.
accessibilityIdentifierAssigns an identifier used to find this view in tests.
overlayPlaces specified views in front of the view.
backgroundLayers the views that you specify behind this view.
centerCenters the view within a new parent view.
tintApplies a tint color to the view.
opacitySets the transparency level of the view.
scaleEffectScales the view by specified factors along the x and y axes.
rotationEffectRotates the view by a specified angle around a given anchor point.

Text Modifier

nameDescription
fontSets the font of the text.
foregroundColorApplies a foreground color to the text.
textAlignedSets the alignment of the text within its container.
lineLimitSpecifies the maximum number of lines the text can span.
lineBreakModeDefines how text wraps when it reaches the edge of its container.
adjustFontSizeAdjusts the font size of the text to fit its width.
minimumScaleFactorSets the smallest multiplier for text size reduction to fit the width.
preferredMaxLayoutWidthSets the preferred maximum width for the Text object and enables method chaining.
baselineAdjustedApplies a baseline adjustment to the Text object and enables method chaining.

Stack Modifier

nameDescription
distributedModify stack's distribution layout.

ScrollView Modifier

nameDescription
bouncesModify scroll view bounces.
isPagingEnabledModify scroll view paging enabled.
isScrollEnabledModify scroll view enabled.

UIKit Extensions

nameDescription
shadowApplies a shadow to the view with specified properties
dropShadowApplies a simple drop shadow with default styling
removeShadowRemoves any shadow from the view
debouncedActionAdds debounced action to control events with specified delay
keyboardTypeSets the keyboard type for text input fields
autocorrectionDisabledSets whether to disable autocorrection for text input
textContentTypeSets the text content type for autofill suggestions
textFieldStyleSets the text field's border style
submitLabelSets the submit label for the return key
textInputAutocapitalizationSets the text capitalization style
secureFieldSets whether the text field is a secure entry (password field)
textEditorEditableSets whether the text view is editable
textEditorScrollableSets whether the text view is scrollable
scrollContentBackgroundHides the scroll content background
selectionSets the selected segment index for segmented control (SwiftUI-style)
pickerEnabledSets whether the segmented control is enabled
selectedSegmentTintColorSets the background color for the selected segment
segmentedControlBackgroundColorSets the background color of the segmented control
momentarySets whether the control momentarily highlights segments when touched
onSelectionChangeAdds an action for value changed events

Usage

HStack

HStack(alinement: .center, spacing: 4) {
    Image(Asset.icStar.image)
        .frame(width: 12, height: 12)
    Text()
        .foregroundColor(UIColor.black)
        .font(UIFont.systemFont(ofSize: 14, weight: .regular))
    Spacer()
}

VStack

VStack(spacing: 8) {
    Text()
        .foregroundColor(UIColor.black)
        .font(UIFont.systemFont(ofSize: 14, weight: .regular))
    Spacer()
}

ZStack

ZStack {
    HStack(alinement: .center, spacing: 4) {
        Image(Asset.icStar.image)
            .frame(width: 12, height: 12)
        Text()
            .foregroundColor(UIColor.black)
            .font(UIFont.systemFont(ofSize: 14, weight: .regular))
        Spacer()
    }
    VStack {
        Text()
            .foregroundColor(UIColor.black)
            .font(UIFont.systemFont(ofSize: 14, weight: .regular))
        Spacer()
    }
}

Button

Button(action: { // DO SOMETHING ex) reactor action, closure }) {
    HStack(alignment: .center, spacing: 5.0) {
        Image("cart")
            .padding(.leading, 10.0)
        Text("Add to Cart")
            .foregroundColor(.black)
            .padding(.all, 10.0)
    }
}
.background(Color.gray)
.cornerRadius(5)

Text

Text("✨")
    .foregroundColor(UIColor.black)
    .font(UIFont.systemFont(ofSize: 14, weight: .regular))
    .textAligned(.center)
    .background(.white)
    .cornerRadius(16)

Image

Image(Resource.Profile.placeholderImage)
    .frame(width: 48, height: 48)
    .cornerRadius(24)

ScrollView

// MARK: Example
ScrollView(.vertical, showsIndicators: false) {
    VStack(alignment: .fill) {
        Image(image: Asset.imgPopupPrivateCall.image)
            .makeRatio(0.46106)
        Spacer()
            .frame(height: 24)
        VStack {
            viewModel.messages.map { message in
                HStack(alignment: .top, spacing: 8) {
                    Text("β€’")
                        .font(UIFont.systemFont(ofSize: 14, weight: .regular))
                        .foregroundColor(.Palette.gray04)
                        .frame(width: 6)
                    Text(message)
                        .font(UIFont.systemFont(ofSize: 14, weight: .regular))
                        .foregroundColor(.Palette.gray04)
                        .lineLimit(2)
                        .lineBreakMode(.byCharWrapping)
                    Spacer()
                        .frame(width: 5)
                }
                .padding(.vertical, 8)
            }
        }
        Spacer()
            .frame(height: 16)
    }
}

@Behavior - It's seems like SwiftUI's @State using DynamicLinkable 😎

@Behavior var isLive: Bool = false
@Behavior var username: String? = nil
@Behavior var profileImageURL: URL? = nil

// MARK Example
final class SearchHostHistoryViewCell: UICollectionViewCell {
    @Behavior var isLive: Bool = false
    @Behavior var username: String? = nil
    @Behavior var profileImageURL: URL? = nil

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubviewWithFit(
            ZStack {
                VStack(alignment: .center, spacing: 8) {
                    Image(Resource.Profile.placeholderImage)
                        .linked($profileImageURL.flatMapLatest { \$0?.getImage(failover: Resource.Profile.placeholderImage) ?? .just(Resource.Profile.placeholderImage) }, keyPath: \.image)
                        .makeContentMode(.scaleAspectFill)
                        .frame(width: 48, height: 48)
                        .cornerRadius(24)
                        .background(.Palette.gray05)
                    Text("")
                        .linked($username, keyPath: \.text)
                        .textAligned(.center)
                        .foregroundColor(.darkModeSupporting(.Palette.gray01, .Palette.dkGray01))
                        .font(UIFont.systemFont(ofSize: 10, weight: .regular))
                        .frame(height: 12)
                }.padding(UIEdgeInsets(top: 12, left: 0, bottom: 4, right: 0))
                VStack(alignment: .center) {
                    Spacer()
                    Text("LIVE")
                        .foregroundColor(.Palette.white)
                        .font(UIFont.systemFont(ofSize: 8, weight: .bold))
                        .padding(UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4))
                        .background(.Palette.red)
                        .cornerRadius(4)
                        .linked($isLive.not(), keyPath: \.isHidden)
                    Spacer()
                        .frame(height: 20)
                }
            }
        )
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Spacer

Spacer()
    .frame(width: 10)
Spacer()
    .frame(height: 20)

LinearGradient

ProfileView()
    .background(
        LinearGradient(
            gradient: Gradient(
                stops: [
                    Stop(color: UIColor.black, location: 1.0),
                    Stop(color: UIColor.black, location: 0.2),
                    Stop(color: UIColor.black, location: 0.0)
                ]),
            startPoint: .top,
            endPoint: .bottom
        )
    )

ViewBuildable - Customize UI, Make reusable component and Design System by confirming ViewBuildable protocol.

struct ProfileView: ViewBuildable {
    @Behavior var country: String
    @Behavior var name: String

    func build() -> UIView {
        VStack {
            HStack(alignment: .center, spacing: 12) {
                Text("")
                    .linked($country, keyPath: \.text)
                    .font(UIFont.systemFont(ofSize: 20, weight: .regular))
                    .accessibilityIdentifier("country")
                Text("")
                    .linked($name, keyPath: \.text)
                    .font(UIFont.systemFont(ofSize: 20, weight: .regular))
                    .accessibilityIdentifier("name")
            }
        }
    }
}

UIKit Extensions

Shadow

// Default shadow
Text("Drop Shadow")
    .background(.systemBlue)
    .cornerRadius(8)
    .shadow()

// Custom shadow
Text("Custom Shadow")
    .background(.systemPurple)
    .cornerRadius(8)
    .shadow(color: .systemPurple, radius: 8, offset: CGSize(width: 0, height: 4), opacity: 0.4)

// Remove shadow
view.removeShadow()

Debounced Actions

// Default 0.3s delay
button.debouncedAction {
    print("Action executed!")
}

// Custom delay and events
button.debouncedAction(delay: 1.0, for: .touchUpInside) {
    print("Custom debounced action!")
}

// TextField debouncing
textField.debouncedAction(delay: 0.5, for: .editingChanged) {
    performSearch()
}

Text Input Controls

// TextField with SwiftUI-style modifiers
UITextField()
    .keyboardType(.emailAddress)
    .textFieldStyle(.roundedRect)
    .autocorrectionDisabled()
    .textContentType(.emailAddress)
    .submitLabel(.done)
    .secureField(false)

// TextEditor with SwiftUI-style modifiers  
UITextView()
    .keyboardType(.default)
    .textInputAutocapitalization(.sentences)
    .textEditorScrollable(true)
    .textEditorEditable(true)
    .scrollContentBackground(true)

// Segmented Control with SwiftUI-style modifiers
UISegmentedControl(items: ["Option 1", "Option 2", "Option 3"])
    .selection(0)
    .selectedSegmentTintColor(.systemBlue)
    .pickerEnabled(true)
    .onSelectionChange { index in
        print("Selected: \(index)")
    }

Important: Layer Frame Updates

When using borders or gradients with HypeUI, ensure proper layer sizing by calling updateHypeUILayers() in your view's layoutSubviews:

class MyCustomView: UIView {
    override func layoutSubviews() {
        super.layoutSubviews()
        updateHypeUILayers() // Updates border and gradient layer frames
    }
}

// Or in ViewBuildable components:
struct MyViewBuildable: ViewBuildable {
    func build() -> UIView {
        let containerView = UIView()
        
        // Apply borders and gradients
        containerView
            .gradient(colors: [.red, .blue])
            .border(edges: .all, color: .black, width: 2)
        
        // Container will automatically update layers when bounds change
        return containerView
    }
}

Main Contributors

cruz@hpcnt.com xeon@hpcnt.com owen.j@hpcnt.com dough@hpcnt.com

Dependencies