There is no built-in font-weight modifier for textfield in SwiftUI, as of Xcode 11.2.1.
How can we introduce font-weight without extending UITextField as UIViewRepresentable?
A general approach for using standard font size options and weights that work with SwiftUI TextField. For example:
TextField("Name", text: $name)
.font(Font.headline.weight(.light))
Available standard size options (smallest to largest):
.caption
.footnote
.subheadline
.callout
.body
.headline
.title3
.title2
.title
.largeTitle
Available standard font weights (lightest to heaviest):
.ultralight
.thin
.light
.regular
.medium
.semibold
.bold
.heavy
.black
import SwiftUI
struct ContentView: View {
#State var TextValue: String = "Hello"
var body: some View {
VStack {
TextField("placeholder", text: $TextValue)
.padding(.horizontal, 50)
.font(.system(size: 30, weight: .heavy, design: .default))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
TextField("Name", text: $name)
.font(Font.body.bold())
iOS 15+
SwiftUI supports markdown.
Add double asterisks (**) arroud the text/characters to make it bold.
Text("**This text is bold**")
To emphasize text, use underscore
Text("_This text is italic_")
The updated approach for iOS 13.0+, macOS 10.15+, tvOS 13.0+, watchOS 6.0+ is:
.fontWeight(.bold)
Expanding on shawnynicole's answer, you can create an extension:
extension View {
func bold() -> some View {
font(Font.body.bold())
}
}
and apply it to any View (including the TextField):
TextField("Text", text: $text)
.bold()
Related
TLDR: The view modifier .ignoresSafeArea(.keyboard) does not appear to work when used inside a bottom sheet. Is there a workaround?
In a SwiftUI View, tapping a TextField invokes the keyboard and the Textfield then moves upwards to avoid the keyboard.
struct ContentView: View {
#State var mytext: String = "Some text"
var body: some View {
VStack {
Spacer()
TextField("abc", text: $mytext)
Spacer()
}
}
}
This keyboard avoidance behaviour can be disabled by adding the .ignoresSafeArea modifier
struct ContentView: View {
#State var mytext: String = "Some text"
var body: some View {
VStack {
Spacer()
TextField("abc", text: $mytext)
Spacer()
}
.ignoresSafeArea(.keyboard, edges: .bottom)
}
}
and the TextField no longer moves upwards.
If this technique is applied inside to a view in a bottom sheet it no longer works and the entire sheet is pushed up by the keyboard.
struct ContentView: View {
#State var mytext: String = "Some text"
#State var isPresented: Bool = true
var body: some View {
Color.mint
.sheet(isPresented: $isPresented) {
VStack {
Spacer()
TextField("abc", text: $mytext)
Spacer()
}
.presentationDetents( [.fraction(0.33)] )
.ignoresSafeArea(.keyboard, edges: .bottom)
}
}
}
I've tried applying .ignoresSafeArea(.keyboard, edges: .bottom) to every view thats exposed in the code with no success.
I suspect that the bug is due to the bottom sheet implementation using a UIHostingController internally. This can been seen using Xcode's Debug View Hierarchy tool.
Others have described how UIHostingController does not respect the .ignoresSafeArea(.keyboard, edges: .bottom) modifier and have developed workarounds but these are not applicable here because the UIHostingController is created internally, not explicitly in my code.
Is there any way to get the view inside the sheet to ignore the keyboard and stay put?
I'm open to any and all suggestions. Thanks!
Goal: use a custom Font on SwiftUI, targeting MacOS.
Problem: On iOS, custom Font works fine in SwiftUI:
But on MacOS, it doesn't:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
.font(Font.custom("SourceCodePro-ExtraLight", size: 40))
Text("Hello, world!")
.font(Font.custom("LobsterTwo", size: 40))
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Tried: I made sure that both fonts are added to Info tab on corresponding iOS and MacOs targets:
Seems to be a problem with SwiftUI using UIFont under the hood, and a special NSFont would be needed...
Any help is much appreciated!
Solved by adding this line to the plist file, and a "." as the value
I'm beginner in SwiftUI and faced strange behaviour of ForEach layout when adding some VStack with divider inside.
Here is example:
struct TestUserView: View {
#State var users: [String] = ["John Doe",
"Jane Doe",
"James Doe",
"Judy Doe"]
var body: some View {
VStack {
ForEach(users, id: \.self) { user in
VStack(spacing: 0) {
// Text("")
// .background(Color.blue)
// .frame(height: 0)
//
Rectangle()
.frame(height: 5)
HStack {
Text(user)
.font(.system(size: 55, weight: .bold))
Spacer()
}
}
.background(Color.green)
}
}
.background(Color.purple)
}
}
It looks like this:
See this purple area. I don't expect it to be there.
Strange enough that it disappears if add Text before separator(no matter if this is Rectangle, Divider or Color.black). Just uncomment commented code and it will become as expected.
Just wondering if this is bug or I don't understand SwiftUI layout.
If this is expected please point me to some useful documentation.
Used XCode 11.5
It is effect of default spacing between different kind of views.
Here is a solution. Tested with Xcode 11.4 / iOS 13.4.
var body: some View {
VStack(spacing: 0) { // << explicit spacing !!
// .. other code
I am trying to build a "chat" view using SwiftUI and I would like to know how can I do in order to increase the height dynamically of a TextField where the users should write their messages.
I have defined a minHeight expecting that the TextField could increase its height based on its intrinsic content.
My current view code:
struct MessageSenderView: View {
#Binding var userTextInput: String
var body: some View {
VStack {
HStack(alignment: .center, spacing: 17) {
senderPlusImage()
ZStack {
Capsule()
.fill(Color("messagesBankDetailColor"))
.frame(minHeight: 34, alignment: .bottom)
HStack(spacing: 15){
Spacer()
ZStack(alignment: .leading) {
if userTextInput.isEmpty { Text(Constants.Login.Text.userPlaceHolder).foregroundColor(Color.white) }
TextField(" ", text: $userTextInput)
.multilineTextAlignment(.leading)
.frame(minHeight: CGFloat(34))
.foregroundColor(Color.white)
.background(Color("messagesBankDetailColor"))
.onAppear { self.userTextInput = "" }
}
arrowImage()
}
.frame(minHeight: CGFloat(34))
.padding(.trailing, 16)
.layoutPriority(100)
}
}
.padding(16)
}
.background(Color("mainBackgroundColor"))
}
}
And here is how it looks like:
Thank you!!!!
For this purpose, you should use UITextfield with the UIViewRepresentable protocol.
Maybe this tutorial can help you : Dynamic TextField SwiftUI
To support multiline text, you should use TextEditor instead of TextField.
If you want it to grow as you type, embed it with a label like below:
ZStack {
TextEditor(text: $text)
Text(text).opacity(0).padding(.all, 8) // <- This will solve the issue if it is in the same ZStack
}
Demo
I am exploring SwiftUI as I am trying to build a login view and now I am facing a problem
This is what I am trying to achieve:
As you can see I already reached this point but I don't like my implementation
struct ContentView : View {
#State var username: String = ""
var body: some View {
VStack(alignment: .leading) {
Text("Login")
.font(.title)
.multilineTextAlignment(.center)
.lineLimit(nil)
Text("Please")
.font(.subheadline)
HStack {
VStack (alignment: .leading, spacing: 20) {
Text("Username: ")
Text("Password: ")
}
VStack {
TextField($username, placeholder: Text("type something here..."))
.textFieldStyle(.roundedBorder)
TextField($username, placeholder: Text("type something here..."))
.textFieldStyle(.roundedBorder)
}
}
}.padding()
}
}
Because in order to make the username and password text aligned exactly in the middle of the textfield, I had to put literal spacing value of 20 in the VStack which I don't like because most probably It won't work on different device sizes.
Anyone sees a better way to achieve the same result?
Thanks
We're going to implement two new View modifier methods so that we can write this:
struct ContentView: View {
#State var labelWidth: CGFloat? = nil
#State var username = ""
#State var password = ""
var body: some View {
VStack {
HStack {
Text("User:")
.equalSizedLabel(width: labelWidth, alignment: .trailing)
TextField("User", text: $username)
}
HStack {
Text("Password:")
.equalSizedLabel(width: labelWidth, alignment: .trailing)
SecureField("Password", text: $password)
}
}
.padding()
.textFieldStyle(.roundedBorder)
.storeMaxLabelWidth(in: $labelWidth)
}
}
The two new modifiers are equalSizedLabel(width:alignment:) and storeMaxLabelWidth(in:).
The equalSizedLabel(width:alignment) modifier does two things:
It applies the width and alignment to its content (the Text(“User:”) and Text(“Password:”) views).
It measures the width of its content and passes that up to any ancestor view that wants it.
The storeMaxLabelWidth(in:) modifier receives those widths measured by equalSizedLabel and stores the maximum width in the $labelWidth binding we pass to it.
So, how do we implement these modifiers? How do we pass a value from a descendant view up to an ancestor? In SwiftUI, we do this using the (currently undocumented) “preference” system.
To define a new preference, we define a type conforming to PreferenceKey. To conform to PreferenceKey, we have to define the default value for our preference, and we have to define how to combine the preferences of multiple subviews. We want our preference to be the maximum width of all the labels, so the default value is zero and we combine preferences by taking the maximum. Here's the PreferenceKey we'll use:
struct MaxLabelWidth: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = max(value, nextValue())
}
}
The preference modifier function sets a preference, so we can say .preference(key: MaxLabelWidth.self, value: width) to set our preference, but we have to know what width to set. We need to use a GeometryReader to get the width, and it's a little tricky to do properly, so we'll wrap it up in a ViewModifier like this:
extension MaxLabelWidth: ViewModifier {
func body(content: Content) -> some View {
return content
.background(GeometryReader { proxy in
Color.clear
.preference(key: Self.self, value: proxy.size.width)
})
}
}
What's happening above is we attach a background View to the content, because a background is always the same size as the content it's attached to. The background View is a GeometryReader, which (via the proxy) provides access to its own size. We have to give the GeometryReader its own content. Since we don't actually want to show a background behind the original content, we use Color.clear as the GeometryReader's content. Finally, we use the preference modifier to store the width as the MaxLabelWidth preference.
Now have can define the equalSizedLabel(width:alignment:) and storeMaxLabelWidth(in:) modifier methods:
extension View {
func equalSizedLabel(width: CGFloat?, alignment: Alignment) -> some View {
return self
.modifier(MaxLabelWidth())
.frame(width: width, alignment: alignment)
}
}
extension View {
func storeMaxLabelWidth(in binding: Binding<CGFloat?>) -> some View {
return self.onPreferenceChange(MaxLabelWidth.self) {
binding.value = $0
}
}
}
Here's the result:
You can use Spacers alongside with fixedSize modifier for height. You should set set heights of any row's object in order to achieve exact table style view:
struct ContentView : View {
private let height: Length = 32
#State var username: String = ""
var body: some View {
VStack(alignment: .leading) {
Text("Login")
.font(.title)
.multilineTextAlignment(.center)
.lineLimit(nil)
Text("Please")
.font(.subheadline)
HStack {
VStack (alignment: .leading) {
Text("Username: ") .frame(height: height)
Spacer()
Text("Password: ") .frame(height: height)
}
VStack {
TextField($username, placeholder: Text("type something here..."))
.textFieldStyle(.roundedBorder)
.frame(height: height)
Spacer()
TextField($username, placeholder: Text("type something here..."))
.textFieldStyle(.roundedBorder)
.frame(height: height)
}
}
.fixedSize(horizontal: false, vertical: true)
}
.padding()
}
}
Note that setting height on TextField does not effect it's height directly, but it will just set the height of it's content text's height.
If you are looking to do something similar with Buttons on macOS, be advised that as of Xcode 11.3 you'll end up with the following at run time:
instead of:
I've written up my solution in this blog post. It is quite similar to #rob-mayoff 's answer and works for both labels and buttons.