Post

Replies

Boosts

Views

Activity

Reply to Swift + OS X + Xcode : Change NavigationLink destination and text programtically
I have looked at using observable objects and adjusted my code as shown below. Xcode does not like any line with the word ObservableObject in it. The attempt I am trying to make is to change the firstPass variable so that the navigation panel in ContentView redraws. I was going also link the observable object to the NextContentView view, toggle it there then hope that the ContentView navigation panel finally redraws and shows the updated button text and NavigationLink destination. My hope is that I have made some simple stupid error. Any help would be appreciated. Chris import SwiftUI import Combine class SelectedView: ObservedObject {     @Published var firstPass : Bool = true } struct ContentView: View {          @ObservedObject var theSelection = SelectedView()          var body: some View {         NavigationView {             if (self.theSelection.firstPass){                 NavigationLink(destination: NextContentView()){                     Text ("Next View")                 }             }             else {                 NavigationLink(destination: ContentView()) {                     Text ("Previous View")                         }                 }             }     } }
Aug ’21
Reply to Remove gap between lazyvgrids in vstack
Yes, between those two lazyVgrids. I ended up adding negative padding right after the closing } of the first lazyVgrid and it removed the gap. .padding(.bottom, - 7.5) As far as a screen shot I know how to cut out a section with shift + command + 4. When I select the paper clip below and add image I select the associated png file from my desktop but I do no see it appear in this box. I clearly do not understand how to do it. Below is the section of code that includes the two lazyVgrids and the added padding. Thank you for giving me the heads up on paste and match style. It sure looks a lot cleaner. Regards, Chris LazyVGrid( columns: columns, alignment: .center, spacing: 0) { ForEach(0..<1) {row in ForEach(0..<numElementsPerArray) {col in Rectangle() .foregroundColor(.white) .overlay (Text(principalData.csvData[row][col]).bold()) .frame(height: 30) .border(Color.gray, width: 2) } } }.padding(.bottom, -7.5) ScrollView{ LazyVGrid(
Sep ’21
Reply to Create Spreadsheet Like Grid with SwiftUI
It appears that I should have been using GridItems. They have solved my problem. Below is the code: struct DateAndCloseTable: View { let containerData: [CommonAttributes] let heading: String let verticalSpacing: CGFloat = 0 let frameWidth: CGFloat = 100 let frameHeight: CGFloat = 25 let horizontalSpacing: CGFloat = 0 let trailingPadding: CGFloat = 45 let bottomPadding: CGFloat = -2 let columns = [ GridItem(.fixed(75), spacing: 0), GridItem(.fixed(75), spacing: 0) ] var body: some View { Text("") Text(heading) .font(.system(size: 18, weight: .bold, design: .default)) .foregroundColor(.blue) .padding(.trailing, 24) Text("") ScrollView { let lastRowIndex: Int = containerData.count - 1 LazyVGrid(columns: columns, alignment: .center, spacing: verticalSpacing){ ForEach((0...lastRowIndex), id: \.self) { index in let theDate = dateToStringFormatter.string(from: containerData[index].date!) let theClose = String(format: "$%.2f", containerData[index].close ) Text(theDate) .font(.system(size: 14, weight: .regular, design: .default)) .frame(width: frameWidth, height: frameHeight, alignment: .center) .background(.white) .border(.black, width: 1) .padding(.trailing, trailingPadding) .padding(.bottom, bottomPadding) Text(theClose) .font(.system(size: 14, weight: .regular, design: .default)) .frame(width: frameWidth, height: frameHeight, alignment: .center) .background(.white) .border(.black, width: 1) .padding(.bottom, bottomPadding) } Text("") Text("") Text("") } // end lazy v grid .padding(.horizontal) } // end of scroll view } }
Aug ’22
Reply to Charts: How do I position x axis value labels below the associated grid lines
After some additional research I was able to position values with the AxisValueLabel horizontal and vertical spacing parameters. I was not able to figure out how to get Charts to place a value under the far right vertical grid line, i.e. my 5th date. So I resolved the problem by removing the AxisValueLabel code and using an overlay along with x & y positioning of the values. See updated code below. struct LineChart: View { private var localArray: [TradingDayPrices] private var chartTitle: String private var numYears: Int init(passedInArray: [TradingDayPrices], chartTitle: String, numYears: Int) { self.localArray = passedInArray self.chartTitle = chartTitle self.numYears = numYears } var body: some View { let minCloseValue: Double = localArray.map { $0.close }.min()! let maxCloseValue: Double = localArray.map { $0.close }.max()! let minDate: Date = localArray[0].timeStamp! let itemCount: Int = localArray.count - 1 let maxDate: Date = localArray[itemCount].timeStamp! let dateArray: [Date] = GetXAxisLabels(min: minDate, max: maxDate, numYears: numYears) Spacer() GroupBox (label: Text("\(chartTitle)") .font(Font.custom("Arial", size: 20)) .frame(width: 700, height: 50, alignment: .center)) { Chart { ForEach(localArray) { item in LineMark ( x: .value("TimeStamp", item.timeStamp!), y: .value("Close", item.close) ) .foregroundStyle(Color.blue) .lineStyle(StrokeStyle(lineWidth: 1.25)) } // end for each } // end chart .padding(50) .chartBackground { item in Color.white } .chartXAxisLabel(position: .bottom, alignment: .center, spacing: 25) { Text("") } .chartYAxisLabel(position: .leading, alignment: .center, spacing: 25) { Text("Closing Value") .font(.system(size: 14)) .foregroundColor(Color.black) } .chartXAxis { AxisMarks (values: dateArray) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisTick(centered: true, length: 7 , stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) } // end axis marks } // end chart x axis .chartYAxis { AxisMarks (position: .leading, values: GetYAxisLabels(min: minCloseValue, max: maxCloseValue)) { value in AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisTick(centered: true, length: 7 , stroke: StrokeStyle(lineWidth: 0.5)) .foregroundStyle(Color.gray) AxisValueLabel(verticalSpacing: 10) { if let localValue = value.as(Double.self) { let formattedValue = String(format: "$%.2f", localValue) Text(formattedValue) .font(.system(size: 12)) .foregroundColor(Color.black) } } } // end axis marks } // end chart y axis .chartXScale(domain: minDate...maxDate) .chartYScale(domain: minCloseValue...maxCloseValue) .frame(width: 700, height: 700, alignment: .center) .overlay { let dateValue0 = dateToStringFormatter.string(from: dateArray[0]) Text(dateValue0).position(x: 155, y: 620) let dateValue1 = dateToStringFormatter.string(from: dateArray[1]) Text(dateValue1).position(x: 275, y: 620) let dateValue2 = dateToStringFormatter.string(from: dateArray[2]) Text(dateValue2).position(x: 398, y: 620) let dateValue3 = dateToStringFormatter.string(from: dateArray[3]) Text(dateValue3).position(x: 522, y: 620) let dateValue4 = dateToStringFormatter.string(from: dateArray[4]) Text(dateValue4).position(x: 654, y: 620) Text("Date").position(x: 398, y: 655) .font(.system(size: 14)) .foregroundColor(Color.black) } // end overlay } // end group box frame Spacer().frame(height:65) } // end of body } // end of structure
Nov ’22
Reply to Creating Instance of Class of type NSWindowController
Looks like I was heading down the wrong path. I find that I need to work with NSWindow, not NSWindowController, and among other things, its style mask. I found some code on line that lets me position the window on the screen. I made some modifications to it and added a function setStyleMask which is an extension to NSWndow. It allows me to make the modifications I want. Below is the updated code. My ContentView does not change with the exception of the elimination of @State private var winController = WinController(). import SwiftUI @main struct BouncingWheelApp: App { var body: some Scene { WindowGroup { ContentView() .hostingWindowPosition( vertical: .center, horizontal: .center, screen: .main) } } } import SwiftUI import AppKit extension NSWindow { func setStyleMask() { titlebarAppearsTransparent = true titleVisibility = .hidden backgroundColor = .gray styleMask.remove(.resizable) } func setPosition(_ position: Position, in screen: NSScreen?) { setStyleMask() guard let visibleFrame = (screen ?? self.screen)?.visibleFrame else { return } let origin = position.value(forWindow: frame, inScreen: visibleFrame) let myRect = CGRect(x: origin.x, y: origin.y, width: 800.0, height: 800.0) setFrame(myRect, display: true) } // end function set position struct Position { static let defaultPadding: CGFloat = 16 var vertical: Vertical var horizontal: Horizontal var padding = Self.defaultPadding enum Horizontal { case left, center, right } enum Vertical { case top, center, bottom } func value(forWindow windowRect: CGRect, inScreen screenRect: CGRect) -> CGPoint { let xPosition = horizontal.valueFor(screenRange: screenRect.minX..<screenRect.maxX, width: windowRect.width, padding: padding) let yPosition = vertical.valueFor(screenRange: screenRect.minY..<screenRect.maxY, height: windowRect.height, padding: padding) return CGPoint(x: xPosition, y: yPosition) } } // end structure Position } extension NSWindow.Position.Horizontal { func valueFor(screenRange: Range<CGFloat>, width: CGFloat, padding: CGFloat) -> CGFloat { switch self { case .left: return screenRange.lowerBound + padding case .center: return (screenRange.upperBound + screenRange.lowerBound - width) / 2 case .right: return screenRange.upperBound - width - padding } } } extension NSWindow.Position.Vertical { func valueFor(screenRange: Range<CGFloat>, height: CGFloat, padding: CGFloat) -> CGFloat { switch self { case .top: return screenRange.upperBound - height - padding case .center: return (screenRange.upperBound + screenRange.lowerBound - height) / 2 case .bottom: return screenRange.lowerBound + padding } } } struct HostingWindowFinder: NSViewRepresentable { var callback: (NSWindow?) -> () func makeNSView(context: Self.Context) -> NSView { let view = NSView() DispatchQueue.main.async { self.callback(view.window) } return view } func updateNSView(_ nsView: NSView, context: Context) { DispatchQueue.main.async { self.callback(nsView.window) } } } private struct WindowPositionModifier: ViewModifier { let position: NSWindow.Position let screen: NSScreen? func body(content: Content) -> some View { content .background(HostingWindowFinder { $0?.setPosition(position, in: screen) } ) } } extension View { func hostingWindowPosition(vertical: NSWindow.Position.Vertical, horizontal: NSWindow.Position.Horizontal, padding: CGFloat = NSWindow.Position.defaultPadding, screen: NSScreen? = nil) -> some View { modifier( WindowPositionModifier( position: NSWindow.Position(vertical: vertical, horizontal: horizontal, padding: padding), screen: screen ) ) } }
Mar ’23
Reply to Swift: Create a range of angles around a circle between 235 and 35
After some thought I realized I could use an array instead of a range. I created a function that that filters out the unwanted angles and returns the filtered array. I then use array.randomElement() to get a random angle with in the range desired. let localRange = RemoveAngles(start: 36, end: 234) randomAngle = localRange.randomElement()! func RemoveAngles(start: Int, end: Int) -> Array<Int> { let fullRange: ClosedRange<Int> = 0...360 let filteredRange = fullRange.filter { $0 < start || $0 > end } return filteredRange }
Mar ’23
Reply to SwiftUI - Accessing StateObject's Object Without Being Installed on a View
Thank you MobileTen. I needed to use async and await. Below are the main call, view model and data table structure that work. @main struct NavigationStackApp: App { let coreDataManager = CoreDataManager() var body: some Scene { WindowGroup { ContentView(fetchedCoreData: FetchCoreData(persistentContainer: coreDataManager.persistentContainer)) } } } class FetchCoreData: ObservableObject { @Published var closingValues: [TradingDayPrices] = [] private (set) var persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer Task { closingValues = await FetchResults(moc: persistentContainer.viewContext) } } } func FetchResults(moc: NSManagedObjectContext) async -> [TradingDayPrices] { var coreDataValues: [TradingDayPrices] = [] let fetchRequest : NSFetchRequest<TradingDayPrices> = TradingDayPrices.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: true)] fetchRequest.predicate = NSPredicate(format: "netWorth > %d", 0.0) do { coreDataValues = try moc.fetch(fetchRequest) } catch let error { print("Error fetching max date. \(error.localizedDescription)") } return coreDataValues } struct DataTable: View { var closingValues: [TradingDayPrices] = [] init(closingValues: [TradingDayPrices]) { self.closingValues = closingValues } var body: some View { List(closingValues, id: \.self) { item in Text("\(dateToStringFormatter.string(from: item.timeStamp!)) - ") + Text("\(item.vooClose) ") } } }
Apr ’23
Reply to Swift - Map two elements from an array to a new array
I did not properly set up my closingValues variable to be an array, which is what I wanted. In addition, I went with a for loop to populate the closingValues array instead of the map functionality. The code below works. Thank you for your assistance DMG. struct FundValues: Identifiable { var timeStamp: Date var close: Double var id = UUID() } struct DataTable: View { var allClosingValues: [TradingDayPrices] var closingValues: Array<FundValues> = Array() var selection: DataDisplayed init(selection: DataDisplayed, allClosingValues: [TradingDayPrices]) { self.selection = selection self.allClosingValues = allClosingValues switch selection { case .VFIAXDT: for value in allClosingValues { closingValues.append(FundValues(timeStamp: value.timeStamp!, close: value.vfiaxClose)) } case .PrinDT: for value in allClosingValues { closingValues.append(FundValues(timeStamp: value.timeStamp!, close: value.prinClose)) } case .VOODT: for value in allClosingValues { closingValues.append(FundValues(timeStamp: value.timeStamp!, close: value.vooClose)) } default: closingValues = Array() } } var body: some View { Table(closingValues) { TableColumn("Date") { value in Text(dateToStringFormatter.string(from: value.timeStamp)) } TableColumn("Closing Value") { value in Text(currencyFormatter.string(from: value.close as NSNumber)!) } } } }
Apr ’23
Reply to Swift - access attribute in array of core data entities in a table column via a variable
I went about solving the problem a little differently. After fetching the core data into an array, I use the map functionality to generate arrays based the structure below, all in the view model. I can then make the Data Table structure generic, i.e. work with any array of objects based on the structure. Works. struct ClosingValue: Identifiable { var timeStamp: Date var close: Double var id = UUID() } // partial code in my view model. tempValues is array of objects based on structure above. tempValues = closingValues.map { tempEntity = ClosingValue(timeStamp: $0.timeStamp!, close: $0.s1Close) } return tempEntity } // Data Table structure struct DataTable: View { var closingValues: Array<ClosingValue> var heading: String init(closingValues: Array<ClosingValue> , heading: String) { self.closingValues = closingValues self.heading = heading } var body: some View { Text(heading) .foregroundColor(.black) .font(Font.custom("Arial", size: 18)) .bold() .padding(.top, 10) Table (closingValues) { TableColumn("Date") { value in HStack { Spacer() Text(dateToStringFormatter.string(from: value.timeStamp)) Spacer() } } .width(100) TableColumn("ClosingValue") { value in HStack { Spacer() Text(String(format: "$ %.2f", value.close)) Spacer() } } .width(100) } .foregroundColor(.black) .font(Font.custom("Arial", size: 16)) .frame(width: 250) Spacer() .frame(height: 30) } }
Apr ’23
Reply to How do I animate a Swift line mark chart
It works. My memory was wrong on assigning values to a @State variable in the init but after some research I corrected my error. Below is the updated view. Thank you for your input. struct ClosingValuesChart: View { @State private var selectedDate: Date? = nil @State private var selectedClose: Float? = nil @State private var xAxisLabels: [Date] = [] var closingValues: [TradingDayClose] var heading: String = "" var renderRate: Double @State var showData: [Bool] init(fundName: String, numYears: Int, closingValues: [TradingDayClose], renderRate: Double) { self.heading = fundName + String(" - \(numYears) Year") self.closingValues = closingValues _showData = State(initialValue: Array(repeating: false, count: closingValues.count)) self.renderRate = renderRate } var body: some View { GroupBox (heading) { let xMin = closingValues.first?.timeStamp let xMax = closingValues.last?.timeStamp let yMin = closingValues.map { $0.close }.min()! let yMax = closingValues.map { $0.close }.max()! let xAxisLabels: [Date] = GetXAxisLabels(xMin: xMin!, xMax: xMax!) var yAxisLabels: [Float] { stride(from: yMin, to: yMax + ((yMax - yMin)/7), by: (yMax - yMin) / 7).map { $0 } } Chart { ForEach(Array(closingValues.enumerated()), id: \.offset ) { (index, value) in if showData[index] { LineMark( x: .value("Time", value.timeStamp!), y: .value("Closing Value", value.close) ) .foregroundStyle(Color.blue) .lineStyle(StrokeStyle(lineWidth: 1.25)) } } } .onAppear { for i in 0...closingValues.count - 1 { DispatchQueue.main.asyncAfter(deadline: .now() + renderRate * Double(i)) { showData[i] = true } } } .chartXScale(domain: xMin!...xMax!) .chartXAxisLabel(position: .bottom, alignment: .center, spacing: 25) { Text("Date") .textFormatting(fontSize: 14) } .chartXAxis { AxisMarks(position: .bottom, values: xAxisLabels) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) AxisValueLabel(anchor: .top) { if value.as(Date.self) != nil { Text("") } } } } .chartYScale(domain: yMin...yMax) .chartYAxisLabel(position: .leading, alignment: .center, spacing: 25) { Text("Closing Value") .font(Font.custom("Arial", size: 14)) .foregroundColor(.black) } .chartYAxis { AxisMarks(position: .leading, values: yAxisLabels) { value in AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1)) AxisValueLabel() { if let labelValue = value.as(Double.self) { Text(String(format: "$ %.2f", labelValue)) .textFormatting(fontSize: 12) } } } } .chartOverlay { proxy in GeometryReader { geometry in ChartOverlayRectangle(selectedDate: $selectedDate, selectedClose: $selectedClose, proxy: proxy, geometry: geometry, xMin: xMin!, xMax: xMax!, closingValues: closingValues) } } .overlay { XAxisDates(dateLabels: xAxisLabels) } .overlay { DateAndClosingValue(selectedDate: selectedDate ?? Date(), selectedClose: selectedClose ?? 0.0) } } .groupBoxStyle(ChartGroupBoxStyle()) } }
Jun ’23