I have a program that creates a custom table view. In the delegate that populates the cells with data I create an instance of a custom NSTableCellView. It works. What I would like to be able to do is pass in a value when making an instance so that I can set the width of the frame (var rectWidth in the custom NSTableCellView). I am currently using two different custom NSTableCellViews, each with a different value for var rectWidth. Below is my delegate and custom NSTableCellView code.
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if (tableColumn?.identifier)!.rawValue == "fund" {
let dataCell = CustomTableCellView()
dataCell.textField?.stringValue = closingValues[row].fundName
return dataCell
} else if (tableColumn?.identifier)!.rawValue == "date" {
let dataCell = CustomTableCellViewDate()
dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
return dataCell
} else {
let dataCell = CustomTableCellView()
dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
return dataCell
}
}
class CustomTableCellView: NSTableCellView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
let rectWidth: CGFloat = 100
self.autoresizingMask = .width
let nsRectangle = NSMakeRect(0, 0, rectWidth, 24)
let customTextField: NSTextField = CustomTextField(frame: nsRectangle)
self.textField = customTextField
self.addSubview(customTextField)
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am creating a user interface for a working program. I am able to lay things out with offsets but am trying as a learning experience to do the same with alignment guides. For the section heading labeled "Group 1" I am able to get the layout I want. What I cannot get to work are alignment guides for the associated rounded rectangle. It appears that the alignment guides with the rounded rectangle only affect the contents i.e. the text "Data Table". Below is a picture of the code output and the code. How, using alignment guides, can move the top rounded rectangle? To keep the picture small I just copied the left side of the output window. The top rounded rectangle is approximately centered in this window.
struct ContentView: View {
var body: some View {
NavigationStack {
Text("Group1")
.font(Font.custom("Arial", size: 16))
.alignmentGuide(HorizontalAlignment.center, computeValue: { d in
print("\(d[HorizontalAlignment.leading])")
// print leading = 0.0
// print center = 27
// print trailing = 54
return d[HorizontalAlignment.leading] + 255
})
ZStack (alignment: Alignment(horizontal: .center, vertical: .center)) {
RoundedRectangle(cornerRadius: 10)
.fill(.white)
.alignmentGuide(HorizontalAlignment.center, computeValue: { d in
return d[HorizontalAlignment.leading] + 45
})
VStack (alignment: HorizontalAlignment.leading) {
NavigationLink(value: "Table1") {
Text("Data Table")
}
.font(Font.custom("Arial", size: 14))
.buttonStyle(.link)
.underline()
.focusable(false)
} // end vstack
} // end zStack
.frame(width: 200, height: 60)
Text("Group2")
.font(Font.custom("Arial", size: 16))
.frame(width: 600, height: 20, alignment: .leading)
.padding(.leading, 35)
.padding(.top, 20)
.offset(x: 30)
ZStack {
RoundedRectangle(cornerSize: CGSize(width: 200, height: 60))
.stroke(Color(.clear), lineWidth: 1)
.frame(width: 200, height: 60, alignment: .leading)
.background(.white)
.cornerRadius(10)
.offset(x: -160)
VStack () {
NavigationLink(value: "Table2") {
Text("Data Table")
}
.font(Font.custom("Arial", size: 14))
.buttonStyle(.link)
.underline()
.padding(.leading, 8)
.frame(width: 200, height: 20, alignment: .leading)
.offset(x: -160)
.focusable(false)
}
}
Text("Group3")
.font(Font.custom("Arial", size: 16))
.frame(width: 600, height: 20, alignment: .leading)
.padding(.leading, 35)
.padding(.top, 20)
.offset(x: 30)
ZStack {
RoundedRectangle(cornerSize: CGSize(width: 200, height: 60))
.stroke(Color(.clear), lineWidth: 1)
.frame(width: 200, height: 60, alignment: .leading)
.background(.white)
.cornerRadius(10)
.offset(x: -160)
VStack () {
NavigationLink(value: "Table3") {
Text("Data Table")
}
.font(Font.custom("Arial", size: 14))
.buttonStyle(.link)
.underline()
.padding(.leading, 8)
.frame(width: 200, height: 20, alignment: .leading)
.offset(x: -160)
.focusable(false)
}
}
.padding(.bottom, 20)
.navigationDestination(for: String.self) { command in
switch command {
case "Table1":
HStack {
CustomTableView(fundName: "Table1", numYears: 1)
.frame(width: 320, height: 345, alignment: .center)
.padding(.leading, 120)
.padding(.trailing, 160)
}
case "Table2":
HStack {
CustomTableView(fundName: "Table2", numYears: 1)
.frame(width: 320, height: 345, alignment: .center)
.padding(.leading, 120)
.padding(.trailing, 160)
}
case "Table3":
HStack {
CustomTableView(fundName: "Table3", numYears: 1)
.frame(width: 320, height: 345, alignment: .center)
.padding(.leading, 120)
.padding(.trailing, 160)
}
default:
let _ = print("problem in main view switch statement")
} // end switch
} // end navigation destination
}
.frame(width: 600, height: 400, alignment: .trailing)
}
}
I have a swift program that displays a chart using Chart. The code includes an X Axis Scale parameter but for some reason the last value (right most) on the x axis does not display. It should display Aug 2023. In checking the array used for the x axis labels I find that the last value is Aug 2023. I do not know how to overcome this obstacle. Any assistance will be appreciated. Below is a picture of the bottom of the chart and the code.
struct CustomChartView: View {
let vm: SQLDataVM = SQLDataVM.shared
let closingValues: [TradingDay]
let fundName: String
let numYears: Int
let maxCloseStruct: TradingDay
let maxClose: Double
let minCloseStruct: TradingDay
let minClose: Double
let yIncrment: Double
let yAxisValues: [Double]
let minTimeStampStruct: TradingDay
let minTimeStamp: Date
var dateComponent = DateComponents()
let maxTimeStampStruct: TradingDay
let maxTimeStamp: Date
var xAxisValues: [Date] = []
init (fundName: String, numYears: Int) {
self.fundName = fundName
self.numYears = numYears
closingValues = self.vm.QueryDatabase(fundName: fundName, numYears: numYears)
maxCloseStruct = self.closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
maxClose = maxCloseStruct.close
minCloseStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
minClose = minCloseStruct.close
yIncrment = (maxClose - minClose)/4
yAxisValues = [
minClose,
minClose + (1 * yIncrment),
minClose + (2 * yIncrment),
minClose + (3 * yIncrment),
maxClose
]
minTimeStampStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
minTimeStamp = minTimeStampStruct.timeStamp
maxTimeStampStruct = closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
maxTimeStamp = maxTimeStampStruct.timeStamp
xAxisValues.append(minTimeStamp)
for i in 1...11 {
dateComponent.month = i
let nextMonth = Calendar.current.date(byAdding: dateComponent, to: minTimeStamp)
xAxisValues.append(nextMonth!)
}
xAxisValues.append(maxTimeStamp)
print("\(xAxisValues[12])") // prints 2023-08-04 00:00:00 +0000
} // end init
var body: some View {
HStack(alignment: .center) {
VStack(alignment: .center) {
Chart(closingValues, id:\.id) {
LineMark(
x: .value("Date", $0.timeStamp, unit: .day),
y: .value("Closing", $0.close)
)
.foregroundStyle(.blue)
} // end chart
.frame(width: 1000, height: 700, alignment: .center)
.chartXAxisLabel(position: .bottom, alignment: .center, spacing: 15) {
Text("Date")
.font(.custom("Arial", size: 20))
}
.chartYAxisLabel(position: .leading, alignment: .center, spacing: 20) {
Text("Closing Value")
.font(.custom("Arial", size: 20))
}
.chartXAxis {
AxisMarks(values: xAxisValues) { value in
if let date = value.as(Date.self) {
AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) {
VStack(alignment: .leading) {
Text(ChartMonthFormatter.string(from: date))
.font(.custom("Arial", size: 14))
Text(ChartYearFormatter.string(from: date))
.font(.custom("Arial", size: 14))
} // end v stack
} // end axis label
} // end if statement
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
}
} // end chart x axis
.chartXScale(domain: [xAxisValues[0], xAxisValues[12]])
.chartYAxis {
AxisMarks(position: .leading, values: yAxisValues) { value in
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
AxisValueLabel(horizontalSpacing: 10) {
if let yAxisValue = value.as(Double.self) {
let stringValue = String(format: "$%.02f", yAxisValue)
Text(stringValue)
.font(.custom("Arial", size: 14))
}
}
}
}
.chartYScale(domain: [minClose, maxClose])
.chartPlotStyle { plotArea in
plotArea.background(.white.opacity(0.9))
.border(.black, width: 1)
} // end chart plot style
} // end v stack
.frame(width: 1200, height: 900, alignment: .center)
} // end h stack
} // end some view
}
I have a program that utilizes a Navigation Stack. I want each view to be centered on the screen and be a specific size. I accomplished this with some position logic which sets the views frame size and origin. There is unique position logic for each of the 3 view sizes, the Content View and 2 navigation destination views. When the Content View is first displayed the associated position logic code runs and the view is the correct size and centered. The same is true every time one of the 2 navigation destination views is displayed. Unfortunately, when I return to the Content View from a navigation destination view the position logic does not run again and the Content View is now the same size and position as the previous navigation destination view. How do I resolve this problem? Below is the position logic code associated with the Content View and how it is called.
@main
struct TableViewTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.hostingWindowPositionHome(
screen: .main
)
}
}
}
extension View {
func hostingWindowPositionHome(
screen: NSScreen? = nil
) -> some View {
modifier(
WindowPositionModifierHome(
screen: screen
)
)
}
}
private struct WindowPositionModifierHome: ViewModifier {
let screen: NSScreen?
func body(content: Content) -> some View {
content.background(
HostingWindowFinderHome {
$0?.setPositionHome(in: screen)
}
)
}
}
private struct HostingWindowFinderHome: 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) }
}
}
extension NSWindow {
func setPositionHome(in screen: NSScreen?) {
let nsRectangle: NSRect = NSRect(x: 1055.0, y: 370.0, width: 450, height: 700)
setFrame(nsRectangle, display: true)
}
}
I have a program that uses 3 different windows, each in their own window group. In a button I can use openWindow() to call another window and it works perfectly. I watched the video at the link below and now am trying to convert my program to use a navigation stack instead of buttons. I got things to work using the code listed at the link with a few changes but am unable to get the navigation destination to use openWindow. I attempted to create a view builder but could not get it to work. After some additional research I am starting to think that the navigation destination expects to use the same window as the root view not a separate window/view and therefore, navigation destination wants just a view. But I am unsure. If someone could provide some guidance it would be appreciated.
https://developer.apple.com/videos/play/wwdc2022/10054/
struct ContentView: View {
@Environment (\.openWindow) private var openWindow
@StateObject private var dataModel = DataModel()
var body: some View {
VStack(alignment: .center) {
NavigationStack() {
List(Sections.allCases) { section in
Section(section.localizedName) {
ForEach(dataModel.stocks(in: section)) { stock in
NavigationLink(stock.listingName, value: stock)
.font(Font.custom("Arial", size: 16))
}
} // end section
} // end list
.scrollContentBackground(.hidden)
.background(Color.mint)
.navigationTitle("Stocks")
.navigationDestination(for: StockData.self) { stock in
Text("\(stock.listingName) - \(stock.name)")
// GenericTableView(content: openWindow(id: "table", value: stock.name))
// Cannot convert value of type '()' to expected argument type '() -> ContentView'
}
} // end navigation stack
} // end v stack
}
}
struct GenericTableView<Content:View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
}
}