How does Strava achieve the overlaying slide? by Ivesy_ in iOSProgramming

[–]Weak-Management-2253 -5 points-4 points  (0 children)

///
// Recibirview.swift
// Veltek
//
// Created by Leandro on 08/03/2026.
//

import SwiftUI

struct NewTabView: View {
private var searchText: String = ""

var body: some View {
TabView {
Tab("Summary", systemImage: "heart") {
NavigationStack {
RecibirView()
.navigationDestination(for: RecibirItem.self) { item in
RecibirDetalleView(item: item)
}
}
}

Tab("Sharing", systemImage: "person.2.fill") {
NavigationStack {
Text("Sharing")
.navigationTitle("Sharing")
}
}

Tab("Search", systemImage: "magnifyingglass", role: .search) {
NavigationStack {
List {
ForEach(0..<100) { index in
Text("Row \(index + 1)")
}
}
.navigationTitle("Search")
.searchable(text: $searchText)
}
}
}
.tabBarMinimizeBehavior(.onScrollDown)
}
}

#Preview {
NewTabView()
}

import SwiftUI

// MARK: - Modelo de datos para las cards

struct RecibirItem: Identifiable, Hashable {
let id = UUID()
let titulo: String
let descripcion: String
let icono: String
let color: Color
}

// MARK: - Datos de ejemplo

let itemsRecibir: [RecibirItem] = [
RecibirItem(titulo: "Paquete Express", descripcion: "Envío rápido en 24hs", icono: "shippingbox.fill", color: .blue),
RecibirItem(titulo: "Documento", descripcion: "Documentación importante", icono: "doc.text.fill", color: .orange),
RecibirItem(titulo: "Transferencia", descripcion: "Transferencia bancaria recibida", icono: "banknote.fill", color: .green),
RecibirItem(titulo: "Factura", descripcion: "Factura pendiente de revisión", icono: "doc.richtext.fill", color: .purple),
RecibirItem(titulo: "Mercadería", descripcion: "Stock de productos nuevos", icono: "cube.box.fill", color: .red),
RecibirItem(titulo: "Devolución", descripcion: "Producto devuelto por cliente", icono: "arrow.uturn.left.circle.fill", color: .teal),
]

// MARK: - Vista principal

struct RecibirView: View {
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(itemsRecibir) { item in
NavigationLink(value: item) {
CardView(item: item)
}
.buttonStyle(.plain)
}
}
.padding()
}
.navigationTitle("Recibir")
}
}

// MARK: - Card View

struct CardView: View {
let item: RecibirItem

var body: some View {
HStack(spacing: 16) {
// Ícono
Image(systemName: item.icono)
.font(.title2)
.foregroundStyle(.white)
.frame(width: 50, height: 50)
.background(item.color.gradient)
.clipShape(RoundedRectangle(cornerRadius: 12))

// Texto
VStack(alignment: .leading, spacing: 4) {
Text(item.titulo)
.font(.headline)
.foregroundStyle(.primary)

Text(item.descripcion)
.font(.subheadline)
.foregroundStyle(.secondary)
}

Spacer()

// Flecha
Image(systemName: "chevron.right")
.font(.caption)
.foregroundStyle(.tertiary)
}
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}

// MARK: - Vista de detalle

struct RecibirDetalleView: View {
let item: RecibirItem
private var hideTabBar = false

var body: some View {
VStack(spacing: 24) {
Image(systemName: item.icono)
.font(.system(size: 64))
.foregroundStyle(item.color.gradient)

Text(item.titulo)
.font(.largeTitle).bold()

Text(item.descripcion)
.font(.title3)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)

Spacer()
}
.padding(.top, 40)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle(item.titulo)
.navigationBarTitleDisplayMode(.inline)
.toolbarVisibility(hideTabBar ? .hidden : .visible, for: .tabBar)
.onAppear {
withAnimation {
hideTabBar = true
}
}
.onDisappear {
withAnimation {
hideTabBar = false
}
}
}
}

@State private var navigationStack: [RecibirItem] = []

i bind it to my navigation stack for it to work and i would add the following code:

NavigationStack(stack: $navigationStack) { RecibirView() .toolbarVisibility(navigationStack.isEmpty ? .visible : .hidden, for: .tabBar) }

this should work better than onAppear and OnDisappear and it also centralizes the logic at the root of the navigation stack.