SwiftUI foreground/background order with .primary - swiftui

Given this View definition:
struct ContentView: View {
var body: some View {
VStack {
Text("yellow on black")
.foregroundColor(.yellow)
.background(.black)
Text("yellow on black")
.background(.black)
.foregroundColor(.yellow)
Text("yellow on black")
.foregroundColor(.yellow)
.background(.primary)
Text("yellow on black")
.background(.primary)
.foregroundColor(.yellow)
}
}
}
And this result:
Can anyone explain why the last Text is yellow on yellow?

Related

How to have only one Navigation Link at a time

I created a program that helped me understand the basics of navigation links which I am still learning. I was wondering how I would get rid of the navigation links stacking on top of each other.
import SwiftUI
struct RedOneView: View {
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: .red, number: 1)
.navigationTitle("Red one")
.offset(y: -60)
NavigationLink(destination: BlueTwoView(color: .orange), label: {
Text("Blue View")
.bold()
.frame(width: 200, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
})
}
}
}
struct CircleViewNumber: View{
var color: Color
var number: Int
var body: some View{
ZStack{
Circle()
.frame(width: 200, height: 200)
.foregroundColor(color)
Text("\(number)")
.foregroundColor(.white)
.font(.system(size: 70, weight: .bold))
}
}
}
struct test: View{
var number: Int
var body: some View{
ZStack{
Circle()
.scale(1.5)
.foregroundColor(.blue)
Text("\(number)")
}
}
}
struct BlueTwoView: View {
var color: Color
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: color, number: 2)
.navigationTitle("Blue two")
.offset(y: -60)
NavigationLink(destination: GreenThreeView(), label: {
Text("Next Screen")
})
}
}
}
}
struct GreenThreeView: View {
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: .green, number: 2)
.navigationTitle("Green three")
.offset(y: -60)
NavigationLink(destination: test(number: 5), label: {
Text("Next Screen")
})
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
RedOneView()
}
}
}
So how would I go about getting rid of navigation link so that in you cannot just skip to the very first link (red one) but instead there is one button and you must go each screen individually.
You should use only one NavigationView in your navigation stack. So you have to get rid of nested NavigationView's in your components. You can simply delete NavigationView everywhere except RedOneView.
But I suggest creating RootView component with NavigationView and get rid of NavigationView in all child components
struct RootView: View {
var body: some View {
NavigationView {
RedOneView()
}
}
}
struct RedOneView: View {
var body: some View {
VStack {
CircleViewNumber(color: .red, number: 1)
.navigationTitle("Red one")
.offset(y: -60)
NavigationLink(destination: BlueTwoView(color: .orange), label: {
Text("Blue View")
.bold()
.frame(width: 200, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
})
}
}
struct BlueTwoView: View {
var color: Color
var body: some View {
VStack {
CircleViewNumber(color: color, number: 2)
.navigationTitle("Blue two")
.offset(y: -60)
NavigationLink(destination: GreenThreeView(), label: {
Text("Next Screen")
})
}
}
}
//...

SwiftUI - Sheet doesn't work in Navigation View

Having issues with a NavigationView and Sheet.
I want to use not full-size sheet but bottom sheet and connect LoginView() and SignView() through sheet. At this time, frame of SignView never follow sheet.
So I tried two ways to solve.
First, LoginView: Has NavigationView out of the sheet and NavigationLink in sheet . But it didn't work.
So I put NavigationView in sheet, it works. But the height of the destination View becomes like sheet.
How can I solve the problem proper way? Thanks!
import SwiftUI
struct LoginView:View{
#State var isPlus : Bool = false
var body: some View{
NavigationView{
VStack(alignment:.center){
Spacer()
ZStack{
Button(action:{
self.isPlus = true})
{
Text("Sign up")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.fontWeight(.heavy)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $isPlus){
VStack{
NavigationLink(destination:SignView()){
Text("MyCard")
.font(.title)
.foregroundColor(Color.black)
}
}
.presentationDetents([.height(300)])
}
}
}
}
}
}
Hope you can get solution from the below code snippet.
By this way we can use sheet in the NavigationView.
struct LoginView: View {
#State var isPlus : Bool = false
#State private var showingSheet = false
var body: some View {
NavigationView {
VStack(alignment:.center) {
Spacer()
ZStack{
Button(action:{
self.isPlus = true})
{
Text("First Sheet View")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $isPlus){
VStack{
NavigationView {
NavigationLink(destination:SignView()){
Button(action:{
self.showingSheet = true})
{
Text("Full Sheet View")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $showingSheet){
Button("Close"){
showingSheet = false
isPlus = false
}
.presentationDetents([.large])
}
}
}
.presentationDetents([.medium])
.edgesIgnoringSafeArea(.all)
}
}
}
}
}
}
}

SwiftUI list row layout

Back with a couple of SwiftUI layout questions :
I'm trying to display 2 lists side by side with custom cells.
I created the cell views (EventRow.swift) and I display them in my content view.
I added a border to my lists, for better visibility.
As you can see from the picture below, the result is ghastly:
I would like the gradient effect to be applied to the whole cell, width and height wise.
I tried setting the frame of my EventRow (using .infinity for width and height), but this crashes the app.
Since the size of EventRow is inferred, I also don't know how to adapt my row cells height to its size : you can see the horizontal delimitating bars are not fitted to my custom EventRow...
If anyone has some pointers for this, it would be greatly appreciated.
The sample project can be found here
But I also post my code below:
ContentView :
import SwiftUI
struct ContentView: View {
struct listsSetup: ViewModifier {
func body(content: Content) -> some View {
return content
.frame(maxHeight: UIScreen.main.bounds.size.height/3)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))
.padding([.top, .bottom])
}
}
var body: some View {
VStack {
HStack {
VStack { // 1 list Vstack
VStack {
Text("List 1")
.padding(.top)
List {
EventRow()
EventRow()
} // END of 1st List
}
.modifier(listsSetup())
} // END of 1st list VStack
VStack { // 2nd Vstack
VStack {
Text("List 2")
.padding(.top)
List {
EventRow()
EventRow()
} // END of Landings List
}
.modifier(listsSetup())
} // End of 2nd List VStack
} // End of 1st & 2nd lists HStack
.padding(.top)
Spacer()
} // END of VStack
} // END of body
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
EventRow :
import SwiftUI
struct EventRow: View {
var body: some View {
LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
.edgesIgnoringSafeArea(.all)
.overlay(
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
)
}
}
struct EventRow_Previews: PreviewProvider {
static var previews: some View {
EventRow().previewLayout(.fixed(width: 300, height: 60))
}
}
Edit after trying Asperi's solution :
My actual EventRow code is as follows, and the listRowBackground modifier doesn't seem to have any effect :
import SwiftUI
import CoreData
struct EventRow: View {
var event: Events
var dateFormatter: DateFormatter {
let formatter = DateFormatter()
// formatter.dateStyle = .long
formatter.dateFormat = "dd MMM yy"
return formatter
}
var body: some View {
VStack{
HStack {
Text(event.airportName ?? "")
.font(.headline)
Spacer()
Text(self.dateFormatter.string(from: event.eventDate!))
.font(.body)
}
HStack {
Text(event.flightNumber ?? "")
.font(.body)
Spacer()
if event.isSimulator {
Image(systemName: "s.circle")
.font(.body)
} else {
Image(systemName: "airplane")
.font(.body
)
}
Spacer()
if event.aircraftType == 0 {
Text("")
.font(.body)
} else if event.aircraftType == 1 {
Text("330")
.font(.body)
} else if event.aircraftType == 2 {
Text("350")
.font(.body)
}
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom))
}
}
struct EventRow_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newEvent = Events(context: context)
newEvent.eventDate = Date()
newEvent.aircraftType = 1
newEvent.airportName = "LDG tst"
newEvent.flightNumber = "AF TEST"
newEvent.id = UUID()
newEvent.isLanding = true
newEvent.isSimulator = false
return EventRow(event: newEvent).environment(\.managedObjectContext, context)
.previewLayout(.fixed(width: 300, height: 60))
}
}
Here is a solution to make gradient row-wide
struct EventRow: View {
var body: some View {
VStack{
HStack {
Text("Text one")
Spacer()
Text("Text two")
}
HStack {
Spacer()
Image(systemName: "flame")
.font(.body)
Spacer()
} // END of second HStack
.padding(.top, -14)
} //END of Vstack
.listRowBackground(LinearGradient(gradient: Gradient(colors: [Color.white, Color.blue]), startPoint: .top, endPoint: .bottom)
)
}
}

