SwiftUI add image to left side of text field - uitextfield

I'm trying to get an SF Symbol on the left side of a text field in SwiftUI, but the methods used before SwiftUI don't really work. I thought this code would work, but it didn't. Also if anyone could help, how would I change the font and color of the text in the text field?
Here's an image of what I'm trying to accomplish: https://i.stack.imgur.com/Dud0M.png
TextField(textFieldDescription, text:
.constant(""))
.padding(.all)
.background(textFieldBackground)
.cornerRadius(10)
.leftViewMode = Image(systemName: "lock").always
.leftViewMode = .always

Here's one implementation. Note that there is a bug, where if the initial text of the textfield is empty, the color and font setting will be ignored:
HStack {
Image(systemName: "lock")
TextField("", text: .constant("typed text")).foregroundColor(Color.red).font(Font.custom("Papyrus", size: 16))
}
.padding()
.overlay(RoundedRectangle(cornerRadius: 10).stroke(lineWidth: 2).foregroundColor(Color.black))

SwiftUI, XCode 11.6
This code worked for me.
Note:-
The yellow border outside the view is background view color which will not be there in your case. Outer-most HStack holds another HStack(inner HStack) of items image and TextField. To inner HStack
Spacer(minLength: 20) is added move away from the edge of the screen.
HStack {
Spacer(minLength: 20)
HStack (alignment: .center,
spacing: 10) {
Image("userName")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.foregroundColor(.black)
.frame(minWidth: 0, maxWidth: 30)
.frame(minHeight: 0, maxHeight: 33)
TextField ("User Name", text: $userName)
} // HSTack
.padding([.top,.bottom], 2)
.padding(.leading, 5)
.background(Color.white, alignment: .center)
.cornerRadius(5)
Spacer(minLength: 20)
}

Here is my implementation with ZStack:
ZStack(alignment: .trailing) {
TextField("", text: $text)
.font(Font.system(size: 21))
Button(action: {
//Some button action
}) {
Image("iconName").resizable()
}
.frame(width: 35, height: 35)
.padding(.trailing, 10)
}

If you can, I might recommend encapsulating your TextField and other inputs within SwuiftUI's Form container around your TextField inputs. This will provide you with some "freebie" styling that can make what you're looking for a bit easier. For example, in iOS and iPadOS, the Form wrapper renders each element as an item in a List with the .grouped style. (It's a bit different for macOS.)
Here's what I used to achieve the style you're looking for. One note: SF Symbols aren't all uniform in their width, so you'd want to explicitly set the frame dimensions and padding to get everything lined up perfectly.
Form {
HStack{
Image(systemName:"envelope")
// play with the frame and padding here
TextField("Email Address", text: $email)
}
HStack{
Image(systemName:"lock")
SecureField("Password", text: $password)
}
}

Related

SwiftUI Firestore LazyVGrid Navigation Slows with more elements

I have a tab on my fitness app that shows all the fitness trainers on my app, pulled from firestore. I have noticed that when the grid is showing more than 4-5 trainers then when I tap on a trainer (navigation link to their profile) the transition is pretty laggy and slow, and the same thing happens when I press the back button on the trainer profile to return to the grid of all trainers.
Here is my code for the tab showing all trainers:
ScrollView (.vertical, showsIndicators: false, content: {
VStack (alignment: .leading, spacing: 15){
//PAGE TITLE
HStack {
Text("Explore creators")
.font(.system(size: 22, weight: .semibold))
.foregroundColor(.black)
Spacer(minLength: 0)
}
.padding(.horizontal)
LazyVGrid(columns: items, alignment: .leading, spacing: 12, content: {
//FOR EACH LOOP TO SHOW ALL TRAINERS
ForEach(topTrainers) { trainer in
NavigationLink(
destination: TrainerView(trainer: trainer, user: user),
label: {
ExploreGridCell(trainer: trainer)
})
//END OF FOR EACH LOOP
}
//END OF LAZYVGRID
})
.padding(.top, 6)
.padding(.horizontal)
}
.padding(.bottom)
.padding(.top)
})
.background(Color("fiticBg").ignoresSafeArea())
.navigationBarTitle("")
.navigationBarHidden(true)
.onTapGesture {
self.hideKeyboard()
}
Here is my code for what a trainer cell in the lazyVGrid is:
ZStack {
KFImage(URL(string: trainer.trainerImageUrl))
.loadImmediately()
.resizable()
.scaledToFill()
.frame(width: width, height: 175)
.clipped()
Rectangle()
.foregroundColor(.clear)
.background(LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .center, endPoint: .bottom))
VStack (alignment: .leading, spacing: 5){
//TRAINER CERTIFICATION BADGE
if trainer.trainerCertified {
HStack {
ZStack {
Color(.white)
.frame(width: 15, height: 15)
Image(systemName: "checkmark.seal.fill")
.font(.title2)
.foregroundColor(Color("fiticGreen"))
}
.clipShape(Circle())
Spacer(minLength: 0)
}
} else {
//SHOW NOTHING HERE IF TRAINER IS NOT CERTIFIED
}
Spacer()
//CONTENT TITLE WITH SPACER FOR SECOND LINE OVERLAP
HStack {
Text(trainer.trainerName)
.font(.system(size: 16, weight: .bold))
.foregroundColor(.white)
Spacer(minLength: 0)
}
}
.padding(.horizontal, 10)
//PUSHES TRAINER NAME UP A BIT
.padding(.bottom)
//PUSHES CERTIFICATION BADGE DOWN A BIT
.padding(.top, 5)
}
.cornerRadius(8)
.shadow(color: Color.black.opacity(0.25), radius: 5, x: 0, y: 5)
From other stack overflow questions I have seen things about using a List instead of scrollview, but I have tried and it just does not work with how my view needs to be set up.
Is there anything in my code that would appear to be causing such poor performance and slow transitions for the navigation links?
So from other suggestions it seemed part of the problem was loading the images from firestore since they were such large documents. So I compressed the images and it slightly helped.
However, the thing that helped the most was removing the shadow from trainer cell. That seemed to be causing the most lag.
Nothing in your code seems to cause that lag, except, perhaps, the time to retrieve the Image for the trainer. Anything pulled from the interweb is subject to source of truth delays. One trouble shoot for that would be to pull a dozen or so images locally sourced just to determine if that lag goes away when pulling them from a local source. If so, then you need to look to FireStore

