I'm working on a SwiftUI project where I use a .sheet modifier to present a bottom drawer with two detent sizes: .medium and .large. The drawer contains a button that toggles its size between these two states. This part works as expected. However, I'm facing an animation issue when I set a non-default background color to the sheet.
Here's the simplified code for context:
struct ContentView: View {
@State private var selectedDetent: PresentationDetent = .medium
var body: some View {
VStack {}
.sheet(isPresented: .constant(true)) {
Button("Press Me") {
selectedDetent = selectedDetent == .medium ? .large : .medium
}
.presentationBackground(.gray)
.presentationDetents([.medium, .large], selection: $selectedDetent)
}
}
}
The issue arises when I try to set a background color using .presentationBackground(.gray) (or any color, even white). Instead of the expected behavior when pressing the button (where the upper part of the sheet closes, and the bottom part stays attached to the screen bottom), the sheet momentarily turns into a square in the middle of the screen before moving down to the .medium position.
As soon as I remove the.presentationBackground(.gray) line, it works as expected:
I tried several approaches, such as:
Using a custom background view.
Explicitly specifying animations.
Adjusting view hierarchy and layering.
Unfortunately, none of these solutions worked. The issue persists with any color. It seems like a bug or limitation in SwiftUI's handling of sheet animations with custom backgrounds.
Has anyone else encountered this issue, or does anyone have a workaround or solution?
Post
Replies
Boosts
Views
Activity
App was rejected with:
Guideline 2.3 - Performance - Accurate Metadata
We were unable to locate some of the features described in your metadata. > Specifically, “Languages: English and Portuguese (PT and BR).”.
My app is indeed localized in these three languages, tested and working. The app automatically adapts its language to match the user's iOS system language settings.
Isn't this enough?
I replied to the rejection saying this, but I find it hard to believe that the reviewer didn't change the iOS system language settings. Is it possible, or is it something else?
Also, do I need to press the "Add For Review Button" so he can see my reply?
Thank you.
I've encountered an animation glitch affecting the text for AxisMarks and AxisLabels in the SwiftUI Chart framework. Below are the sample project code and animated gif for reference:
(I'm not being able to attach the gif for some reason. Here's my StackOverflow post with a the gift: https://stackoverflow.com/questions/77007744/swiftui-chart-text-animation-glitch-with-axismarks-and-axislabels)
struct ContentView: View {
@State var isDisplayingAge = true
var body: some View {
ChartView(data: ChartDataSample, isDisplayingAge: isDisplayingAge)
.onTapGesture {
withAnimation {
isDisplayingAge.toggle()
}
}
}
}
struct ChartData: Identifiable {
let age: Int
let presence: Int
let grade: Int
let id = UUID()
}
struct ChartView: View {
let data: [ChartData]
let isDisplayingAge: Bool
let xAxis = [0, 50, 100]
var body: some View {
VStack {
Chart {
ForEach(data) { chartData in
BarMark(x: .value("X Axis", isDisplayingAge ? chartData.age : chartData.presence),
y: .value("Y Axis", chartData.grade))
}
}
.chartXAxis(content: {
AxisMarks(position: .bottom, values: xAxis.map{$0}) { data in
AxisValueLabel(String(xAxis[data.index]) + (isDisplayingAge ? " years" : " days"))
}
})
.chartXAxisLabel(content: {
Text(isDisplayingAge ? "Data: age" : "Data: presence")
})
}
.padding(.horizontal, 13)
}
}
As you can observe, when I tap the chart to trigger a content change with animation, the text for AxisMarks (e.g., x years / x days) and AxisLabels (e.g., Data: age / Data: presence) animates unusually. A portion of the text is temporarily replaced by an ellipsis ("...") during the animation.
Interestingly, this issue occurs only in one direction of the animation. When transitioning from "year" to "day" or from "presence" to "age," the text simply gets replaced without any noticeable animation.
Can anyone explain what's happening here? Ideally, I'd like the texts to either fade into each other or be replaced without any animation.
Thank you.
I'm using the new SwiftUI Charts framework to display data in a vertical bar chart, but I'm having trouble centering the Y-axis date labels on each bar:
struct ChartEntry: Identifiable {
var id = UUID()
let labelDate: Date
let amount: Int
}
struct ContentView: View {
let chartContent: [ChartEntry]
var body: some View {
Chart {
ForEach(chartContent) { entry in
BarMark(x: .value("Value", entry.amount),
y: .value("Hour Label", entry.labelDate, unit: .hour))
}
}
.chartYAxis {
AxisMarks(position: .leading, values: chartContent.map{$0.labelDate}) { data in
AxisValueLabel()
}
}
.chartXScale(domain: 0...50)
}
}
This code generates a chart with Y-axis date labels aligned to the bottom of the bars (I populated the chartContent object with sample entries):
I want to center the labels on each bar.
I've tried AxisValueLabel(centered: true). It moved all the Y-axis date labels down in an apparent random amount. Now they are misaligned and in the wrong place. Additionally, the first row is missing a label:
I've also tried AxisMarks(preset: .aligned), but it doesn't change anything.
How can I center the Y-axis date labels on each bar?
I'm aware of this question and this question, but these solutions do not solve the problem.
Thank you very much.
In SwiftUI, I have a .searchable searchbar with a TabView in the .page style as the content. When the user taps the cancel button, the searchbar disappears.
import SwiftUI
struct ContentView: View {
@State var searchText = ""
var body: some View {
NavigationView {
TabView {
Text("Tab Content")
}
.tabViewStyle(.page)
}
.searchable(text: $searchText)
}
}
That's what happens:
Removing the .tabViewStyle(.page) fixes the problem (but then I cannot use the .page style of TabView):
Am I doing something wrong? Or is this a SwiftUI bug?
I can't fetch the weather using the WeatherKit framework inside a Widget Extension.
Here's a project I created just for this example. This widget shows the humidity of a sample location.
Here's the code:
import WidgetKit
import SwiftUI
import WeatherKit
import CoreLocation
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), humidity: 9.99) // placeholder humidity
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), humidity: 9.99) // placeholder humidity
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
Task {
let nextUpdate = Date().addingTimeInterval(3600) // 1 hour in seconds
let sampleLocation = CLLocation(latitude: 51.5072, longitude: 0.1276) // sample location (London)
let weather = try await WeatherService.shared.weather(for: sampleLocation)
let entry = SimpleEntry(date: .now, humidity: weather.currentWeather.humidity)
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let humidity: Double
}
struct WidgetWeatherTestWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Text("\(entry.humidity)")
}
}
struct WidgetWeatherTestWidget: Widget {
let kind: String = "WidgetWeatherTest"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
WidgetWeatherTestWidgetEntryView(entry: entry)
}
.configurationDisplayName("Widget Weather Test")
.description("Testing weatherkit in a Widget")
.supportedFamilies([.systemMedium])
}
}
It works fine in the simulator:
But it doesn't work in a real device. As soon as I call WeatherService's weather(for: CLLocation) async throws -> Weather the widget get's "blocked":
I've tried moving the try await WeatherService.shared.weather(for: sampleLocation) to different places, but nothing worked. As soon as I comment out this line (and create an entry with a placeholder humidity) everything works.
I added the WeatherKit capability in the main app target and in the WidgetExtension target. I also added the WeatherKit "Capability" and "App Service" in the "Certificates, Identifiers & Profiles" of the Apple Developer website.
The WeatherKit framework works fine in other parts of the main app.
I haven't tried using the WeatherKit REST API, yet.
Any ideas what could be happening?
CLGeocoder's geocodeAddressString function always return an array with only one CLPlacemark object, independently of the string passed as a parameter.
I'm using it like this:
let placesArray = try await CLGeocoder().geocodeAddressString(addressString)
CLGeocoder's documentation is clear:
In the case of forward-geocoding requests, multiple placemark objects
may be returned if the provided information yielded multiple possible
locations.
But that never happens. Even when passing something like "San" which should obvioulsy return an array with many CLPlacemark possibilities.
I've seen this same question asked in multiple places (like here, here, here, and here) but I can't find an answer.
Is this a bug? Am I doing something wrong? How can I obtain multiple possible locations from CLGeocoder?
EDIT: MKLocalSearch
I tried the same thing using MKLocalSearch:
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = addressString
let search = MKLocalSearch(request: searchRequest)
let responses = try await search.start()
Same problem, the returned MKLocalSearch.Response's mapItems array always contains only one object. Very strange.