CustomText in Swift UI - swiftui

I need to make custom text in swift UI, I know I can make extension and do something like this :
Text("ABCD")
.HeadingXLargeStyle()
extension Text{
func HeadingXLargeStyle() -> some View{
self.font( .custom("nunito_regular", size: 80))
}
}
BUT I want to do something like this:
HeadingXLargeStyle("ABCD")
//I tried this
final class HeadingXLarge: UIViewRepresentable{
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = newtext
}
var newtext: String
init(_ text: String){
newtext = text
}
typealias UIViewType = UITextView
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.font = UIFont(name: "inter_bold.ttf", size: 40)
return textView
}
}
but not working.

For a custom text view, you can simply create one View that has a string property to display text like this.
struct CustomText: View {
let text: String
var body: some View {
Text(text)
.font(.custom("nunito_regular", size: 80))
}
}
If you want to access UITextView from SwiftUI you need to create a struct that confirms to protocol UIViewRepresentable, not a class.
struct TextView: UIViewRepresentable {
#Binding var text: String
func makeUIView(context: Context) -> UITextView {
UITextView()
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
}
}
Now access the above TextView like this.
struct ContentView: View {
#State var text = ""
var body: some View {
TextView(text: $text)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}

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 do I change the height of this UIViewRepresentable?

I found this code on the web :
struct CustomTextField: UIViewRepresentable {
#Binding var text: String
#State var placeholder: String
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
func makeUIView(context: Context) -> UITextField {
let textField = UITextField()
textField.borderStyle = .roundedRect
textField.placeholder = placeholder
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.spellCheckingType = .no
textField.keyboardType = .URL
textField.frame = CGRect(x: 0, y: 0, width: 20.00, height: 10)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ view: UITextField, context: Context) {
view.text = text
}
}
extension CustomTextField {
class Coordinator: NSObject, UITextFieldDelegate {
#Binding var text: String
init(text: Binding<String>) {
_text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
DispatchQueue.main.async {
self.text = textField.text ?? ""
}
}
}
}
The code works absolutely fine. The problem with this is that I am not able to find a suitable way to increase the height of this. As you can see, I tried to use a CGRect as the frame, to no effect. How can I change the size (particularly height in my specific scenario) of this custom UIViewRepresentable?
Just the same you would do with any other SwiftUI view:
CustomTextField(text: $text, placeholder: "")
// constant
.frame(height: 100)
// fill available height
.frame(maxHeight: .infinity)
If you wanna make it respect intrinsicContentSize, check out this answer

Expand NSViewRepresentable (NSTextView) height based on window height

I created an NSViewRepresentable structure that manages the state of an NSTextView. The view, by default, only has one line and I'd like to extend that to the edge of the window.
The view is defined as such:
struct Editor: View, NSViewRepresentable {
#Binding var text: String
func makeNSView(context: Context) -> NSTextView {
let view = NSTextView()
view.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
return view
}
func updateNSView(_ view: NSTextView, context: Context) {
let attributedText = NSMutableAttributedString(string: text)
view.textStorage?.setAttributedString(attributedText)
}
}
It currently looks like this, it adds lines as you go. Is there a way for the darker text area to be expanded to the bottom of the window automatically?
You can use NSTextView.scrollableTextView() to do this:
struct ContentView : View {
#State var text = ""
var body: some View {
VStack {
Editor(text: $text)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct Editor: View, NSViewRepresentable {
#Binding var text: String
func makeNSView(context: Context) -> NSView {
let scrollView = NSTextView.scrollableTextView()
guard let textView = scrollView.documentView as? NSTextView else {
return scrollView
}
textView.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
context.coordinator.textView = textView
return scrollView
}
func updateNSView(_ view: NSView, context: Context) {
let attributedText = NSMutableAttributedString(string: text)
context.coordinator.textView?.textStorage?.setAttributedString(attributedText)
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator {
var textView : NSTextView?
}
}

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
}
}

SwiftUI not refresh my custom UIView with UIViewRepresentable & ObservableObject

I have
created a simple ARClass: ObservableObject with #Published var name: String
created a custom ARView: UIView that receives ARClass as a
parameter and draws a Text view displaying ARClass.name in the center
created UIViewRepresentable
and then used in SwiftUI View by using ARClass(color: .red, name: "Test Text") as an environment object in SceneDelegate
class ARClass: ObservableObject {
#Published var bg: UIColor
#Published var name: String
init(color: UIColor, name: String) {
self.bg = color
self.name = name
}
}
struct ARViewX: UIViewRepresentable {
var ar: ARClass
var frame: CGRect
func updateUIView(_ uiView: ARView, context: Context) {
uiView.frame = frame
uiView.ar = ar
uiView.setNeedsDisplay()
}
func makeUIView(context: Context) -> ARView {
ARView(ar: ar, frame: frame)
}
}
struct ContentView: View {
#EnvironmentObject var ar: ARClass
var body: some View {
GeometryReader { g in
VStack {
Spacer()
ARViewX(ar: self.ar, frame: CGRect(origin: .zero, size: .init(width: g.size.width, height: g.size.height/3)))
.padding()
Spacer()
Text(self.ar.name)
Divider()
TextField("Name", text: self.$ar.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Spacer()
}
}
}
}
As I edited the TextField, the whole body is refreshed except the UIViewRepresentable. It always resets the 'name' variable to its initial value.
After hours finally I know that the updateUIView(_ uiView: ARView, context: Context) in UIViewRepresentable never got called so I modified the ARClass like this:
class ARClass: ObservableObject {
#Published var bg: UIColor
#Published var name: String {
didSet {
if let onNameChange = onNameChange {
onNameChange()
}
}
}
var onNameChange: (()->Void)?
init(color: UIColor, name: String) {
self.bg = color
self.name = name
}
}
And the UIViewRepresentable like this:
func updateUIView(_ uiView: ARView, context: Context) {
uiView.frame = frame
ar.onNameChange = {
uiView.setNeedsDisplay()
}
}