Hi community:
I noticed that each closure is counted as lines in code coverage (unit tests) (Xcode 14.1.0) in a swiftUI File. I mean, If you coded and VStack that involves another HStack, and HStack contains 4 lines, and the VStack contains 6 lines counting the HStack. The total executable lines should be 6 (6 lines in the file). But Xcode count 10, counting twice the HStack lines.
Is it a bug, or is it correct? You know, I don't know if Apple has another concept about executable lines.
Also, Is it possible to remove previews with any configuration from code coverage or constant files?
Thanks for all.
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
What I am trying to build
Apple Watch app(written in SwiftUI, targeting watchOS 7 or higher, built with Xcode 14.1)
The Problem
Picker placed inside a ScrollView on an apple watch device does not work as expected
I want to find out how to get the Picker to work as expected, stated below.
Expected behavior
On an iOS simulator, a Picker inside a ScrollView works as expected.
If I try scroll interaction on the Picker area, the ScrollView part doesn’t get scrolled and only the Picker gets scrolled.
whereas on the watch simulator Example,
If I try to scroll the Picker by touching the Picker area, the whole ScrollView reacts and moves up and down. And I am not able to control the Picker properly.
The code I wrote is as follows:
ScrollView {
//..other view elements..
Picker(selection: $currentDay) {
ForEach(weekDays, id: \.self) {
Text($0)
}
} label: {
Text("")
}
.frame(width: 148,height: 50)
.pickerStyle(.wheel)
//..other view elements..
}//: ScrollView
Things I have tried
putting the Picker inside a VStack/ZStack/HStack
giving the Picker fixed frame values / giving other elements inside the ScrollView fixed frame values
Generic parameter 'V' could not be inferred ERROR
Is there a way to observe the currentEDRHeadroom property of UIScreen for changes? KVO is not working for this property...
I understand that I can query the current headroom in the draw(...) method to adapt the rendering. However, our apps only render on-demand when the user changes parameters. But we would also like to re-render when the current EDR headroom changes to adapt the tone mapping to the new environment.
The only solution we've found so far is to continuously query the screen for changes, which doesn't seem ideal. It would be better if the property would be observable via KVO or if there would be a system notification to listen for.
Thanks!
I want to add a widget to my app that will display the # of pickups the user has for the day. I have the DeviceActivityReport working in the main app but can't get it to display in the widget since it is not a supported view for widgets. Is there any workaround for getting this view to the widget?
I tried converting the DeviceActivityReport view to a UI image thinking maybe that would be a way to use a widget approved view type but ImageRenderer seems to fail to render an image for the view (which is just a Text view).
To summarize my questions:
Is it possible to display a DeviceActivityReport in a widget? If so, what is the best practice?
Is converting the DeviceActivityReport view into an image and displaying that in a widget an option?
Here's my attempt to convert the DeviceActivityReport view into a UIImage:
import SwiftUI
import _DeviceActivity_SwiftUI
struct PickupsDeviceActivityReport: View {
@State private var context: DeviceActivityReport.Context = .totalActivity
@State private var renderedImage = Image(systemName: "exclamationmark.triangle")
@Environment(\.displayScale) var displayScale
var body: some View {
renderedImage
.onAppear { render() }
.onChange(of: context) {
_ in render()
}
}
@MainActor func render() {
let renderer = ImageRenderer(content: DeviceActivityReport(context))
renderer.scale = displayScale
if let uiImage = renderer.uiImage {
renderedImage = Image(uiImage: uiImage)
}
}
}
Help is appreciated. Thank you.
I have find out that a UIViewRepresentable, even with a simples UIView, seems to never be dismantled when deleted from a ForEach and this can cause serious crashes.
In the following example you can observe this behavior by deleting a row from the list. The dismantleUIView function of SomeUIViewRepresentable or the deinit of SomeUIView are never called.
Has anyone faced this and found a solution for it?
I have also filled a Feedback: FB11979117
class SomeUIView: UIView {
deinit {
print(#function)
}
}
struct SomeUIViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> SomeUIView {
let uiView = SomeUIView()
uiView.backgroundColor = .systemBlue
return uiView
}
func updateUIView(_ uiView: SomeUIView, context: Context) { }
static func dismantleUIView(_ uiView: SomeUIView, coordinator: Coordinator) {
print(#function)
}
}
struct Model: Identifiable {
let id = UUID()
}
struct ContentView: View {
@State var models = [Model(), Model(), Model(), Model(), Model()]
var body: some View {
List {
ForEach(models) { _ in
SomeUIViewRepresentable()
}
.onDelete {
models.remove(atOffsets: $0)
}
}
}
}
I'm trying to create a List that allows multiple selection. Each row can be edited but the issue is that since there's a tap gesture on the Text element, the list is unable to select the item.
Here's some code:
import SwiftUI
struct Person: Identifiable {
let id: UUID
let name: String
init(_ name: String) {
self.id = UUID()
self.name = name
}
}
struct ContentView: View {
@State private var persons = [Person("Peter"), Person("Jack"), Person("Sophia"), Person("Helen")]
@State private var selectedPersons = Set<Person.ID>()
var body: some View {
VStack {
List(selection: $selectedPersons) {
ForEach(persons) { person in
PersonView(person: person, selection: $selectedPersons) { newValue in
// ...
}
}
}
}
.padding()
}
}
struct PersonView: View {
var person: Person
@Binding var selection: Set<Person.ID>
var onCommit: (String) -> Void = { newValue in }
@State private var isEditing = false
@State private var newValue = ""
@FocusState private var isInputActive: Bool
var body: some View {
if isEditing {
TextField("", text: $newValue, onCommit: {
onCommit(newValue)
isEditing = false
})
.focused($isInputActive)
.labelsHidden()
}
else {
Text(person.name)
.onTapGesture {
if selection.contains(person.id), selection.count == 1 {
newValue = person.name
isEditing = true
isInputActive = true
}
}
}
}
}
Right now, you need to tap on the row anywhere but on the text to select it. Then, if you tap on the text it'll go in edit mode.
Is there a way to let the list do its selection? I tried wrapping the tap gesture in simultaneousGesture but that didn't work.
Thanks!
I'm trying to implement the same UI used by the Settings app on iPad: a split view with two columns that are visible at all times.
This code produces the layout i want, but I would like to hide the "toggle sidebar visibility" button that the system introduces.
Is there a SwiftUI API I can use to hide this button? Maybe an alternate way to setup views that tells the system that the button is not necessary?
struct SomeView: View {
var body: some View {
NavigationSplitView(
columnVisibility: .constant(.all),
sidebar: { Text("sidebar") },
detail: { Text("detail") }
)
.navigationSplitViewStyle(.balanced)
}
}
I'm building a macOS app using SwiftUI and I recently updated to xcode 14.3. Since then I've been debugging why none of my animations were working, it turned out that the NavigationSplitView or NavigationStack are somehow interfering with all the animations from withAnimation to .transition() and everything in between.
Is anyone else experiencing this, knows a work around or knows why this is happening?
Hello Team,
We have Advanced App Clip Experiences live but we have add App Clip experience URL since long ago but status remains as Received and never changed to Published, can you please help us to fix this issue.
Please see attached.
Thanks
I have an app that uses UITextView for some text editing. I have some custom operations I can do on the text that I want to be able to undo, and I'm representing those operations in a way that plugs into NSUndoManager nicely. For example, if I have a button that appends an emoji to the text, it looks something like this:
func addEmoji() {
let inserting = NSAttributedString(string: "😀")
self.textStorage.append(inserting)
let len = inserting.length
let range = NSRange(location: self.textStorage.length - len, length: len)
self.undoManager?.registerUndo(withTarget: self, handler: { view in
view.textStorage.deleteCharacters(in: range)
}
}
My goal is something like this:
Type some text
Press the emoji button to add the emoji
Trigger undo (via gesture or keyboard shortcut) and the emoji is removed
Trigger undo again and the typing from step 1 is reversed
If I just type and then trigger undo, the typing is reversed as you'd expect. And if I just add the emoji and trigger undo, the emoji is removed. But if I do the sequence above, step 3 works but step 4 doesn't. The emoji is removed but the typing isn't reversed.
Notably, if step 3 only changes attributes of the text, like applying a strikethrough to a selection, then the full undo chain works. I can type, apply strikethrough, undo strikethrough, and undo typing.
It's almost as if changing the text invalidates the undo manager's previous operations?
How do I insert my own changes into UITextView's NSUndoManager without invalidating its chain of other operations?
I've discovered an issue with using iOS 16's Transferable drag-and-drop APIs for SwiftUI. The dropDestination modifier does not work when applied to a subview of a List.
This code below will not work, unless you replace the List with a VStack or any other container (which, of course, removes all list-specific rendering).
The draggable modifier will still work and the item will drag, but the dropDestination view won't react to it and neither closure will be called.
struct MyView: View {
var body: some View {
List {
Section {
Text("drag this title")
.font(.largeTitle)
.draggable("a title")
}
Section {
Color.pink
.frame(width: 400, height: 400)
.dropDestination(for: String.self) { receivedTitles, location in
true
} isTargeted: {
print($0)
}
}
}
}
}
Has anyone encountered this bug and perhaps found a workaround?
I'm in the process of migrating to the Observation framework but it seems like it is not compatible with didSet. I cannot find information about if this is just not supported or a new approach needs to be implemented?
import Observation
@Observable class MySettings {
var windowSize: CGSize = .zero
var isInFullscreen = false
var scalingMode: ScalingMode = .scaled {
didSet {
...
}
}
...
}
This code triggers this error:
Instance member 'scalingMode' cannot be used on type 'MySettings'; did you mean to use a value of this type instead?
Anyone knows what needs to be done? Thanks!
I am using a LayzVStack embedded into a ScrollView. The list items are fetched from a core data store by using a @FetchResult or I tested it also with the new @Query command coming with SwiftData.
The list has one hundred items 1, 2, 3, ..., 100.
The user scrolled the ScrollView so that items 50, 51, ... 60 are visible on screen.
Now new data will be fetched from the server and updates the CoreData or SwiftData model. When I add new items to the end of the list (e.g 101, 102, 103, ...) then the ScrollView is keeping its position.
Opposite to this when I add new items to the top (0, -1, -2, -3, ...) then the ScrollView scrolls down.
Is there a way with the new SwiftData and SwiftUI ScrollView modifiers to update my list model without scrolling like with UIKit where you can query and set the scroll offset pixel wise?
When I update a variable inside my model that is marked @Transient, my view does not update with this change. Is this normal? If I update a non-transient variable inside the model at the same time that I update the transient one, then both changes are propagated to my view.
Here is an example of the model:
@Model public class WaterData {
public var target: Double = 3000
@Transient public var samples: [HKQuantitySample] = []
}
Updating samples only does not propagate to my view.
Simplely, when we set UITextView.inputView and then call becomeFirstResponder, but the custom inputView could not show expectedly just like before. We test this code in iOS17 and below, while only iOS17 does not work.
And xcode console print these logs:
Failed to retrieve snapshot.
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID
Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked:
Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked:
Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked:
Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked:
So I am trying to move an old project from ios16 to ios17... wanted to play around with the new previews, and animations and first error I get is the above.
When I create a new project I can use the macro just fine.
What is more: when I add a new swiftUI file I get the same error with the #Preview macro.
I went through the project and target settings, making sure everything is set to ios17 and Swift5, but can't find any other settings. Cleared the build cache and rebuilt from scratch.
Hoping someone else ran onto the same problem and found a solution?
Without using #Preview
When showing an Alert from within a Popover that has a fixed height, the newly presented Alert is in the same position but gets limited by the Popovers height causing the title of the Alert to be hidden. Is this intentional behavior or are Alerts not supported within Popovers and I'd have to pass it through to my main view?
Code:
//
// DemoalertPopover.swift
// ********
//
// Created by Thilo on 26.06.2023.
//
import SwiftUI
struct DemoAlertPopover: View {
@Environment(\.dismiss) var dismiss
@State private var showDeleteConfirmation = false
let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy"
return formatter
}()
var body: some View {
VStack(alignment: .leading, spacing: 0) {
HStack {
Text("Title").font(.extraLargeTitle).lineLimit(1)
Spacer()
Button(action: {
dismiss()
}) {
Label("Close", systemImage: "xmark").labelStyle(.iconOnly)
}
}
HStack(alignment: .center) {
Text("Content").font(.largeTitle)
Text("Content2").foregroundStyle(.secondary)
}
LazyVGrid(columns: [GridItem(.flexible(), spacing: 10),GridItem(.flexible(), spacing: 10),], spacing: 10) {
Button(action: {
showDeleteConfirmation = true
}) {
ZStack{
Image(systemName: "trash.fill").resizable().foregroundColor(.primary)
}.aspectRatio(1/1,contentMode: .fit)
.frame(maxWidth: .infinity).padding(5)
}.aspectRatio(3/1,contentMode: .fit)
}.alert("Are you sure you want to delete ...?", isPresented: $showDeleteConfirmation) {
Button("Trash",role: .destructive, action: {
print("Deleted")
dismiss()
})
Button("Cancel", role: .cancel) {}
} message: {
Text("This is a small message below the title, just so you know.")
}
}
.padding(.all, 10).frame(width: 300)
}
}
#Preview {
DemoAlertPopover()
}
Video:
https://www.youtube.com/shorts/31Kl7qbJIiA
On iOS17, UIDevice.current.batteryLevel is returning values rounded to 0.05, such as 1, 0.95, 0.9. Which used to be a 1% granularity in iOS16. Is this a bug or a new feature?
Help,I have encountered a thorny problem! In systems with iOS 16.5 and above, there is a probability that the keyboard will not disappear after it appears. And once it appears, unless the app is restarted, all places where the keyboard is used cannot be closed.
I have tried using the forced shutdown method [UIView endEditing:YES], but it didn't work. When this exception occurs, I notice that there will be two UITextEffectsWindow at the same time.
Does anyone know how to solve it?