I am getting an error when calling an image:
'(String) -> Image' is not convertible to '(String, Bundle?) -> Image'\
This error show on the line Image(specie.imageName)
This is the whole page code.
import SwiftUI
struct ForefootView : View {
#State var iconOpacity: Double = 0.5
let specie: Species
var body: some View {
NavigationView {
ZStack () {
Image("Busanga")
.resizable()
VStack (spacing: 10) {
Image(specie.imageName)
.resizable()
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
.padding(15)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
ZStack() {
Image(specie.trackSizerImage)
.resizable()
.aspectRatio(contentMode: .fit)
.opacity(iconOpacity)
Image(specie.frontTrackImage)
.resizable()
.aspectRatio(contentMode: .fit)
}
HStack {
Image(specie.trackSizerImage)
.resizable()
.frame(width: 40, height: 40, alignment: .topLeading)
.opacity(0.2)
Slider(value: $iconOpacity, from: 0.0, through: 1.0)
Image(specie.trackSizerImage)
.resizable()
.frame(width: 40, height: 40, alignment: .topTrailing)
}
.padding(20)
}
}
.navigationBarTitle(Text((specie.fullName) + " " + "FOREFOOT".localized), displayMode: .inline)
.navigationBarItems(trailing: NavigationLink(destination: NotesView(species: specie)) {
Text("Notes").color(.white)
.font(.custom("Marker Felt", size: 15))
.shadow(color:.black, radius:1, x:1, y:1)
})
}
}
}
#if DEBUG
struct ForefootView_Previews : PreviewProvider {
static var previews: some View {
ForefootView(specie: speciesData[0])
}
}
#endif
The image name Image(specie.imageName) is used on another page and is fine, so apparently the euro is elsewhere. Help pinpointing possible areas of concern would be appreciated.
I made two changes and the error seems to have gone away, after I chased it all around the page.
Text("Notes").color(.white)
changes to:
Text("Notes").foregroundColor(Color.white)
and
Slider(value: $iconOpacity, from: 0.0, through: 1.0)
changes to:
Slider(value: $iconOpacity, in:0...1.0)
Related
Good afternoon community,
I have a problem with my app, I am trying to make it look good in both situations, so when I change orientation my app returns to the main screen, it does not stay on the second screen, will someone have a solution to this problem?
I don't know if my view breaks or cannot cover the space that I have determined, I leave my code below.
import SwiftUI
struct LoginView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
init() {
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().tintColor = .clear
UINavigationBar.appearance().backgroundColor = .clear
}
var backButton : some View {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
HStack {
Image("Backarrow")
.aspectRatio(contentMode: .fit)
.foregroundColor(.white)
Text(" Back")
.foregroundColor(.yellow)
}
}
}
var topImage:some View{
Image("header2")
.resizable()
.overlay( ImageOverlay() , alignment: .center)
.background(Color.black)
}
var usernameTextField:some View{
HStack{
TextField("", text: $LoginViewM.username)
.placeholder(Text("Numero de telefono,email o usuario").padding().foregroundColor(.white), show: LoginViewM.password.isEmpty)
.background(Color.black)
Image("menuCloseSmall")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.lineLimit(1)
.foregroundColor(.white)
.minimumScaleFactor(0.5)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
}
var errorUsernameLabel:some View{
VStack{
Text(" Hey you, no user found. Make sure you’ve provided the ")
.lineLimit(1)
Text("correct information.")
}
.multilineTextAlignment(.leading)
.foregroundColor(.redBlueParrot)
.minimumScaleFactor(0.5)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var passwordTextField:some View{
HStack{
TextField("Contraseña", text: $LoginViewM.password)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.padding(.bottom)
.foregroundColor(.white)
.placeholder(Text("Contraseña").padding().foregroundColor(.white), show: LoginViewM.username.isEmpty)
.lineLimit(1)
.minimumScaleFactor(0.5)
.background(Color.black)
Image("editShow")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
}
var errorPasswordLabel:some View{
VStack{
Text(" Incorrect password for \(LoginViewM.password). Please try again.")
}
.lineLimit(1)
.minimumScaleFactor(0.5)
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var buttonLogin:some View{
NavigationLink(
destination: Text("Hola"),
label: {
Text("Iniciar sesion")
}) .font(.custom("Montserrat-Medium", size: 16))
.foregroundColor(Color.ligthGray)
.frame(minWidth: 0, idealWidth: 174, maxWidth: 174, minHeight: 0, idealHeight: 48, maxHeight: 48, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.gray, lineWidth: 1.5))
}
var textInBottom:some View{
HStack(spacing:5){
Text("Olvidaste tu")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("contraseña"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
Text("o")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("usuario"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
}
}
#ObservedObject var LoginViewM = LoginViewModel()
var body: some View {
GeometryReader{ geometry in
NavigationView{
VStack(spacing:2){
topImage
.frame(width: geometry.size.width, height: geometry.size.height * 0.39)
VStack(spacing:17){
usernameTextField
.frame(width: geometry.size.width*0.90, height: geometry.size.height*0.05)
errorUsernameLabel
.frame(width: geometry.size.width*0.90,height: geometry.size.height*0.06, alignment: .center)
passwordTextField
.frame(width: geometry.size.width*0.90, height: geometry.size.height*0.05)
errorPasswordLabel
.frame(height: geometry.size.height*0.06, alignment: .center)
}.frame( height: geometry.size.height * 0.40)
VStack{
buttonLogin
}.frame(height: geometry.size.height * 0.10, alignment: .center)
Spacer()
textInBottom
.frame(height: geometry.size.height * 0.05, alignment: .center)
Spacer()
}
.ignoresSafeArea(.all)
.background(Color.black)
}
.navigationBarItems(leading: backButton)
.navigationBarBackButtonHidden(true)
.background(Color.black)
.navigationViewStyle(StackNavigationViewStyle())
}
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
}
}
I'm trying to eliminate the space that the top stack covers, but as much as I need the image to cover the space where the time is shown and the battery is not successful, does anyone have any idea how to do it?
I leave a photo of what I want to eliminate, it is circled with yellow, I also leave my code.
import SwiftUI
struct LoginView: View {
#ObservedObject var LoginViewM:LoginViewModel
var body: some View {
GeometryReader{ geo in
NavigationView{
VStack(spacing:10){
topImage
.frame(width: geo.size.width, height: 270)
.padding(.bottom)
VStack{
usernameTextField
errorUsernameLabel
passwordTextField
errorPasswordLabel
}
.aspectRatio(contentMode: .fill)
Spacer(minLength: 10)
VStack{
buttonLogin
}
Spacer(minLength: 10)
VStack{
textInBottom
}
Spacer(minLength: 10)
}
.padding(.all)
.background(Color.black)
}
.padding(.all)
.background(Color.black)
.frame(width: geo.size.width, height: geo.size.height,alignment: .bottom)
}
.padding(.vertical)
.background(Color.black, alignment: .bottom)
.ignoresSafeArea(.all)
}
}
extension LoginView{
var topImage:some View{
Image("header2")
.resizable()
.overlay( ImageOverlay() , alignment: .center)
.background(Color.black)
}
var usernameTextField:some View{
HStack{
TextField("Phone number, username or email", text: $LoginViewM.username)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.foregroundColor(.white)
.placeholder(Text("Phone number, username or email").padding().foregroundColor(.white), show: LoginViewM.password.isEmpty)
.background(Color.black)
// need to hide this icon
Image("menuCloseSmall")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding()
}
var errorUsernameLabel:some View{
Text(" Hey you, no user found. Make sure you’ve provided the \n correct information.")
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var passwordTextField:some View{
HStack{
TextField("Password", text: $LoginViewM.password)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.padding(.bottom)
.foregroundColor(.white)
.placeholder(Text("Password").padding().foregroundColor(.white), show: LoginViewM.username.isEmpty)
.background(Color.black)
Image("editShow")
.padding()
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding()
}
var errorPasswordLabel:some View{
Text(" Incorrect password for \(LoginViewM.password). Please try again.")
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var buttonLogin:some View{
Button(action: {
}) {
Text("Log In")
}
.font(.custom("Montserrat-Medium", size: 16))
.foregroundColor(Color.ligthGray)
.frame(width: 174, height: 42, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.gray, lineWidth: 1.5))
}
var textInBottom:some View{
HStack(spacing:5){
Text("Forgot")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("password"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
Text("or")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("username"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
}
.padding()
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView(LoginViewM: LoginViewModel())
}
}
That gap is for navigation bar's title gap. You can set .navigationTitle("Example") to see that. If you want to hide it you need to set .navigationBarHidden(true).
NavigationView {
VStack(spacing: 10) {
// ...
}
.navigationBarHidden(true) // <-- Here
}
I am trying to build a List that I want to look like a timeline.
Each cell will represent a milestone.
Down the left hand side of the table, I want the cells to be 'connected', by a line (the timeline).
I have tried various things to get it to display as I want but I have settled with basic geometric shapes , i.e Circle() and Rectangle().
This is sample code to highlight the problem:
import SwiftUI
struct ContentView: View {
var body: some View {
let roles: [String] = ["CEO", "CFO", "Managing Director and Chairman of the supervisory board", "Systems Analyst", "Supply Chain Expert"]
NavigationView{
VStack{
List {
ForEach(0..<5) { toto in
NavigationLink(
destination: dummyView()
) {
HStack(alignment: .top, spacing: 0) {
VStack(alignment: .center, spacing: 0){
Rectangle()
.frame(width: 1, height: 30, alignment: .center)
Circle()
.frame(width: 10, height: 10)
Rectangle()
.frame(width: 1, height: 20, alignment: .center)
Circle()
.frame(width: 30, height: 30)
.overlay(
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.system(size: 30, weight: .light , design: .rounded))
.frame(width: 30, height: 30)
)
//THIS IS THE RECTANGLE OBJECT FOR WHICH I WANT THE HEIGHT TO BE VARIABLE
Rectangle()
.frame(width: 1, height: 40, alignment: .center)
.foregroundColor(.green)
}
.frame(width: 32, height: 80, alignment: .center)
.foregroundColor(.green)
VStack(alignment: .leading, spacing: 0, content: {
Text("Dummy operation text that will be in the top of the cell")
.font(.subheadline)
.multilineTextAlignment(.leading)
.lineLimit(1)
Label {
Text("March 6, 2021")
.font(.caption2)
} icon: {
Image(systemName: "calendar.badge.clock")
}
HStack{
HStack{
Image(systemName: "flag.fill")
Text("In Progress")
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.blue)
.background(Color.white)
.cornerRadius(5, antialiased: true)
HStack{
Image(systemName: "person.fill")
Text(roles[toto])
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.green)
.background(Color.white)
.cornerRadius(5, antialiased: true)
HStack{
Image(systemName: "deskclock")
Text("in 2 Months")
.font(.system(size: 12))
}
.padding(.horizontal, 4)
.padding(.vertical, 3)
.foregroundColor(.red
)
.background(
Color.white
)
.cornerRadius(5, antialiased: true)
}
})
}.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct dummyView: View {
var body: some View {
Text("Hello, World!")
}
}
struct dummyView_Previews: PreviewProvider {
static var previews: some View {
dummyView()
}
}
but as you can see in the enclosed picture, there are unwanted gaps
So other content in the cell is making the height of the entire cell 'unpredictable' and break the line.
Is there a way to determine the height of the cell and extend the dimensions of the Rectangle, so that it extends to the full height of the cell?
Is there a better approach you recommend for trying to build such a timeline ?
PS: I have tried playing around with .frame and .infinity but that does work.
Many thanks.
Why not just draw the line based on the size of the row. See Creating custom paths with SwiftUI. Remember, everything is a view.
First, you need to decompose what you are doing into subviews. You have too many moving parts in one view to get it correct. Also, I would avoid setting specific padding amounts as that will mess you up when you change devices. You want a simple, smart view that is generic enough to handle different devices.
I would have a row view that has a geometry reader so it knows its own height. You could then draw the line so that it spanned the full height of the row, regardless of the height. Something along the lines of this:
struct ListRow: View {
var body: some View {
GeometryReader { geometry in
ZStack {
HStack {
Spacer()
Text("Hello, World!")
Spacer()
}
VerticalLine(geometry: geometry)
}
}
}
}
and
struct VerticalLine: View {
let geometry: GeometryProxy
var body: some View {
Path { path in
path.move(to: CGPoint(x: 20, y: -30))
path.addLine(to: CGPoint(x: 20, y: geometry.size.height+30))
}
.stroke(Color.green, lineWidth: 4)
}
}
I have a vertical ScrollView with a ForEach loop that has HStack's inside with Text, Image, and Two Text's. I'd like to keep each row's items in alignment with each other. I've attempted to wrap in a VStack with alignment .leading but did nothing. The issue I'm having is the text doesn't line up. Still very new to SwiftUI so any help would be appreciated.
ScrollView(.vertical) {
ForEach(self.daily.forecast, id: \.date) { forecast in
HStack (spacing : 10){
Text(forecast.date ?? "")
.fontWeight(.bold)
Spacer()
RequestImage(Url("IMAGE_URL"))
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.clipped()
Spacer()
Text("\(forecast.maxTemp)")
.fontWeight(.bold)
Text("\(forecast.minTemp)")
.fontWeight(.bold)
}
}
}
.padding(.all, 15)
.onAppear() {
authorize {_ in
loadForecast()
}
}
UPDATED:
I was able to get a bit closer but things still aren't aligned to where I'd like them to be.
ScrollView(.vertical) {
ForEach(self.daily.forecast, id: \.date) { forecast in
HStack (spacing : 10){
Text(date)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 45)
Spacer()
RequestImage(Url("IMAGE_URL"))
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.frame(minWidth: 50)
.clipped()
Spacer()
Text(maxTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 45)
Text(minTemp)
.font(.title3)
.fontWeight(.bold)
.foregroundColor(Color.secondary)
.frame(minWidth: 45)
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}
.padding(.all, 15)
.onAppear() {
authorize {_ in
loadForecast()
}
}
Here is a demo of possible solution. Prepared with Xcode 12.4 / iOS 14.4
struct DemoWeatherLayout: View {
private var dayOfTheWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sut"]
var body: some View {
ScrollView {
VStack {
ForEach(dayOfTheWeek, id: \.self) {
WeatherRowView(day: $0,
icon: ["sun.max", "cloud.sun", "cloud", "cloud.snow"].randomElement()!,
low: Array(-5..<0).randomElement()!,
high: Array(1..<15).randomElement()!)
}
}.padding()
}
}
}
struct WeatherRowView: View {
var day: String
var icon: String
var low: Int
var high: Int
var body: some View {
HStack {
Text(day)
.frame(maxWidth: .infinity, alignment: .leading)
Image(systemName: icon)
.frame(maxWidth: .infinity, alignment: .leading)
HStack {
Text("+XXº").foregroundColor(.clear)
.overlay(Text(String(format: "%+d", low)), alignment: .leading)
Text("+XXº").foregroundColor(.clear)
.overlay(Text(String(format: "%+d", high)), alignment: .leading)
}
}
}
}
Three suggestions:
add alignment parameter to HStack:
HStack(alignment: .lastTextBaseline, spacing: 10) { ... //others options: .top, .center, .firstTextBaseline...
Add minLength parameter to Spacer:
Spacer(minLength: 0) but with spacing: 10 in HStack it is a bit redundant. You can remove spacing: 10 for Spacer(minLength: 10)
Add a Spacer(minLength: 0) at the end after Text("\(forecast.minTemp)").fontWeight(.bold)
I'm going to accept #Asperi answer as correct. The UI has indeed changed since to better fit said labels etc. Appreciate everyone's else. The code is very much ugly but works. Not sure if it's 100% correct.
HStack (spacing: 10){
Text(date)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
Spacer()
RequestImage(Url("IMAGE_URL_HERE"))
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.frame(minWidth: 55)
.clipped()
Spacer()
Text(maxTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 50)
.background(Color.orange)
.cornerRadius(5)
Text(minTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 50)
.background(Color.blue)
.cornerRadius(5)
}
I'm trying to get from one SwiftUI view to another SwiftUI view and I'm using a NavigationLink as per the code below, but I'm getting the error: Cannot invoke initializer for type 'NavigationLink<_, _>' with an argument list of type '(destination: PlaylistTable)'
Below is my code for the button which triggers the link to the next view:
struct MusicButton: View {
var body: some View {
NavigationView {
Button(action: {
NavigationLink(destination: PlaylistTable())
})
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
}
}
Don't put NavigationLink inside a Button will solve your problem:
NavigationView {
NavigationLink(destination: PlaylistTable())
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
If you want to use the button, then move the navigation link to the background.
struct MusicButton: View {
#State var isActive = false
var body: some View {
NavigationView {
Button(action: {
isActive.toggle()
})
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
.background(
NavigationLink(destination: PlaylistTable(), isActive: $isActive) {EmptyView()}
)
}
}