SwiftUI: animating between Single and HStack views

Goal:
1- Shows a view (Blue) that covers entire screen
2- When tapped on bottom (top right corner), it shows an HStack animating right side HStack (Green) "Slide Offset animation".
import SwiftUI
struct ContentView: View {
#State var showgreen = false
var body: some View {
NavigationView {
HStack {
Rectangle()
.foregroundColor(.blue)
if showgreen {
Rectangle()
.foregroundColor(.green)
.offset(x: showgreen ? 0 : UIScreen.main.bounds.width)
.animation(.easeInOut)
}
}
.navigationBarItems(trailing:
Button(action: { self.showgreen.toggle() }) {
Image(systemName: "ellipsis")
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.colorScheme(.dark)
.previewDevice("iPad Pro (12.9-inch) (3rd generation)")
}
}
The code works, however I cannot get the Green "Slide Offset animation" to work. Really appreciate any help! : )
Instead of using the if conditional, you need the green rectangle to be already present, and just offscreen. When showgreen toggles, you need to shrink the size of the blue rectangle, which will make room for the green rectangle.
struct ContentView: View {
#State var showgreen = false
var body: some View {
NavigationView {
HStack {
Rectangle()
.foregroundColor(.blue)
.frame(width: showgreen ? UIScreen.main.bounds.width / 2 : UIScreen.main.bounds.width)
.animation(.easeInOut)
Rectangle()
.foregroundColor(.green)
.animation(.easeInOut)
}
.navigationBarItems(trailing:
Button(action: { self.showgreen.toggle() }) {
Image(systemName: "ellipsis")
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

How to remove List selection indicator and separator in SwiftUI?

I code a List in a ScrollView, when I selected a List cell to translate to another view and return back, the cell selected indicator did not disappear after selecting.
I hope after selected the list cell, the selected indicator should be disappear.
I debugged, I found that the ScrollView has some problems when it worked with List.If no ScrollView, the list selection behavior is all right, if plus the ScrollView outside the list, the problem become.
The other problem is How to remove the List Separator.
Thank you for your help!!!
#State var valueData: [String] = ["Apple", "Pear", "Orange", "Cake"]
var body: some View {
NavigationView {
ScrollView(.vertical) {
VStack(spacing: 10) {
DietListView(valueData: self.$valueData)
DietListView(valueData: self.$valueData)
.padding()
}
}
.frame(width: 352)
}
}
struct DietListView: View {
#Binding var valueData: [String]
var body: some View {
VStack {
List {
ForEach(self.valueData, id: \.self) { item in
NavigationLink(destination: DietItemDetailView()) {
HStack {
Text(item)
Spacer()
Text("100")
}
}
}
.onDelete { index in
self.valueData.remove(at: index.first!)
}
}
.frame(height: 300)
}
.frame(width: 352, height: 350)
.background(Color.white)
.cornerRadius(16)
.shadow(radius: 10)
}
}
the problem just like this:
At the moment (SwiftUI Beta 5) you can't customise List very much changing, for example, the divider style. What you can do, depending on your needs, is to use a ScrollView with ForEach and give the cell the style you want. For example:
struct ContentView: View {
#State var valueData: [String] = ["Apple", "Pear", "Orange", "Cake"]
var body: some View {
NavigationView {
ScrollView(.vertical) {
VStack(spacing: 10) {
DietListView(valueData: self.$valueData)
DietListView(valueData: self.$valueData)
.padding()
}
}
.frame(width: 352)
}
}
}
struct DietListView: View {
#Binding var valueData: [String]
var body: some View {
VStack {
ScrollView {
ForEach(self.valueData, id: \.self) { item in
NavigationLink(destination: Text("ciao")) {
HStack {
Text(item)
Spacer()
Text("100")
}
.foregroundColor(.primary)
.padding(10)
}
}
}
.frame(height: 300)
}
.frame(width: 352, height: 350)
.background(Color.white)
.cornerRadius(16)
.shadow(radius: 10)
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Also, take a look at this: https://stackoverflow.com/a/56498261/1291872
EDIT: you can use onDelete, onMove and onInsert only within a List. If you want to let users delete a row in a ScrollView you must implement something yourself. Take a look at the code below for a simple (pretty ugly) example:
struct ContentView: View {
#State var valueData: [String] = ["Apple", "Pear", "Orange", "Cake"]
var body: some View {
NavigationView {
ScrollView(.vertical) {
VStack(spacing: 10) {
DietListView(valueData: self.$valueData)
DietListView(valueData: self.$valueData)
.padding()
}
}
.frame(width: 352)
}
}
}
struct DietListView: View {
#Binding var valueData: [String]
var body: some View {
VStack {
ScrollView {
ForEach(self.valueData.indices, id: \.self) { idx in
NavigationLink(destination: Text("ciao")) {
HStack {
Text(self.valueData[idx])
Spacer()
Text("100")
.padding(.trailing, 20)
Button(action: {
self.valueData.remove(at: idx)
}) {
Image(systemName: "xmark.circle")
.resizable()
.frame(width: 25, height: 25)
.foregroundColor(Color.red)
}
}
.foregroundColor(.primary)
.padding([.leading, .trailing], 20)
.padding([.top, .bottom], 10)
}
}
}
.frame(height: 300)
}
.frame(width: 352, height: 350)
.background(Color.white)
.cornerRadius(16)
.shadow(radius: 10)
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif