Post

Replies

Boosts

Views

Activity

Compact screens, keyboard and dynamic type UI issues
When testing my app on an iPhone SE i noticed an issue with the UI when editing some text in a text field. When the keyboard comes up it pushes everything in the view up and part of the text field gets covered by the navigation title and buttons. It gets worse when testing dynamic fonts and changing the text to XXLarge or higher. There are no issues on a larger screen. Is it possible to prevent the keyboard from push up the content of the view when it is displayed? This is with the default font of large. This is with the extra large text var body: some View { NavigationStack { VStack { HStack { Text("Name") Spacer() TextField("Name", text: $name) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .frame(width: 240) .onChange(of: name) { if name.count >= 10 { isShowingLongNameWarning = true } else { isShowingLongNameWarning = false } } } VStack(alignment: .trailing){ HStack { Text("Short Name") Spacer() TextField("Short Name", text: $shortName.max(shortNameCharacterLimit)) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .frame(width: isShowingLongNameWarning ? 215 : 240) if isShowingLongNameWarning { VStack { Image(systemName: "exclamationmark.circle") } .popoverTip(shortNameTip) } } Text("Short Name Length: \(shortName.count) characters") .font(.caption) .foregroundStyle(shortName.count >= shortNameCharacterLimit ? .red : .primary) } HStack { Text("Fluid Amount") Spacer() TextField("Fluid Amount", value: $amount, format: .number) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .keyboardType(.decimalPad) .focused($numberPadIsFocused) .frame(width: 140) .toolbar { if numberPadIsFocused { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { numberPadIsFocused = false } } } } } HStack { Text("Unit of Measure") Spacer() Picker("Unit of measure", selection: $unitOfMeasure) { ForEach(FluidUnit.allCases) { Text($0.title) } } .tint(colorScheme == .dark ? .yellow : .pink) } .accessibilityElement() Toggle("Favorite Drink", isOn: $isFavorite) Text("Drink Image") ScrollView(.horizontal) { HStack{ ForEach(DataStore.drinkImages, id: \.self) { image in Button { selectDrinkImage(imageName: image) } label: { ZStack { Image(image) .resizable() .scaledToFit() .frame(height: 100) if imageName == image { SelectedDrinkImageView() } } } .padding(.trailing, 30) } } .scrollTargetLayout() } .scrollIndicators(.hidden) .scrollTargetBehavior(.viewAligned) Spacer() .navigationTitle("Add a Drink") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Save") { addDrink() } .tint(colorScheme == .dark ? .yellow : .pink) .disabled(disableSaveButton()) } ToolbarItem(placement: .topBarLeading) { Button("Cancel") { dismiss() } .tint(colorScheme == .dark ? .yellow : .pink) } } } .padding() } }
0
0
401
Jun ’24
how to open a binary webloc file with swift
I'm trying to get the url out of a binary webloc file, but I'm getting the follow error: NSURLConnection finished with error - code -1002. error: The file “link.webloc” couldn’t be opened. Does anyone know how to read a binary webloc file with swift? func readFile() { if let path = Bundle.main.path(forResource: "link", ofType: "webloc") { print("path: \(path)") if let url = URL(string: path) { do { let data = try Data(contentsOf: url) let plist = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) print("plist") } catch { print("error: \(error.localizedDescription)") } } } } I made a git repo of the project if anyone want to try it out. https://github.com/syclonefx/ReadWeblocFile. I have 2 different webloc files the link.webloc is a binary webloc file and the link2.webloc is a text webloc file
0
0
224
Jun ’24
Swift Chart causing app to crash when deleting an item from the data array
When deleting the last added item from a list view in my app a bar chart in a different view crashes my app. If I delete any other item in the list view everything work as expected. I'm using SwiftData in my app. Does anyone have any idea how I can prevent the app from crashing? I filter the data in the init to only have the current days data Chart View struct ConsumedDrinkChartView: View { @Environment(\.modelContext) var modelContext let screenVerticalSizeClass = UIScreen.VerticalSizeClass var compactScreen: Bool { return screenVerticalSizeClass == "compact" } @State private var chartCalendarUnit: Calendar.Component = .hour @State private var chartRange: ClosedRange<Date> @State private var axisValueLabelFormat: Date.FormatStyle @State private var axisValueLabelCount: Int @State private var startDate: Date @State private var endDate: Date @State private var plotStartPadding: Double = 0 @State private var plotEndPadding: Double = 0 @Binding var selectedTimeFrame:String @Query var consumedFluids: [ConsumedDrink] let defaultVolume = DataStore.defaultVolume init(selectedTimeFrame: Binding<String>, dateRange: ClosedRange<Date>) { _selectedTimeFrame = selectedTimeFrame _startDate = State(initialValue: Date().startOfDay) _endDate = State(initialValue: Date().endOfDay) let endDate = dateRange.upperBound let startDate = dateRange.lowerBound _consumedFluids = Query(filter: #Predicate { $0.date > startDate && $0.date < endDate }, sort: \ConsumedDrink.date) _chartRange = State(initialValue: dateRange) _axisValueLabelFormat = State(initialValue: .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow))) _axisValueLabelCount = State(initialValue: 2) } var body: some View { Chart { ForEach(consumedFluids) { consumedFluid in BarMark(x: .value("Date", consumedFluid.date, unit: chartCalendarUnit), y: .value("Fluid Ounces", consumedFluid.drink.amount)) } .foregroundStyle(.pink) } .frame(height: 180) .padding() .chartXAxis { AxisMarks(values: .stride(by: chartCalendarUnit, count: axisValueLabelCount,roundLowerBound: true, roundUpperBound: true)) { _ in AxisGridLine() AxisValueLabel(format: axisValueLabelFormat, centered: true) } } .chartXScale(domain: chartRange, range: .plotDimension(startPadding: plotStartPadding, endPadding: plotEndPadding)) .background(RoundedRectangle(cornerRadius: 12).fill(Color(.secondarySystemBackground))) .onChange(of: selectedTimeFrame) { selectChartRange() } .onChange(of: consumedFluids) { print("consumedFluids: \(consumedFluids.count)") } .onAppear { selectChartRange() } } func selectChartRange() { plotStartPadding = 0 plotEndPadding = 0 switch selectedTimeFrame { case "Day": startDate = Date().startOfDay endDate = Date().endOfDay chartCalendarUnit = .hour axisValueLabelCount = 2 axisValueLabelFormat = .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow)) case "Week": startDate = Date().add(days: -7) chartCalendarUnit = .day axisValueLabelCount = 1 axisValueLabelFormat = .dateTime.weekday() case "Month": startDate = Date().add(days: -30) chartCalendarUnit = .day axisValueLabelCount = 2 axisValueLabelFormat = .dateTime.day() plotStartPadding = 10 plotEndPadding = 10 case "SixMonths": let endOfMonth = Date().endOfMonth() startDate = endOfMonth.add(months: -6) chartCalendarUnit = .month axisValueLabelCount = 1 axisValueLabelFormat = .dateTime.month() plotStartPadding = 10 plotEndPadding = 32 case "Year": let endOfMonth = Date().endOfMonth() startDate = endOfMonth.add(months: -12) chartCalendarUnit = .month axisValueLabelCount = 1 axisValueLabelFormat = .dateTime.month(.narrow) plotStartPadding = 15 plotEndPadding = 15 default: chartCalendarUnit = .day } chartRange = startDate...endDate } } List View struct ConsumedDrinkListView: View { @Environment(\.modelContext) var modelContext @Query(sort: \ConsumedDrink.date) var dailyConsumedFluids: [ConsumedDrink] @State private var showingAlert = false @State private var alertMessage: String = "" @State private var alertTitle: String = "" var body: some View { NavigationStack { if dailyConsumedFluids.isEmpty { ContentUnavailableView("No Consumed Drinks", systemImage: "mug.fill", description: Text("Drink some water and stay hydrated.")) } else { List { ForEach(dailyConsumedFluids, id: \.self) { consumedDrink in NavigationLink { EditConsumedDrinkView(consumedDrink: consumedDrink) } label: { ConsumedDrinkRowView(consumedDrink: consumedDrink) } .swipeActions{ Button("Delete", systemImage: "trash", role: .destructive) { deleteConsumedDrink(consumedDrink: consumedDrink) } .tint(.red) } } } .listStyle(.plain) .alert(isPresented: $showingAlert) { Alert(title: Text(alertTitle), message: Text(alertMessage), dismissButton: .default(Text("OK")) ) } } Text("") .navigationTitle("Consumed Drinks") .navigationBarTitleDisplayMode(.inline) } } func deleteConsumedDrink(consumedDrink: ConsumedDrink) { do { if modelContext.hasChanges { print("ConsumedDrinkListView.deleteConsumedDrink") print("modelContext has Changes. Saving modelContext") try modelContext.save() } try DataStore.deleteConsumedDrink(drink: consumedDrink, modelContext: modelContext) } catch { self.alertTitle = "Error deleting consumed drink - \(consumedDrink.drink.name)" self.alertMessage = error.localizedDescription self.showingAlert = true } } }
2
0
511
Jun ’24
SwiftData enum No exact matches in call to instance method 'setValue' error
I'm getting an "No exact matches in call to instance method 'setValue'" error for a property that has a enum as a value. How do I fix this? Any help would be appreciated. enum FluidUnit: CaseIterable, Identifiable { case ounce, liter var id: Self { self } var title: String { switch self { case .ounce: return "ounce" case .liter: return "liters" } } } @Model class Drink: Identifiable, Hashable { let id: UUID = UUID() let name: String = "" var shortName: String = "" var amount: Double = 0.0 let unitOfMeasure: FluidUnit = FluidUnit.ounce let date: Date = Date() var image: String = "water" var favorite: Bool = false init(name: String, amount: Double, unitOfMeasure: FluidUnit, image: String, favorite: Bool = false, shortName: String = "") { self.id = UUID() self.name = name self.amount = amount self.unitOfMeasure = unitOfMeasure self.date = Date() self.image = image self.favorite = favorite self.shortName = shortName } static func == (lhs: Drink, rhs: Drink) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } }
1
0
546
May ’24