Game Leaderboard

Game Leaderboard

by dockui

A modern and sleek leaderboard interface designed to showcase player rankings and scores.Perfect for a variety of applications.

Platform
SwiftUI
Code
Native Swift
Format
Screen
Access
Free

Code Snippet

import SwiftUI

struct PlayerScore: Identifiable {
    let id = UUID()
    let rank: Int
    let playerName: String
    let score: Int
    let isCurrentPlayer: Bool
    let playerAvatar: String // SF Symbol name
    let achievementBadges: [String] // SF Symbol names
}

struct LeaderboardCategory: Identifiable {
    let id = UUID()
    let name: String
    let icon: String
    let timeFrame: TimeFrame
}

enum TimeFrame: String, CaseIterable {
    case allTime = "All"
    case today = "Today"
    case week = "This Week"
    case month = "This Month"
}

struct GameLeaderboardView: View {
    @State private var selectedTimeFrame: TimeFrame = .week
    @State private var selectedCategory: LeaderboardCategory?
    @State private var showingPlayerDetail: PlayerScore?

    
    let playerScores = [
        PlayerScore(rank: 1, playerName: "MaxPower", score: 98750, isCurrentPlayer: false, playerAvatar: "person.crop.circle.fill", achievementBadges: ["star.circle.fill", "trophy.fill"]),
        PlayerScore(rank: 2, playerName: "GameMaster", score: 95200, isCurrentPlayer: false, playerAvatar: "person.crop.circle.fill.badge.checkmark", achievementBadges: ["star.circle.fill"]),
        PlayerScore(rank: 3, playerName: "PlayerOne", score: 92100, isCurrentPlayer: true, playerAvatar: "person.crop.circle.fill", achievementBadges: ["star.circle.fill", "trophy.fill", "medal.fill"]),
        PlayerScore(rank: 4, playerName: "ProGamer", score: 89400, isCurrentPlayer: false, playerAvatar: "person.crop.circle.fill", achievementBadges: ["star.circle.fill"]),
        PlayerScore(rank: 5, playerName: "GameWizard", score: 87600, isCurrentPlayer: false, playerAvatar: "person.crop.circle.fill", achievementBadges: [])
    ]
    
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 24) {
                    timeFrameSelector
                    topPlayersSection
                    leaderboardList
                }
                .padding(8)
            }
            .navigationTitle("Leaderboard")
            .sheet(item: $showingPlayerDetail) { player in
                PlayerDetailSheet(player: player)
            }
        }
    }
    
    private var timeFrameSelector: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 12) {
                ForEach(TimeFrame.allCases, id: \.self) { timeFrame in
                    TimeFramePill(
                        timeFrame: timeFrame,
                        isSelected: selectedTimeFrame == timeFrame,
                        action: { selectedTimeFrame = timeFrame }
                    )
                }
            }
            .padding(.horizontal, 4)
        }
    }
    
    private var topPlayersSection: some View {
        VStack(spacing: 20) {
            if playerScores.count >= 3 {
                HStack(alignment: .bottom, spacing: 20) {
                    // Second Place
                    TopPlayerPodium(
                        player: playerScores[1],
                        size: 80,
                        place: 2
                    )
                    
                    // First Place
                    TopPlayerPodium(
                        player: playerScores[0],
                        size: 100,
                        place: 1
                    )
                    
                    // Third Place
                    TopPlayerPodium(
                        player: playerScores[2],
                        size: 70,
                        place: 3
                    )
                }
                .padding(.bottom)
            }
        }
    }
    
    private var leaderboardList: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Rankings")
                .font(.title3)
                .fontWeight(.semibold)
            
            ForEach(playerScores) { player in
                PlayerScoreRow(player: player)
                    .onTapGesture {
                        showingPlayerDetail = player
                    }
            }
        }
    }
}

struct CategoryCard: View {
    let category: LeaderboardCategory
    let isSelected: Bool
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            VStack(spacing: 12) {
                Image(systemName: category.icon)
                    .font(.title)
                    .foregroundStyle(isSelected ? .white : .blue)
                
                Text(category.name)
                    .font(.subheadline)
                    .fontWeight(.medium)
                    .foregroundStyle(isSelected ? .white : .primary)
            }
            .frame(maxWidth: .infinity)
            .padding()
            .background(isSelected ? Color.blue : Color(.systemGray6))
            .clipShape(RoundedRectangle(cornerRadius: 15))
        }
    }
}

struct TimeFramePill: View {
    let timeFrame: TimeFrame
    let isSelected: Bool
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            Text(timeFrame.rawValue)
                .font(.subheadline)
                .fontWeight(.medium)
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(
                    Capsule()
                        .fill(isSelected ? Color.blue : Color(.systemGray6))
                )
                .foregroundStyle(isSelected ? .white : .primary)
        }
    }
}

struct TopPlayerPodium: View {
    let player: PlayerScore
    let size: CGFloat
    let place: Int
    
