SwiftUi is there a way to get a Text inside a TextField - swift

I have recently migrated from UIKit to SwiftUi 2.0 and I am rebuilding my app with SwiftUI . In UIKit I have a textbox and inside that textbox I have a post button and I am trying to do the same in SwiftUi but have not succeeded . In the image below for SwiftUi you can see that the Text is outside the TextField . This is the code I have for that region
HStack {
TextField("", text: $Postdata)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(height: 38)
Text("Post")
.foregroundColor(.white)
.padding(.trailing, 10)
}
This is how it looks in UIKit
This is how I have it in SwiftUI, as you can see the post text is outside the TextField, any suggestions would be great

Using ZStack, we can arrange view in z axis.
Spacer() is also doesn't block any view taping, dragging and etcetera like EmptyView(). It only provide space as the name itself.
struct ContentView: View {
#State var postdata = ""
var body: some View {
ZStack {
TextField("", text: $postdata)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(height: 38)
HStack {
Spacer()
Button(action: {
}, label: {
Text("Post")
.bold()
.foregroundColor(.green)
.padding(.trailing, 10)
})
}
}
}
}

Related

iOS16 Bug Keyboard breaks layout on sheet dismissal SwiftUI

In iOS16 faced a bug with keyboard inside sheet, when sheet is dismissing keyboard disappears(what is ok), but layout is not updated. I saw only 1 question on same problem and wondering maybe somebody found a temporary workaround until Apple don't fix this.
Code to reproduce :
struct Test: View {
#State var isPresented: Bool = false
#State var text: String = ""
var body: some View {
VStack{
Button {
isPresented.toggle()
} label: {
Text("PRESENT")
}
}
.sheet(isPresented: $isPresented) {
ZStack {
Color.red
VStack{
TextField("Test", text: $text)
.frame(height: 50, alignment: .center)
Spacer()
Rectangle()
.fill(Color.blue)
.frame(width:300, height: 50)
}
}
}
}
}
Video:
https://vimeo.com/758845068
The .ignoresSafeArea() fixes the issue, but...
This will have as result of keyboard overlap in your UI and not be able to scroll to see all your elements.
I use the .adaptsToKeyboard() custom modifier taken from this answer
and then using it where needed with this particular order.
VStack {...}
.adaptsToKeyboard()
.ignoresSafeArea()

Textfield not showing

I want to show a textfield on an image. To do so, I used a ZStack view.
But the textfield isn't showing up.
Here is my code :
var meme: some View {
ZStack {
image!
.resizable()
.scaledToFit()
TextField("Enter here", text: $topText)
.padding(.all)
.foregroundColor(.white)
}
}
Why is it doing this ?
The TextField is there, but just difficult to see. You can add a background color to it, similar to what it would look like in something like Snapchat. You will now be able to see it and know where to tap.
Code:
struct ContentView: View {
#State private var topText = ""
var body: some View {
ZStack {
Image("background")
.resizable()
.scaledToFit()
TextField("Enter here", text: $topText)
.padding(.all)
.foregroundColor(.white)
.background(Color.black.opacity(0.5))
}
}
}
Result:

How to make TextEditor look like TextField - SwiftUI

I'm looking for a way to make a swiftUI TextEditor look like a TextField. I need a multiline input but I really like the appearance of rounded TextFields.
This is the closest I was able to get:
Using this code:
TextEditor(text: $instanceNotes)
.border(Color.gray)
.foregroundColor(.secondary)
.cornerRadius(3)
.padding(.horizontal)
.frame(height:100)
which looks/acts nothing like a TextField
This is the code for the TextField I want to replicate:
TextField("Name", text: $instanceName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal)
Thanks!
This gets closer (no focus support, although that could be added):
TextEditor(text: $textBinding)
.padding(4)
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.secondary).opacity(0.5))
I think the most important thing is making sure that the border is actually rounded -- right now, yours is getting cut off at the corners.
How could I change it when it's focused like TextField does?
…
#State private var text: String = ""
#FocusState private var isFocused: Bool
…
…
TextEditor(text: $textBinding)
.focused($isFocused)
.padding(4)
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(isFocused ? Color.secondary : Color.clear).opacity(0.5))
…
Show a TextEditor more accurately like a TextField:
…
Text(text)
.padding(.vertical, 10) // If not text first line hides under TextField
.padding(.horizontal, 5) // If not TextField can be saw on the right side
.frame(maxWidth: .infinity, // Frame on the screen size
minHeight: 40 // Initial size equivalent to one line
)
.overlay(
TextEditor(text: $text)
.focused($isFocused)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(isFocused ? Color.secondary : Color.clear).opacity(0.5)
)
)
…
Having the TextEditor in a Form causes the default style to change, so, the accepted answer doesn't work correctly.
I managed to get it working using:
import PlaygroundSupport
import SwiftUI
struct ContentView: View {
#State private var text: String = "Test"
var body: some View {
Form {
TextEditor(text: self.$text)
.background(Color.primary.colorInvert())
.cornerRadius(5)
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(.black, lineWidth: 1 / 3)
.opacity(0.3)
)
TextField("", text: self.$text)
.textFieldStyle(.roundedBorder)
}
}
}
PlaygroundPage.current.setLiveView(
VStack {
ContentView()
.environment(\.colorScheme, .light)
ContentView()
.environment(\.colorScheme, .dark)
}
)

