How do you format the table column headings in Swift - xcode

The following code displays a swift table with all of the correct data. But, I am unable to figure out how to format the table column headings (such as Index Funds and Shares). I would like to change the font size and center the text. Any assistance will be appreciated.
struct SummaryTable: View {
private var localArray: [TradingDayPrices]
init(passedInArray: [TradingDayPrices]) {
self.localArray = passedInArray
}
var body: some View {
let funds: [Fund] = GetSummaryTable(localArray: localArray)
Table(funds) {
TableColumn("Index Fund") { value in
Text(value.name)
.padding(.vertical, 2)
}
.width(90)
TableColumn("Shares") { value in
HStack {
Spacer()
Text(value.shares)
Spacer()
}
}
.width(90)
TableColumn("Share Price") { value in
HStack {
Spacer()
Text(value.sharePrice)
Spacer()
}
}
.width(90)
TableColumn("Total") { value in
HStack {
Spacer()
Text(value.total)
}
}
.width(110)
TableColumn("One Year Gain") { value in
HStack {
Spacer()
Text(value.percentChange)
Spacer()
}
}
.width(90)
} // end table
.tableStyle(.inset(alternatesRowBackgrounds: true))
.padding([.leading, .trailing], 185)
.padding([.top], 30)
.padding([.bottom], 700)
}
}

Related

Progress View doesn't show on second + load when trying to do pagination SwiftUI

Progress View doesn't show on second + load when trying to do pagination. When I scroll to the bottom the progress view will appear once. But all the other times it doesn't. This only seems to occur when im using some sort of animation.
If I just have a static text like "Loading..." it works as expected. I added the section group where it checks a condition to verify if it should be presented or not. Not sure if I'm supposed to use something like "stop animating" like the loading indicator has in UIKit
struct ContentView: View {
#State var movies: [Movie] = []
#State var currentPage = 1
#State private var isLoading = false
var body: some View {
NavigationView {
List {
Section {
} header: {
Text("Top Movies")
}
ForEach(movies) { movie in
HStack(spacing: 8) {
AsyncImage(url: movie.posterURL, scale: 5) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
.cornerRadius(10)
} placeholder: {
ProgressView()
.frame(width: 100)
}
VStack(alignment: .leading, spacing: 10) {
Text(movie.title)
.font(.headline)
Text(movie.overview)
.lineLimit(5)
.font(.subheadline)
Spacer()
}
.padding(.top, 10)
}
.onAppear {
Task {
//Implementing infinite scroll
if movie == movies.last {
isLoading = true
currentPage += 1
movies += await loadMovies(page: currentPage)
isLoading = false
}
}
}
}
Section {
} footer: {
if isLoading {
HStack {
Spacer()
ProgressView()
.tint(.green)
Spacer()
}
} else {
EmptyView()
}
}
}
.navigationTitle("Movies")
.navigationBarTitleDisplayMode(.inline)
.listStyle(.grouped)
.task {
movies = await loadMovies()
}
.refreshable {
movies = await loadMovies()
}
}
}
}
even when I look at the view hierarchy its like the progress view square is there but the icon / loading indicator isn't showing:
If I add the overlay modifier it works but I don't like doing this because when I scroll back up before the content finishes loading the spinner is above the list view:?
.overlay(alignment: .bottom, content: {
if isLoading {
HStack {
Spacer()
ProgressView()
.tint(.green)
Spacer()
}
} else {
EmptyView()
}
})
We also had this problem, we think it is a bug of ProgressView. Our temporary correction is to identify the ProgressView with a unique id in order to render it again.
struct ContentView: View {
#State var id = 0
var body: some View {
ProgressView()
.id(id)
.onAppear {
...
id += 1
}
}
}

SwiftUI - How to animate components corresponding to array elements?

