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)
}
)
Related
I'm working on an app with a piece of large text with buttons underneath which I want to take up the same width as the text. My solution is to use a VStack with the .fixedSize() modifier:
VStack {
Text(viewModel.timeString)
.animation(nil)
.minimumScaleFactor(0.1)
.lineLimit(1)
.font(.system(size: 100, design: .monospaced))
.padding(.vertical, -20)
TimerActionsCompact(viewModel: viewModel) // the 3 buttons
}
.fixedSize()
This produces the result I want:
However, when the text becomes too big, it just goes off the screen instead of shrinking, even though I have minimumScaleFactor and lineLimit set.
I found that the problem was .fixedSize(), and removing it causing the text to shrink properly.
Am I doing something wrong, or could this be a bug with swiftUI? If so is there any workaround?
Thanks!
One possible way you can use frame modifier like this example:
struct ContentView: View {
#State private var string: String = "0.0"
var body: some View {
Text(string)
.font(.system(size: 100, design: .monospaced))
.minimumScaleFactor(0.1)
.lineLimit(1)
.frame(width: 200, height: 80) // give your custom size here as you like!
.background(Color.gray.cornerRadius(10.0))
.animation(nil, value: string)
Button("add") { string += String(describing: Int8.random(in: 0...9)) }.padding()
}
}
I have a text field in swiftUI, and in order to make it more appealing I'd like to add a border and have rounded corners. But it doesn't seem to work like it's supposed to (see image). What did I miss?
I've tried putting .cornerradius() before .border(), but it had the same effect.
TextField("Text input goes here", text: $addMins)
.padding(.all, 5.0)
.background(View)
.frame(width: 300.0, height: 35.0)
.border(Color.green, width: 2)
.cornerRadius(14)
So you want something like this?
TextField("Text Field", text: $text)
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 14)
.stroke(Color.green, lineWidth: 2)
)
.padding()
Here a simple way:
struct ContentView: View {
#State private var stringOfTextField: String = String()
var body: some View {
TextField("Enter text . . .", text: $stringOfTextField)
.padding()
.overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color.black, style: StrokeStyle(lineWidth: 1.0)))
.padding()
}
}
By the way, if you need a stroked and corner radiused text field with a different background, here's a solution
TextField("Placeholder", text: $text)
.padding()
.background(RoundedRectangle(cornerRadius: 5).fill(Color.gray))
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(lineWidth: 1)
)
.foregroundColor(.black)
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)
})
}
}
}
}
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
ZStack {
RoundedRectangle(cornerRadius: 8)
.foregroundColor(.red)
.scaledToFit() //.frame(width: 200, height: 25)
HStack {
Image(systemName: "tag.fill")
.foregroundColor(.white)
Text("Tickets Not Available")
.font(.headline)
.foregroundColor(.white)
.fixedSize(horizontal: true, vertical: false)
}
}
.scaledToFit()
As you can see my views are placed in a zstack so that the rounded rectangle can be the background of the text view. I've tried so many different things like where to put the .scaledtofit and it just gives me wack results each time.
is this what you're after (note the Image.resizable):
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 8).foregroundColor(.blue)
HStack{
Image(systemName: "tag.fill").resizable().padding(4).foregroundColor(.white).scaledToFit()
Text("Get Tickets").font(.headline).foregroundColor(.white)
}
}.fixedSize()
}
The question is a bit unclear but if you are trying to fit a shape inside the text view, and you are fine with getting rid of scaledToFit, then the code should be:
RoundedRectangle(cornerRadius: 8).foregroundColor(.red).frame(width: textView.width, height: textView.height)
Hope this helps, and hopefully you didn't need to use scaledToFit.
If you did tell me in comments.
A reusable ButtonStyle might be helpful here. Instead of a ZStack, using the .background modifier helps to keep the size of the Button contents:
struct RoundedButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
ZStack {
configuration.label
.font(.headline)
.padding()
.background(RoundedRectangle(cornerRadius: 8).foregroundColor(Color.blue))
}
}
}
Usage example:
Button(
action: {
print("Button Tapped")
},
label: {
HStack {
Image(systemName: "tag.fill")
Text("Tickets")
}
}
)
.buttonStyle(RoundedButtonStyle())