Swiftui - Disable Keyboard from showing up for TextField - swiftui

For swiftui are there anything for disable/prevent keyboard from showing up for TextField?
because I am designing a calculator and getting the input from the design instead of keyboard

You can use UITextField with UIViewRepresentable, which lets you stop the keyboard from showing up.
import SwiftUI
struct KeyboardView: View {
#State var text: String = ""
#State var placHolder: String = "Enter username"
var body: some View {
VStack {
Spacer()
MyTextField(currentText: $text, placeHolder: $placHolder)
.padding(.horizontal, 40.0)
Spacer()
}
}
}
struct MyTextField: UIViewRepresentable {
#Binding var currentText: String
#Binding var placeHolder: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField()
textField.inputView = UIView() // hiding keyboard
textField.inputAccessoryView = UIView() // hiding keyboard toolbar
textField.placeholder = placeHolder
textField.textColor = UIColor.black
textField.font = UIFont.systemFont(ofSize: 22.0)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ textField: UITextField, context: Context) {
textField.text = currentText
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $currentText)
}
class Coordinator: NSObject, UITextFieldDelegate {
#Binding var text: String
init(text: Binding<String>) {
self._text = text
}
}
}
Reference: Prevent Keyboard from appearing when tapping on UITextField

if you already have a TextField setup, you can add .disabled(true),
this will stop the keyboard from showing up.
TextField("", text: $txt)
.disabled(true) // <--- here

Related

swiftui ios15 keyboard avoidance issue on custom textfield

Repost question from this Adjust View up with Keyboard show in SwiftUI 3.0 iOS15.
SwiftUI keyboard avoidance won't show the whole textfield including the overlay.
I already tried a lot different ways from googling.
Does anyone have any solution for this?
struct ContentView: View {
#State var text: String = ""
var body: some View {
ScrollView {
VStack {
Spacer(minLength: 600)
TextField("Placeholder", text: $text)
.textFieldStyle(CustomTextFieldStyle())
}
}
}
}
struct CustomTextFieldStyle: TextFieldStyle {
func _body(configuration: TextField<Self._Label>) -> some View {
configuration
.padding(10)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 5)
)
}
}
You can write the custom UITextFeild, in which the intrinsicContentSize will be overridden.
Example:
final class _UITextField: UITextField {
override var intrinsicContentSize: CGSize {
CGSize(width: UIView.noIntrinsicMetric, height: 56)
}
}
Then, you can write your own implementation of TextField, using UIViewRepresentable protocol and UITextFieldDelegate:
struct _TextField: UIViewRepresentable {
private let title: String?
#Binding var text: String
let textField = _UITextField()
init(
_ title: String?,
text: Binding<String>
) {
self.title = title
self._text = text
}
func makeCoordinator() -> _TextFieldCoordinator {
_TextFieldCoordinator(self)
}
func makeUIView(context: Context) -> _UITextField {
textField.placeholder = title
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: _UITextField, context: Context) {}
}
final class _TextFieldCoordinator: NSObject, UITextFieldDelegate {
private let control: _TextField
init(_ control: _TextField) {
self.control = control
super.init()
control.textField.addTarget(self, action: #selector(textFieldEditingChanged), for: .editingChanged)
}
#objc private func textFieldEditingChanged(_ textField: UITextField) {
control.text = textField.text ?? ""
}
}

How to integrate Buttons and Links into a Text in SwiftUI

I wondered how to add Buttons and Links to a SwiftUI Text. Some Example: In a long Text, some special Words are Buttons, or Links, like in a Wikipedia Article:
There are some of the Words blue marked as links, how can I reach that in SwiftUI?
Thanks, Boothosh
I know the pain! I have spend a lot of time on internet reading articles on how to do the same and came across the easiest solution.
Reference for the solution here
1. Add TextView(...) to your project
/// Text view with click able links
struct TextView: UIViewRepresentable {
#Binding var text: String
#Binding var textStyle: UIFont.TextStyle
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.delegate = context.coordinator
textView.font = UIFont.preferredFont(forTextStyle: textStyle)
textView.autocapitalizationType = .sentences
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.isEditable = false
textView.dataDetectorTypes = .link
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
uiView.font = UIFont.preferredFont(forTextStyle: textStyle)
}
func makeCoordinator() -> Coordinator {
Coordinator($text)
}
class Coordinator: NSObject, UITextViewDelegate {
var text: Binding<String>
init(_ text: Binding<String>) {
self.text = text
}
func textViewDidChange(_ textView: UITextView) {
self.text.wrappedValue = textView.text
}
}
}
Full Usage:
struct DetailsView: View {
#State var text : String = "Yo.. try https://google.com"
#State private var textStyle = UIFont.TextStyle.body
var body: some View {
TextView(text: $text, textStyle: $textStyle)
}
}