I have an HStack of circles in SwiftUI, and the number of circles is determined based on the length of an array, like this:
#State var myArr = [...]
...
ScrollView(.horizontal) {
HStack {
ForEach(myArr) { item in
Circle()
//.frame(...)
//.animation(...) I tried this, it didn't work
}
}
}
Then I have a button that appends an element to this array, effectively adding a circle to the view:
Button {
myArr.append(...)
} label: {
...
}
The button works as intended, however, the new circle that is added to the view appears very abruptly, and seems choppy. How can I animate this in any way? Perhaps it slides in from the side, or grows from a very small circle to its normal size.
You are missing transition, here is what you looking:
struct ContentView: View {
#State private var array: [Int] = Array(0...2)
var body: some View {
ScrollView(.horizontal) {
HStack {
ForEach(array, id:\.self) { item in
Circle()
.frame(width: 50, height: 50)
.transition(AnyTransition.scale)
}
}
}
.animation(.default, value: array.count)
Button("add new circle") {
array.append(array.count)
}
Button("remove a circle") {
if array.count > 0 {
array.remove(at: array.count - 1)
}
}
}
}
a version with automatic scroll to the last circle:
struct myItem: Identifiable, Equatable {
let id = UUID()
var size: CGFloat
}
struct ContentView: View {
#State private var myArr: [myItem] = [
myItem(size: 10),
myItem(size: 40),
myItem(size: 30)
]
var body: some View {
ScrollViewReader { scrollProxy in
VStack(alignment: .leading) {
Spacer()
ScrollView(.horizontal) {
HStack {
ForEach(myArr) { item in
Circle()
.id(item.id)
.frame(width: item.size, height: item.size)
.transition(.scale)
}
}
}
.animation(.easeInOut(duration: 1), value: myArr)
Spacer()
Button("Add One") {
let new = myItem(size: CGFloat.random(in: 10...100))
myArr.append(new)
}
.onChange(of: myArr) { _ in
withAnimation {
scrollProxy.scrollTo(myArr.last!.id, anchor: .trailing)
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
.padding()
}
}
}

macOS SwiftUI Table with contextMenu

Using SwiftUI's new Table container, how can I add a context menu that appears when Control-clicking a row?
I can add the contextMenu modifier to the content of the TableColumn, but then I will have to add it to each individual column. And it only works above the specific text, not on the entire row:
I tried adding the modifier to the TableColumn itself, but it shows a compile error:
Value of type 'TableColumn<RowValue, Never, Text, Text>' has no member 'contextMenu'
Here's what I have in terms of source code, with the contextMenu modifier in the content of the TableColumn:
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Item.name, ascending: true)])
private var items: FetchedResults<Item>
#State
private var sortOrder = [KeyPathComparator(\Item.name)]
#State
private var selection = Set<Item.ID>()
var body: some View {
NavigationView {
Table(items, selection: $selection, sortOrder: $items.sortDescriptors) {
TableColumn("Column 1") {
Text("Item at \($0.name!)")
.contextMenu {
Button(action: {}) { Text("Action 1") }
Divider()
Button(action: {}) { Text("Action 2") }
Button(action: {}) { Text("Action 3") }
}
}
TableColumn("Column 2") {
Text($0.id.debugDescription)
}
}
.toolbar {
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
if selection.isEmpty {
Text("Select an item")
} else if selection.count == 1 {
Text("Selected \(items.first(where: { $0.id == selection.first! })!.id.debugDescription)")
} else {
Text("Selected \(selection.count)")
}
}
}
}
So, how can I add a context menu to the entire row inside the Table?
You can make cell view with the following extensions and use it for each column cell, then it will be clickable in any row place
Text("Item at \($0.name!)")
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) // << this !!
.contentShape(Rectangle()) // << this !!
.contextMenu {
Button(action: {}) { Text("Action 1") }
Divider()
Button(action: {}) { Text("Action 2") }
Button(action: {}) { Text("Action 3") }
}

How do I switch between screens in TabView and from the latter to the other View?