SwiftUI: Overlay is on the whole VStack instead of the textfield after wrapping TextFields with VStack

Here's the simplified code:
var body: some View {
Section(header: Text("Personal Data").position(x:45, y: 17)) {
Form {
VStack {
TextField("Title", text: self.$title)
.disabled(true)
.overlay(
Button("", action: {
self.showTitles = true
}))
.popover(isPresented: self.$showTitles, attachmentAnchor: .point(.bottom)) { EmptyView() }
Divider()
TextField("Name", text: $firstName)
Divider()
TextField("Last Name", text: $lastName)
}
.padding()
.padding(.bottom, -7)
.overlay(
RoundedRectangle(cornerRadius: 6.0)
.stroke(Color.secondary, lineWidth: 1.0)
.opacity(0.3)
)
}
}
}
It was working as I wanted before adding the VStack although I need it to be able to place Dividers. I've tried to wrap the single TextField with a VStack and also used Group to see if I can only have button overlay on the the first TextField but nothing seems to work. Do I have to use GeometryReader for this purpose?
I'd appreciate it if anyone can provide some insights.
This is a little bit tricky:
Understanding the issue:
SwiftUI automatically detects the action of the default button and uses it as the cell action. So the popover will come as the popover of the entire list too (somehow 😁)
Solution
So you need to change the buttonStyle to something else than default
TextField("Title", text: self.$title)
.disabled(true)
.overlay(
Button(action: ( { showTitles.toggle() } ),
label: ( { Text("").frame(maxWidth: .infinity, maxHeight: .infinity) } )
).buttonStyle(BorderlessButtonStyle())
)
.popover(isPresented: self.$showTitles, attachmentAnchor: .point(.bottom)) { EmptyView() }
Note that how I scale the button to fill the entire space

In SwiftUI, why will my buttons trigger if contained in a ZStack but not in an overlay on a VStack?

Thanks in advance for any advice you can give. I have a custom dropdown menu that I have built in SwiftUI:
struct PhoneTypeDropdown: View {
let phoneTypes:[PhoneType] = [.Cell, .Work, .Landline]
#State var isExpanded: Bool
var body : some View {
VStack (spacing: 0) {
HStack {
Text("select type").font(.footnote)
Spacer()
Image(systemName: Constants.Design.Image.IconString.ChevronDown)
.resizable()
.frame(width: Constants.Design.Measurement.DropDownIconWidth,
height: Constants.Design.Measurement.DropDownIconHeight)
}
.padding(Constants.Design.Measurement.PadMin)
.background(Constants.Design.Colors.LightGrey)
.cornerRadius(Constants.Design.Measurement.CornerRadius)
.onTapGesture {
self.isExpanded.toggle()
}
if isExpanded {
VStack (spacing: 0){
ForEach(0 ..< phoneTypes.count) { i in
Button(self.phoneTypes[i].description, action: {
print("button tapped")
self.isExpanded.toggle()
})
.buttonStyle(DropDownButtonStyle())
if i != self.phoneTypes.count - 1 {
Divider()
.padding(.vertical, 0)
.padding(.horizontal, Constants.Design.Measurement.Pad)
.foregroundColor(Constants.Design.Colors.DarkGrey)
}
}
}.background(Constants.Design.Colors.LightGrey)
.cornerRadius(Constants.Design.Measurement.CornerRadiusMin)
.padding(.top, Constants.Design.Measurement.PadMin)
}
}.frame(width: Constants.Design.Measurement.PhoneTypeFieldWidth)
.cornerRadius(Constants.Design.Measurement.CornerRadius)
}
}
When I went to utilize this in my view, I had planned on using it as an overlay like this:
VStack(spacing: 0) {
ProfileField(text: phone1,
label: Constants.Content.PrimaryPhone,
position: .Justified)
.overlay(
PhoneTypeDropdown(isExpanded: expandDropdown1)
.padding(.top, 32) //FIXME: Fix this hard-coded value.
.padding(.trailing, Constants.Design.Measurement.PadMax),
alignment: .topTrailing
)
}
However, although the above code will trigger on clicking and expand the dropdown box, tapping any of the Button objects inside the dropdown box does nothing. I then tried to implement the dropdown box using a ZStack like this:
ZStack(alignment: .topTrailing) {
ProfileField(text: phone1,
label: Constants.Content.PrimaryPhone,
position: .Justified)
PhoneTypeDropdown(isExpanded: expandDropdown1)
.padding(.top, 32) //FIXME: Fix this hard-coded value.
.padding(.trailing, Constants.Design.Measurement.PadMax)
}
The dropdown box worked beautifully, expanding and collapsing as expected. However, now, when it expands, it pushes down the rest of the form instead of laying on top of the form as desired.
My question then is this: what would cause my button action to fire correctly when using the dropdown object in a ZStack as opposed to incorporating it in an overlay on an view in a VStack?