SwiftUI RectangularFullView - Aligning nested Stacks

I'm building a personal apple watch app, and I've just wrapped my head around complications.
I've managed to get mine to display with the proper data, but the View is not aligning on the screen as I would like it.
The stacks are aligning in the center with dynamic widths. The text is also centre aligned.
I tried editing the text with .multilineTextAlignment but that didn't change anything.
I have mocked up the expected alignment below:
The red box is a HStack with an image that is always 60x56 pixels.
I want this to be left aligned, which seems to be working so far.
I also want it to be centered vertically in the view, but I'm not sure if it is even possible.
The pink box is a VStack of text.
This text should be left aligned, but I can't get that to work.
The blue box is the encompassing HStack
Here is my code for this complication (I've just realized I've given the template code with images of a real example, but it should be understandable):
struct ComplicationViewTemplate: View {
var body: some View {
HStack {
HStack {
Image("0i")
.aspectRatio(contentMode: .fit)
}.frame(width: 60, height: 56, alignment: .leading)
VStack {
Text("Egg")
.font(.body)
.bold()
Text("0 steps")
.font(.caption)
Text("Level 01")
.font(.caption)
}
}
}
}
If it helps, since this app is only for me, it's only ever going to be on a Series 5 44mm watch, so items wouldn't have to be dynamic for other watch sizes.
Summary of questions:
Is it possible to vertically centre a HStack inside another HStack
Is it possible to left-align text inside of a VStack
Thanks for any help!
I've managed to get this to work:
struct ComplicationViewTemplate: View {
var body: some View {
HStack {
HStack {
Image("14gi")
.interpolation(.none)
.aspectRatio(contentMode: .fill)
.frame(width: 60, height: 56, alignment: .leading)
}.frame(width: 60, height: 56, alignment: .leading)
Spacer(minLength: 10)
VStack(alignment: .leading) {
Text("Pikachu").bold().font(.body).alignmentGuide(.leading, computeValue: { d in d[.leading]
})
Text("000000 steps").font(.caption).alignmentGuide(.leading, computeValue: { d in d[.leading]
})
Text("Level 00").font(.caption).alignmentGuide(.leading, computeValue: { d in d[.leading]
})
}.frame(width: 110, alignment: .leading)
}
}
}
Here's what the result looks like (I've also updated the template slightly):

Why are my SwiftUI List Dividers not lining up properly?