I created a simple collection with a button jump to the next View. From the last View there should be a transition to AddItemView, but it doesn't happen - it goes back to the first screen.
Can you tell me where I made a mistake?
What is the correct way to place the background Image on the first collection screen, so that it won't be on the following screens?
import SwiftUI
struct AddItemView: View {
var body: some View {
Text("Hallo!")
}
}
struct ContentView: View {
var colors: [Color] = [ .orange, .green, .yellow, .pink, .purple ]
var emojis: [String] = [ "👻", "🐱", "🦊" , "👺", "🎃"]
#State private var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
ForEach(0..<emojis.endIndex) { index in
VStack {
Text(emojis[index])
.font(.system(size: 150))
.frame(minWidth: 30, maxWidth: .infinity, minHeight: 0, maxHeight: 250)
.background(colors[index])
.clipShape(RoundedRectangle(cornerRadius: 30))
.padding()
.tabItem {
Text(emojis[index])
}
Button(action: {
self.tabSelection += 1
}) {
if tabSelection == emojis.endIndex {
NavigationLink(destination: AddItemView()) {
Text("Open View")
}
} else {
Text("Change to next tab")
}
}
}
}
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.tabViewStyle(PageTabViewStyle.init(indexDisplayMode: .never))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
In this code, you have not to use NavigationView. It's required to navigate to the next screen. Similar concept like Push view controller if navigation controller exists. Also, remove endIndex and use indices.
struct ContentView: View {
var colors: [Color] = [ .orange, .green, .yellow, .pink, .purple ]
var emojis: [String] = [ "👻", "🐱", "🦊" , "👺", "🎃"]
#State private var tabSelection = 0
var body: some View {
NavigationView { //<- add navigation view
TabView(selection: $tabSelection) {
ForEach(emojis.indices) { index in //<-- use indices
VStack {
Text(emojis[index])
.font(.system(size: 150))
.frame(minWidth: 30, maxWidth: .infinity, minHeight: 0, maxHeight: 250)
.background(colors[index])
.clipShape(RoundedRectangle(cornerRadius: 30))
.padding()
.tabItem {
Text(emojis[index])
}
Button(action: {
self.tabSelection += 1
}) {
if tabSelection == emojis.count - 1 { //<- use count
NavigationLink(destination: AddItemView()) {
Text("Open View")
}
} else {
Text("Change to next tab")
}
}
}
}
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.tabViewStyle(PageTabViewStyle.init(indexDisplayMode: .never))
}
}
}
If you have already a navigation link from the previous screen then, the problem is you are using endIndex in the wrong way. Check this thread for correct use (https://stackoverflow.com/a/36683863/14733292).

MacOS-style List with Plus and Minus buttons

How can I do something like that in SwiftUI?
Reckon this view is built in Cocoa, since I can't even layout List and GroupBox properly: strange border appears.
There is no Table view in SwiftUI, there is no NSSegmentedControl.
This is the code I got so far:
import SwiftUI
struct DetailView: View {
let text: String
var body: some View {
GroupBox {
Text(text)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.padding(.leading, 20)
.frame(width:300, height:300)
}
}
struct ContentView: View {
private let names = ["One", "Two", "Three"]
#State private var selection: String? = "One"
var body: some View {
NavigationView {
List(selection: $selection) {
Section(header:
Text("Header")) {
ForEach(names, id: \.self) { name in
NavigationLink(destination: DetailView(text: name)) {
Text(name)
}
}
}
}.frame(width: 200, height: 300).padding(10).border(Color.green, width: 0)
DetailView(text: self.selection ?? "none selected")
}.padding(10)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
import AppKit
struct ContentView: View {
var body: some View {
HStack(spacing: 20) {
PrinterPicker()
.frame(width: 160)
PrinterDetail()
.frame(width: 320)
} //
.padding()
}
}
struct PrinterPicker: View {
var body: some View {
VStack(spacing: 0) {
PrinterList()
PrinterListToolbar()
} //
.border(Color(NSColor.gridColor), width: 1)
}
}
struct PrinterList: View {
var body: some View {
List {
Text("Printer 1")
.font(Font.system(size: 15))
Text("Printer 2")
.font(Font.system(size: 15))
}
}
}
struct PrinterListToolbar: View {
var body: some View {
HStack(spacing: 0) {
ListButton(imageName: NSImage.addTemplateName)
Divider()
ListButton(imageName: NSImage.removeTemplateName)
Divider()
Spacer()
} //
.frame(height: 20)
}
}
struct ListButton: View {
var imageName: String
var body: some View {
Button(action: {}) {
Image(nsImage: NSImage(named: imageName)!)
.resizable()
} //
.buttonStyle(BorderlessButtonStyle())
.frame(width: 20, height: 20)
}
}
struct PrinterDetail: View {
var body: some View {
HStack {
Spacer()
VStack {
Spacer()
Text("No printers are available.")
Text("Click Add (+) to set up a printer.")
Spacer()
}
Spacer()
} //
.font(Font.system(size: 15))
.background(Color(
NSColor.unemphasizedSelectedContentBackgroundColor))
.cornerRadius(6)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(lineWidth: 1)
.foregroundColor(Color(NSColor.gridColor)))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Resources