SwiftUI - making a textfield inside a view be the first responder on touch to that view

On a view I have something like this:
TextFieldUsername()
this shows something like
So, this view shows an icon and the textfield username.
Below that, I have another one for the password.
Making that username field in focus is unnecessarily hard. The textfield is not small, but making the username field to focus is a matter of tapping on the exact position and perhaps you have to tap 2 or 3 times to make it happen.
I would like to make the whole TextFieldUsername() tappable or to increase the hit area of that textfield. I would like better to make the whole thing tappable and once tapped, make its textfield in focus.
This is TextFieldUsername
struct TextFieldUsername: View {
#State var username:String
var body: some View {
HStack {
Image(systemName: "person.crop.circle")
.renderingMode(.template)
.foregroundColor(.black)
.opacity(0.3)
.fixedSize()
TextField(TextFieldUsernameStrings.username, text: $username)
.textFieldStyle(PlainTextFieldStyle())
.textContentType(.username)
.autocapitalization(.none)
}
}
}
Is that possible in SwiftUI without using any external library like introspect?
Using a custom TextField like the one from Matteo Pacini
you can do something like this:
struct CustomTextField1: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate {
#Binding var text: String
var didBecomeFirstResponder = false
init(text: Binding<String>) {
_text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
#Binding var text: String
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<CustomTextField1>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func makeCoordinator() -> CustomTextField1.Coordinator {
return Coordinator(text: $text)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField1>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
struct ContentView : View {
#State var text: String = ""
#State var isEditing = false
var body: some View {
CustomTextField1(text: $text, isFirstResponder: isEditing)
.frame(width: 300, height: 50)
.background(Color.red)
.onTapGesture {
isEditing.toggle()
}
}
}
It's a bit complex, but should get the work done. As for a pure SwiftUI answer, it's currently unavailable.

SwiftUI Searchbar pushed off screen by keyboard

I have implemented a searchbar that filters a list. However when the keyboard appears it pushes the searchbar right off the screen. I have tried using .ignoresSafeArea(.keyboard) however it will not work (I have tried placing it in many different spots). I would like to make it so the view/list does not move at all when the keyboard appears.
I am displaying this view below after pressing a button
//MARK: - ActivitySelectorView
ActivitySelectorView(showActivitySelector: $showActivitySelector, activityToSave: activityToSave, allActivities: activities, categoryNames: categoryNames)
.environmentObject(activityToSave)
.frame(width: screen.width, height: screen.height)
.offset(x: showActivitySelector ? 0 : screen.width)
.offset(y: screen.minY)
.offset(x: viewState.width)
.animation(.easeInOut)
And inside ActivitySelectorView I have a title bar and the filtered list which includes a searchbar and list
var body: some View {
ZStack {
//backgroundColor
Color("\(activityToSave.category)Color")
VStack {
TitleBar(showingAlert: $showingAlert, showActivitySelector: $showActivitySelector, categoryName: categoryNames[(Int(String(activityToSave.category.last!)) ?? 1) - 1])
//MARK: - LIST
FilteredList(filter: activityToSave.category, passedActivityBinding: $activityToSave.activityName, showActivitySelector: $showActivitySelector)
.colorMultiply(Color("\(activityToSave.category)Color"))
}
}
}
Here we have FilteredList:
var body: some View {
List {
SearchBar(text: $searchText)
ForEach(fetchRequest.wrappedValue.filter({ searchText.isEmpty ? true : $0.name.contains(searchText) }), id: \.self) { activity in
Text(activity.name.capitalized)
.onTapGesture {
self.showActivitySelector = false
self.selectedActivity = activity.name.capitalized
}
}.onDelete(perform: deleteActivity)
}
.resignKeyboardOnDragGesture()
}
And last the code for the searchBar
struct SearchBar: UIViewRepresentable {
#Binding var text: String
class Coordinator: NSObject, UISearchBarDelegate {
#Binding var text: String
init(text: Binding<String>) {
_text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
UIApplication.shared.endEditing()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text)
}
func makeUIView(context: Context) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
searchBar.returnKeyType = .done
searchBar.enablesReturnKeyAutomatically = false
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
}

Custom UITextField wrapped in UIViewRepresentable interfering with ObservableObject in NavigationView

Context
I have created a UIViewRepresentable to wrap a UITextField so that:
it can be set it to become the first responder when the view loads.
the next textfield can be set to become the first responder when enter is pressed
Problem
When used inside a NavigationView, unless the keyboard is dismissed from previous views, the view doesn't observe the value in their ObservedObject.
Question
Why is this happening? What can I do to fix this behaviour?
Screenshots
Keyboard from root view not dismissed:
Keyboard from root view dismissed:
Code
Here is the said UIViewRepresentable
struct SimplifiedFocusableTextField: UIViewRepresentable {
#Binding var text: String
private var isResponder: Binding<Bool>?
private var placeholder: String
private var tag: Int
public init(
_ placeholder: String = "",
text: Binding<String>,
isResponder: Binding<Bool>? = nil,
tag: Int = 0
) {
self._text = text
self.placeholder = placeholder
self.isResponder = isResponder
self.tag = tag
}
func makeUIView(context: UIViewRepresentableContext<SimplifiedFocusableTextField>) -> UITextField {
// create textfield
let textField = UITextField()
// set delegate
textField.delegate = context.coordinator
// configure textfield
textField.placeholder = placeholder
textField.setContentHuggingPriority(.defaultHigh, for: .vertical)
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
textField.tag = self.tag
// return
return textField
}
func makeCoordinator() -> SimplifiedFocusableTextField.Coordinator {
return Coordinator(text: $text, isResponder: self.isResponder)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<SimplifiedFocusableTextField>) {
// update text
uiView.text = text
// set first responder ONCE
if self.isResponder?.wrappedValue == true && !uiView.isFirstResponder && !context.coordinator.didBecomeFirstResponder{
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
class Coordinator: NSObject, UITextFieldDelegate {
#Binding var text: String
private var isResponder: Binding<Bool>?
var didBecomeFirstResponder = false
init(text: Binding<String>, isResponder: Binding<Bool>?) {
_text = text
self.isResponder = isResponder
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
func textFieldDidBeginEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.isResponder?.wrappedValue = true
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.isResponder?.wrappedValue = false
}
}
}
}
And to reproduce, here is the contentView:
struct ContentView: View {
var body: some View {
return NavigationView { FieldView(tag: 0) }
}
}
and here's the view with the field and its view model
struct FieldView: View {
#ObservedObject private var viewModel = FieldViewModel()
#State private var focus = false
var tag: Int
var body: some View {
return VStack {
// listen to viewModel's value
Text(viewModel.value)
// text field
SimplifiedFocusableTextField("placeholder", text: self.$viewModel.value, isResponder: $focus, tag: self.tag)
// push to stack
NavigationLink(destination: FieldView(tag: self.tag + 1)) {
Text("Continue")
}
// dummy for tapping to dismiss keyboard
Color.green
}
.onAppear {
self.focus = true
}.dismissKeyboardOnTap()
}
}
public extension View {
func dismissKeyboardOnTap() -> some View {
modifier(DismissKeyboardOnTap())
}
}
public struct DismissKeyboardOnTap: ViewModifier {
public func body(content: Content) -> some View {
return content.gesture(tapGesture)
}
private var tapGesture: some Gesture {
TapGesture().onEnded(endEditing)
}
private func endEditing() {
UIApplication.shared.connectedScenes
.filter {$0.activationState == .foregroundActive}
.map {$0 as? UIWindowScene}
.compactMap({$0})
.first?.windows
.filter {$0.isKeyWindow}
.first?.endEditing(true)
}
}
class FieldViewModel: ObservableObject {
var subscriptions = Set<AnyCancellable>()
// diplays
#Published var value = ""
}
It looks like SwiftUI rendering engine again over-optimized...
Here is fixed part - just make destination unique forcefully using .id. Tested with Xcode 11.4 / iOS 13.4
NavigationLink(destination: FieldView(tag: self.tag + 1).id(UUID())) {
Text("Continue")
}