Clean-room reimplementation of FotMob's excellent bracket UI SwiftUI and UIKit.
Under the hood the renderer is pure UIKit and manually laid out, to keep scrolling and paging as cheap and performant as possible.
| FotMob | BracketView |
|---|---|
fotmob-demo.mp4 |
bracketview-demo.mp4 |
import SwiftUI
import UIKit
import BracketView
// Define some rounds
private let sampleRounds: [BracketRound] = [
BracketRound(
id: "quarterfinals",
title: "Quarterfinals",
dateText: "6-7 May",
matches: [
BracketMatch(
id: "qf1",
style: .aggregate,
title: "Aggregate",
teams: [
BracketTeam(
id: "arsenal",
name: "Arsenal",
badgeText: "ARS",
badgeColor: BracketColor(red: 0.79, green: 0.04, blue: 0.16),
logoURL: URL(string: "https://images.fotmob.com/image_resources/logo/teamlogo/9825.png"),
score: "3",
isEliminated: false,
isPlaceholder: false
),
BracketTeam(
id: "madrid",
name: "Real Madrid",
badgeText: "RMA",
badgeColor: BracketColor(red: 0.92, green: 0.92, blue: 0.92),
logoURL: URL(string: "https://images.fotmob.com/image_resources/logo/teamlogo/8633.png"),
score: "2",
isEliminated: true,
isPlaceholder: false
)
]
),
...
]
),
...
]
struct BracketExampleView: View {
@State private var selectedRoundID = sampleRounds.defaultSelectedRoundID
var body: some View {
BracketView(
data: sampleRounds,
selectedRoundID: $selectedRoundID,
/// Optional configuration object
configuration: BracketViewConfiguration(
/// Customizing bracket appearance
appearance: BracketAppearance(
cardBackgroundColor: UIColor.secondarySystemBackground,
cardCornerRadius: 20,
connectorStrokeWidth: 1,
connectorCornerRadius: 8
),
/// Controls how many off-screen rounds stay mounted on each side of the current viewport
visibleRoundBuffer: 1
)
)
}
}If logoURL is present, the package tries to load it automatically. If it fails, the badge falls back to your badgeText and badgeColor.
The repo also includes Demo/BracketViewDemo, an Xcode project you can run with a few known sample rounds and brackets already wired up.
import UIKit
import BracketView
let controller = BracketViewController(
data: sampleRounds,
selectedRoundID: sampleRounds.defaultSelectedRoundID,
configuration: BracketViewConfiguration(...)
)This project is an independent, unofficial reimplementation inspired by the bracket UI style seen in FotMob. It is not affiliated with, endorsed by, or sponsored by FotMob or FotMob AS. “FotMob” is a trademark of its respective owner. This project does not include FotMob source code, assets, or proprietary data.