I'm trying to properly line up my SwiftUI list but I am unable to center the list dividers. For some reason, the list seems centred but the dividers are aligned to trailing, not to the center.
I added some background colouring to the elements in an effort to debug it, but can't seem to find out a reason why this is happening.
There doesn't seem to be any padding blocking it either. Maybe it has to do with the list style?
Code below:
List {
ForEach(savedpoems, id:\.title) {SavedPoem in
NavigationLink (destination: DetailViewSaved(savedPoem: SavedPoem)){
HStack {
VStack (alignment: .leading){
Text("\(SavedPoem.title ?? "")")
.font(.headline)
.foregroundColor(.black)
.lineLimit(1)
.padding(.bottom, 3)
Text("\(SavedPoem.author ?? "")")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.trailing)
.background(Color.orange)
Spacer()
}
.padding()
.background(Color.blue)
}.padding(.all, 0)
.background(Color.red)
}.onDelete(perform: remove)
.background(Color.yellow)
}
.navigationTitle("")
.navigationBarHidden(true)
.padding(.bottom, 30)
.listStyle(PlainListStyle())
.background(Color.black)
}
.padding(.horizontal)
.edgesIgnoringSafeArea(.bottom)
Any suggestions? Thanks in advance.
If you decrease the .leading .padding for your List it should even out.
Below is the sample from your code on where to put it (Bottom part)
.padding(.leading, -16)
}//Something not Listed I placed a VStack
.padding(.horizontal)
.edgesIgnoringSafeArea(.bottom)

Align text as leading in ScrollView - SWIFTUI

I have a ScrollView:
ScrollView {
VStack (alignment: .leading) {
Text("\(userData.username), \(userData.age)")
.fontWeight(.semibold)
.font(Font.system(size:30))
}
}
The output is:
I tried flipping the Stack and having the scroll view inside, but I get the same result.
The work around I have is to put it in a HStack and add a Spacer()
HStack {
Text("\(userData.username), \(userData.age)")
.fontWeight(.semibold)
.font(Font.system(size:30))
.padding([.leading])
Spacer()
}
This does the trick but I dont think this is the ideal way. Is this the only way? or is there a better solution to align text vertically in a scrollview?
By default stack container is tight to content, so alignment has no effect.
Here is possible solution
ScrollView {
VStack (alignment: .leading) {
Text("\(userData.username), \(userData.age)")
.fontWeight(.semibold)
.font(Font.system(size:30))
}.frame(maxWidth: .infinity, alignment: .leading) // << make screen-wide !!
}
Actually, you just missed a parameter and can do this:
ScrollView {
VStack (alignment: .leading, spacing: 8) {
Text("\(userData.username), \(userData.age)")
.fontWeight(.semibold)
.font(Font.system(size:30))
}
}

SwiftUI pin Image to top right of screen and resize based on device size

I just learning Apple's SwiftUI and it is a bit frustrating even doing the basics. I am trying to get my image to the top right of my screen but the default has it showing up in the center of my screen. Anyone know how I can accomplish this. In addition, I tried to get the image to resize based on the screen size but the old self.frame.width that I used to use in regular Swift doesn't work in Swift UI. Sorry, but this new way of writing code in SwiftUI is very odd to me.
var body: some View {
ZStack {
//Define a screen color
LinearGradient (gradient: Gradient(colors:[Color(ColorsSaved.gitLabDark),Color(ColorsSaved.gitLabLight)]),startPoint: .leading,endPoint: .trailing)
//Extend the screen to all edges
.edgesIgnoringSafeArea(.all)
VStack(alignment: .trailing) {
Image("blobVectorDark")
.resizable()
.edgesIgnoringSafeArea(.top)
.frame(width: 60, height: 60)
// .offset(x: , y: 20)
}
}
}
}
You need to add a frame for the outer container, here is the VStack.
Then assign the alignment for this container.
The width and height in the frame of VStack needs to use geometryProxy.
GeometryReader{ (proxy : GeometryProxy) in // New Code
VStack(alignment: .trailing) {
Image("blobVectorDark")
.resizable()
.edgesIgnoringSafeArea(.top)
.frame(width: 60, height: 60)
// .offset(x: , y: 20)
}
.frame(width: proxy.size.width, height:proxy.size.height , alignment: .topLeading) // New Code
}
I'm learning too so this might not be the ideal way to do it, but I did manage to get the image to pin to the top right of the screen.
You can get the screen width from GeometryReader. The alignment was driving me nuts for a while, until I realized I could give a frame to a Spacer to take up the other side of an HStack, and then it worked.
var body: some View {
GeometryReader { geometry in
VStack {
HStack {
Spacer()
.frame(width: geometry.size.width / 2)
Image("blobVectorDark")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width / 2)
}
Spacer()
}
}
.edgesIgnoringSafeArea(.all)
}

Resources