    var body: some View {
        VStack(spacing: 8) {
            Image(systemName: player.playerAvatar)
                .font(.system(size: size * 0.5))
                .foregroundStyle(player.isCurrentPlayer ? .blue : .primary)
            
            Text(player.playerName)
                .font(.caption)
                .fontWeight(.medium)
                .lineLimit(1)
            
            Text("\(player.score)")
                .font(.caption2)
                .foregroundStyle(.secondary)
            
            ZStack {
                RoundedRectangle(cornerRadius: 8)
                    .fill(place == 1 ? Color.yellow : place == 2 ? Color.gray : Color.brown)
                    .frame(height: 24 + CGFloat(place == 1 ? 20 : place == 2 ? 10 : 0))
                
                Text("#\(place)")
                    .font(.caption2)
                    .fontWeight(.bold)
                    .foregroundStyle(.white)
            }
        }
        .frame(width: size)
    }
}

struct PlayerScoreRow: View {
    let player: PlayerScore
    
    var body: some View {
        HStack(spacing: 16) {
            Text("#\(player.rank)")
                .font(.headline)
                .foregroundStyle(.secondary)
                .frame(width: 40)
            
            Image(systemName: player.playerAvatar)
                .font(.title2)
                .foregroundStyle(player.isCurrentPlayer ? .blue : .primary)
            
            VStack(alignment: .leading, spacing: 4) {
                Text(player.playerName)
                    .fontWeight(.medium)
                
                HStack {
                    ForEach(player.achievementBadges, id: \.self) { badge in
                        Image(systemName: badge)
                            .font(.caption)
                            .foregroundStyle(.yellow)
                    }
                }
            }
            
            Spacer()
            
            Text("\(player.score)")
                .font(.headline)
                .foregroundStyle(player.isCurrentPlayer ? .blue : .primary)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 15)
                .fill(Color(.systemBackground))
                .shadow(color: .black.opacity(0.1), radius: 5)
        )
    }
}

struct PlayerDetailSheet: View {
    let player: PlayerScore
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 24) {
                    // Player Avatar
                    Image(systemName: player.playerAvatar)
                        .font(.system(size: 80))
                        .foregroundStyle(player.isCurrentPlayer ? .blue : .primary)
                        .padding()
                    
                    // Player Info
                    VStack(spacing: 8) {
                        Text(player.playerName)
                            .font(.title2)
                            .fontWeight(.bold)
                        
                        Text("Rank #\(player.rank)")
                            .font(.headline)
                            .foregroundStyle(.secondary)
                    }
                    
                    // Score
                    ScoreCard(score: player.score)
                    
                    // Achievements
                    if !player.achievementBadges.isEmpty {
                        AchievementsView(badges: player.achievementBadges)
                    }
                }
                .padding()
            }
            .navigationTitle("Player Details")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Done") { dismiss() }
                }
            }
        }
    }
}

struct ScoreCard: View {
    let score: Int
    
    var body: some View {
        VStack(spacing: 8) {
            Text("High Score")
                .font(.headline)
                .foregroundStyle(.secondary)
            
            Text("\(score)")
                .font(.system(size: 44, weight: .bold))
        }
        .frame(maxWidth: .infinity)
        .padding()
        .background(Color(.systemGray6))
        .clipShape(RoundedRectangle(cornerRadius: 15))
    }
}

struct AchievementsView: View {
    let badges: [String]
    
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Achievements")
                .font(.headline)
            
            LazyVGrid(columns: [
                GridItem(.adaptive(minimum: 80))
            ], spacing: 16) {
                ForEach(badges, id: \.self) { badge in
                    VStack {
                        Image(systemName: badge)
                            .font(.title)
                            .foregroundStyle(.yellow)
                            .frame(width: 60, height: 60)
                            .background(Color(.systemGray6))
                            .clipShape(Circle())
                    }
                }
            }
        }
    }
}

Similar Blogs

View All Articles
How to Translate Xcode String Catalogs with AI

How to Translate Xcode String Catalogs with AI

Learn how to efficiently translate Xcode string catalogs using AI fast, streamlining localization for your iOS and SwiftUI applications.

by dockui
May 4
How to optimize your SwiftUI app in 2026

How to optimize your SwiftUI app in 2026

Discover top strategies to optimize your SwiftUI app in 2026, enhancing performance, responsiveness, and maintainability with modern concurrency.

by dockui
Apr 29
SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI iOS confirmation alert with Confirm and Cancel buttons. Beginners guide to building safe actions, destructive deletes, and commit dialogs.

by dockui
Nov 11
SwiftUI: IOS Haptic Feedback Guide 2026

SwiftUI: IOS Haptic Feedback Guide 2026

Add click to vibrate haptic feedback in SwiftUI. Full guide to UIImpactFeedbackgenerator, success, error, selection, and tap vibration patterns with code.

by dockui
Nov 11

Code copied to clipboard!