ScrollViewReader actually provides a ScrollViewProxy with a function scrollTo(_ id:, anchor:) that you can use to scroll to the position of a View related to a given id:
struct ContentView: View {
@State private var position = 0
var body: some View {
VStack {
HStack {
Button("Top") { position = 0 }
Button("Middle") { position = 500 }
Button("Bottom") { position = 1000 }
}
ScrollView {
ScrollViewReader { proxy in
LazyVStack {
ForEach(0...1000, id: \.self) { index in
Text("Row \(index)")
}
}
.onChange(of: position) { value in
withAnimation {
proxy.scrollTo(value, anchor: .center)
}
}
}
}
}
}
}
Post
Replies
Boosts
Views
Activity
You can get the position by using GeometryReader to read the scrollView content frame, pass the value using PreferenceKey and observe it:
struct ContentView: View {
var body: some View {
ScrollView {
ZStack {
LazyVStack {
ForEach(0...100, id: \.self) { index in
Text("Row \(index)")
}
}
GeometryReader { proxy in
let offset = proxy.frame(in: .named("scroll")).minY
Color.clear.preference(key: ScrollViewOffsetPreferenceKey.self, value: offset)
}
}
}
.coordinateSpace(name: "scroll")
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in
print(value)
}
}
}
The .frame(in: .named("scroll")) is required to get the frame relative to the ScrollView and obtain a 0 offset when at the top, without the height of the safe area. If you try using .frame(in: .global) you will get a non-zero value when the scroll view is at the top (20 or 44, depends on the device).
I've noticed this too and I believe it’s because Label is made to be used in specific places, like in a tab item.
You can achieve this using the .fullScreenCover modifier as in the following example:
import SwiftUI
struct ContentView: View {
@State private var isPresented = false
var body: some View {
Button("Present") {
isPresented.toggle()
}
.fullScreenCover(isPresented: $isPresented) {
ModalView()
}
}
}
struct ModalView: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
Button("Dismiss") {
presentationMode.wrappedValue.dismiss()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.red)
.foregroundColor(Color.white)
.edgesIgnoringSafeArea(.all)
}
}
When a sample code is appearing in the video there is a button available in the upper left corner to copy the code to clipboard.
The problem is the fact that in your code you end up with repeated identifiers and I believe that LazyVStack requires the ids to be unique. I managed to make it work using a UUID as an identifier:
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack{
ForEach(0...2, id: \.self) { section in
Section {
ForEach(0..<2) { item in
Text("Section: \(section), Item: \(item)")
.id(UUID())
}
}
}
}
}
}
}
You can also use the @UIApplicationDelegateAdaptor property wrapper if you prefer the UIKit way.
@main
struct SampleApp: App {
@UIApplicationDelegateAdaptor var delegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print(#function)
return true
}
}
You can use the isActive parameter of NavigationLink to bind a property and trigger the push changing the property value to true:
struct ContentView: View {
@State private var isActive = false
var body: some View {
NavigationView {
VStack {
Button("Present") {
isActive = true
}
NavigationLink(destination: Color.red, isActive: $isActive) { }
}
}
}
}
I'm using a Button action to change the value but you can do it in the error handling for example.
You can send a UIResponder.resignFirstResponder action to UIApplication.shared:
struct ContentView: View {
@State private var text = ""
var body: some View {
VStack {
TextField("Enter something here", text: $text).fixedSize()
Button("Done") {
let resign = #selector(UIResponder.resignFirstResponder)
UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
}
}
}
}
Yes, you can setup everything you need directly in your App as following:
@main
struct SampleApp: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
MovieList()
.environment(\.managedObjectContext, persistentContainer.viewContext)
}
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print("active")
case .inactive:
print("inactive")
case .background:
print("background")
saveContext()
}
}
}
var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "SampleApp")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext() {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Unfortunately I believe the only alternative without using a UIColorPickerViewController is to convert the description (which returns a hexadecimal value) property of the Color from HEX to RGBa.
You can manage the App life cycle using @Environment(\.scenePhase) and @UIApplicationDelegateAdaptor as following:
class AppDelegate: NSObject, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplication) {
print(#function)
}
}
@main
struct SampleApp: App {
@Environment(\.scenePhase) private var scenePhase
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print("active")
case .inactive:
print("inactive")
case .background:
print("background")
}
}
}
}
Use the Feedback Assistant to report this and other bugs:
https://feedbackassistant.apple.com
You can use the datePickerStyle modifier to set the style for a DatePicker as following:
struct ContentView: View {
@State private var birthdate = Date()
var body: some View {
DatePicker("Date of Birth", selection: $birthdate, displayedComponents: .date)
.datePickerStyle(WheelDatePickerStyle())
}
}
DefaultDatePickerStyle (iOS, macOS)
The default DatePicker style.
WheelDatePickerStyle (iOS)
A system style of date picker that displays each component as columns in a scrollable wheel.
FieldDatePickerStyle (macOS)
A system style that displays the components in an editable field.
GraphicalDatePickerStyle (iOS)
A system style of DatePicker that displays an interactive calendar or clock.
StepperFieldDatePickerStyle (macOS)
A system style that displays the components in an editable field, with adjoining stepper that can increment/decrement the selected component.
Here is an example that uses CoreLocation to provide a MKCoordinateRegion to a Map:
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var region = MKCoordinateRegion()
private let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locations.last.map {
let center = CLLocationCoordinate2D(latitude: $0.coordinate.latitude, longitude: $0.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
region = MKCoordinateRegion(center: center, span: span)
}
}
}
struct ContentView: View {
@StateObject private var manager = LocationManager()
var body: some View {
Map(coordinateRegion: $manager.region, showsUserLocation: true)
}
}