SwiftUI passing ViewModifier as parameter - swift

I am creating a custom TextField view that consists of multiple adornment views. I want to be able to set up the inner TextField with view modifiers such as keyboard, capitalization, etc. that apply just to that sub-view.
Rather than creating properties for each of these I figured the best way would be to pass in a single optional ViewModifier parameter and use it something like this:
struct MySuperTextField: View {
var vm: ViewModifier?
var body: some View {
TextField(...)
.modifier( vm ?? EmptyModifier() )
// ... more views here
}
}
This doesn't work due to the associatedType in ViewModifier. Alas there is no such thing as AnyViewModifier either (and I could't figure out how to make one that worked).
Anyone manage to do something like this? I couldn't find anything searching the web.
An example would be
struct LastNameModifier: ViewModifier {
func body(content: Content) -> some View {
content
.autocapitalization(.words)
.textContentType(.familyName)
.backgroundColor(.green)
// ... anything else specific to names
}
}
struct EmailModifier: ViewModifier {
func body(content: Content) -> some View {
content
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.backgroundColor(.yellow)
// ... anything else specific to emails
}
}
and then use them with my MySuperTextField like this:
VStack {
MySuperTextField("Last Name", $lastName, vm: LastNameModifier())
MySuperTextField("Email", $email, vm: EmailModifier())
}

If I understood correctly, you can make your MySuperTextField accept a generic parameter:
struct MySuperTextField<V>: View where V: ViewModifier {
private let placeholder: String
#Binding private var text: String
private let vm: V
init(_ placeholder: String, text: Binding<String>, vm: V) {
self.placeholder = placeholder
self._text = text
self.vm = vm
}
var body: some View {
TextField(placeholder, text: $text)
.modifier(vm)
}
}
Then, you can pass some ViewModifier as the parameter:
struct ContentView: View {
#State private var text: String = "Test"
var body: some View {
MySuperTextField("Last Name", text: $text, vm: LastNameModifier())
}
}
If you need a way to skip the vm parameter when creating MySuperTextField:
MySuperTextField("Last Name", text: $text)
you can create an extension:
extension MySuperTextField where V == EmptyModifier {
init(_ placeholder: String, text: Binding<String>) {
self.placeholder = placeholder
self._text = text
self.vm = EmptyModifier()
}
}

Set the ViewModifier up as a struct and just call it on the view. You just have to be specific as to the type, such as this buttonStyle modifier I used:
struct PurchaseButtonStyle: ButtonStyle {
let geometry: GeometryProxy
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(minWidth: 0, idealWidth: 300, maxWidth: .infinity)
.padding(.all, geometry.size.height / 30)
.foregroundColor(.black)
.background(.orange)
.cornerRadius(30)
}
}
The use is:
Button(...)
.buttonStyle(PurchaseButtonStyle(geometry: Geometry))
You just have to write it to be the specific modifier. I just used this because it was handy in an app I was working on.

since ViewModifier has an associated type that you cannot use as an instance variable but I propose you another way of use:
MySuperTextField does not have to maintain instances of the ViewModifier type.
struct MySuperTextField: View {
#State var textValue = ""
var body: some View {
TextField("", text: $textValue)
}
}
For each structure that conforms to the ViewModifier protocol you create an extension:
extension MySuperTextField {
func lastNameModifier() -> some View {
modifier(LastNameModifier())
}
func emailModifier() -> some View {
modifier(EmailModifier())
}
}
and you can use it this way:
struct ContentView : View {
var body: some View {
VStack {
MySuperTextField(textValue: "Last Name")
.lastNameModifier()
MySuperTextField(textValue: "Email")
.emailModifier()
}
}
}

Related

How can I access the parent/Environment of a custom view?

I want to access the parent of my custom view to know whether my view parent is a HStack or VStack, like Divider() could do it. Currently I am hard coding value, but my goal is that I could be get access the parent information inside my custom view to select the right return view.
struct ContentView: View {
var body: some View {
HStack { Divider() }
VStack { Divider() }
HStack { CustomView(parentIsHStack: true) }
VStack { CustomView(parentIsHStack: false) }
}
}
struct CustomView: View {
let parentIsHStack: Bool
var body: some View {
if parentIsHStack {
Text("Parent is HStack")
}
else {
Text("Parent is VStack")
}
}
}
I would be tempted to say this is not a hidden environment variable. I don't see a relevant one when I dump all the environment variables (there are a lot though).
Instead, I believe it's how _VariadicView.Tree works. This contains a root and its content. I'll take how HStack works for example. Inspecting the SwiftUI interface, you can see the following snippet of code:
#frozen public struct HStack<Content> : SwiftUI.View where Content : SwiftUI.View {
#usableFromInline
internal var _tree: SwiftUI._VariadicView.Tree<SwiftUI._HStackLayout, Content>
#inlinable public init(alignment: SwiftUI.VerticalAlignment = .center, spacing: CoreGraphics.CGFloat? = nil, #SwiftUI.ViewBuilder content: () -> Content) {
_tree = .init(
root: _HStackLayout(alignment: alignment, spacing: spacing), content: content())
}
public static func _makeView(view: SwiftUI._GraphValue<SwiftUI.HStack<Content>>, inputs: SwiftUI._ViewInputs) -> SwiftUI._ViewOutputs
public typealias Body = Swift.Never
}
Notice that the Body is of type Never (therefore a primitive view type). The _tree stores information about the layout, and the type HStackLayout obviously shows this is a HStack.
SwiftUI will be using _makeView(view:inputs:) internally to create the view, which I'm assuming gives special treatment to certain views.
You'll need to make custom versions of HStack/VStack and pass an environment variable down to know which kind your subview is in.
I could solve the issue with replacing Apple Stack's, without broking apple api.
struct ContentView: View {
var body: some View {
HStack { Divider() }
VStack { Divider() }
HStack { CustomView() }
VStack { CustomView() }
ZStack { CustomView() }
}
}
struct CustomView: View {
#Environment(\.stack) var stack
var body: some View {
Text("Parent is " + stack.rawValue)
}
}
struct HStack<Content>: View where Content: View {
let alignment: VerticalAlignment
let spacing: CGFloat?
let content: () -> Content
init(alignment: VerticalAlignment = VerticalAlignment.center, spacing: CGFloat? = nil, #ViewBuilder content: #escaping () -> Content) {
self.alignment = alignment
self.spacing = spacing
self.content = content
}
var body: some View {
return SwiftUI.HStack(alignment: alignment, spacing: spacing, content: { content() })
.environment(\.stack, Stack.hStack)
}
}
struct VStack<Content>: View where Content: View {
let alignment: HorizontalAlignment
let spacing: CGFloat?
let content: () -> Content
init(alignment: HorizontalAlignment = HorizontalAlignment.center, spacing: CGFloat? = nil, #ViewBuilder content: #escaping () -> Content) {
self.alignment = alignment
self.spacing = spacing
self.content = content
}
var body: some View {
return SwiftUI.VStack(alignment: alignment, spacing: spacing, content: { content() })
.environment(\.stack, Stack.vStack)
}
}
struct ZStack<Content>: View where Content: View {
let alignment: Alignment
let content: () -> Content
init(alignment: Alignment = Alignment.center, #ViewBuilder content: #escaping () -> Content) {
self.alignment = alignment
self.content = content
}
var body: some View {
return SwiftUI.ZStack(alignment: alignment, content: { content() })
.environment(\.stack, Stack.zStack)
}
}
private struct StackKey: EnvironmentKey { static let defaultValue: Stack = Stack.unknown }
extension EnvironmentValues {
var stack: Stack {
get { return self[StackKey.self] }
set(newValue) { self[StackKey.self] = newValue }
}
}
enum Stack: String { case vStack, hStack, zStack, unknown }

How do I add closures to Viewmodifiers in SwiftUI?

I am using the ClearButton ViewModifier here
.modifier(ClearButton(text: $someBinding))
But I want to run a function after clear textfield. Like this or similar
.modifier(ClearButton(text: $someBinding)) {
print("")
}
Is it possible?
You can pass a function as a parameter like this:
struct ClearButton: ViewModifier {
#Binding var text: String
var action: () -> Void = {} // pass the function here
public func body(content: Content) -> some View {
ZStack(alignment: .trailing) {
content
if !text.isEmpty {
Button(action: {
self.text = ""
action() // call the `action` here
}) {
Image(systemName: "delete.left")
.foregroundColor(Color(UIColor.opaqueSeparator))
}
.padding(.trailing, 8)
}
}
}
}
and apply this modifier to your TextField:
struct ContentView: View {
#State private var text = ""
var body: some View {
TextField("Some Text", text: $text)
.modifier(
ClearButton(text: $text) {
print("TextField cleared")
}
)
}
}
Note that if you want to skip the label for the trailing closure, the action parameter must come last.

SwiftUI. How to change the placeholder color of the TextField?

I want to change the placeholder color of the TextField, but I can't find a method for it.
I tried to set foregroundColor and accentColor, but it doesn't change the placeholder color.
Here is the code:
TextField("Placeholder", $text)
.foregroundColor(Color.red)
.accentColor(Color.green)
Maybe there is no API for this yet?
There is no api for it (yet). BUT YOU CAN:
Use a custom placeholder modifier to show any view as the holder of any other view! e.g:
TextField("", text: $text)
.placeholder(when: text.isEmpty) {
Text("Placeholder recreated").foregroundColor(.gray)
}
💡 It's a simple ZStack that you can in a View extension like:
extension View {
func placeholder<Content: View>(
when shouldShow: Bool,
alignment: Alignment = .leading,
#ViewBuilder placeholder: () -> Content) -> some View {
ZStack(alignment: alignment) {
placeholder().opacity(shouldShow ? 1 : 0)
self
}
}
}
🎁 Now you can apply any kind of style to the placeholder like this gradient placeholder with image:
✅ If you are interested, Here is how to apply resizable gradient on any view
💡 The Art of the simplicity
Most of the time you need to pass just a string and a gray placeholder like:
TextField("", text: $text)
.placeholder("Placeholder", when: text.isEmpty)
you can write a simple wrapper around the above extension for it:
extension View {
func placeholder(
_ text: String,
when shouldShow: Bool,
alignment: Alignment = .leading) -> some View {
placeholder(when: shouldShow, alignment: alignment) { Text(text).foregroundColor(.gray) }
}
}
Just like that 😉
Eventually a ViewModifier that embeds the content in a ZStack is more elegant and less code:
public struct PlaceholderStyle: ViewModifier {
var showPlaceHolder: Bool
var placeholder: String
public func body(content: Content) -> some View {
ZStack(alignment: .leading) {
if showPlaceHolder {
Text(placeholder)
.padding(.horizontal, 15)
}
content
.foregroundColor(Color.white)
.padding(5.0)
}
}
}
Usage:
TextField("", text: $data)
.modifier(PlaceholderStyle(showPlaceHolder: data.isEmpty,
placeholder: "My Placeholder"))
It's a bit modification for the #jfk's answer, we can create an extension for view to simplify the modifier code inside the main view and also it can be used for Text and Image.
struct PlaceHolder<T: View>: ViewModifier {
var placeHolder: T
var show: Bool
func body(content: Content) -> some View {
ZStack(alignment: .leading) {
if show { placeHolder }
content
}
}
}
extension View {
func placeHolder<T:View>(_ holder: T, show: Bool) -> some View {
self.modifier(PlaceHolder(placeHolder:holder, show: show))
}
}
Usage in TextField:
Add this line of code .placeHolder(Text("Your placeholder"), show: text.isEmpty) as a viewModifier to TextField.
TextField("", text: $text, onEditingChanged: { (changing) in
print("Changing: \(changing)")
}, onCommit: {
print("Committed!")
})
.placeHolder(Text("Your placeholder"), show: text.isEmpty)
Usage in Image:
Further more, as #EmilioPelaez suggested, I modified the code to support placeholder for any view for ex. Image like below.
Image("your_image")
.placeHolder(Image("placeholder_image"), show: true)
Super easy solution
We can substitute TextField's placeholder with another Text's string.
So, we can control a color of a fake "placeholder".
struct ContentView: View {
#State private var text: String = ""
var body: some View {
ZStack(alignment: .leading) {
if text.isEmpty {
Text("Type Here")
.foregroundColor(.red.opacity(0.4))
.font(.system(size: 50))
}
TextField("", text: $text)
.font(.system(size: 50))
}
.padding(20)
}
}
On iOS 15, you can use prompt
public init(text: Binding<String>, prompt: Text? = nil, #ViewBuilder label: () -> Label)
Which works as a placeholder view
For iOS 16.0 and above
TextField("", text: $viewModel.userName, prompt: Text("Phone, email or username").foregroundColor(.gray))
If you want to preserve the original TextField and you don't mind adding Introspect to your project (https://github.com/siteline/SwiftUI-Introspect), you can do it by accessing the UIKit attributedPlaceholder:
TextField("Email", text: $email)
.introspectTextField { uiTextField in
uiTextField.attributedPlaceholder = NSAttributedString(string: "placeholder text",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])
}
Changing the Placeholder text color of a TextField:
https://medium.com/app-makers/how-to-use-textfield-in-swiftui-2fc0ca00f75b
struct SuperTextField: View {
var placeholder: Text
#Binding var text: String
var editingChanged: (Bool)->() = { _ in }
var commit: ()->() = { }
var body: some View {
ZStack(alignment: .leading) {
if text.isEmpty { placeholder }
TextField("", text: $text, onEditingChanged: editingChanged, onCommit: commit)
}
} }
and usage
#State var text: String = "TextField Text"
var body: some View {
SuperTextField(
placeholder: Text("Placeholder Text").foregroundColor(.red),
text: $text
)
}

How to pass one SwiftUI View as a variable to another View struct

I'm implementing a very custom NavigationLink called MenuItem and would like to reuse it across the project. It's a struct that conforms to View and implements var body : some View which contains a NavigationLink.
I need to somehow store the view that shall be presented by NavigationLink in the body of MenuItem but have yet failed to do so.
I have defined destinationView in MenuItem's body as some View and tried two initializers:
This seemed too easy:
struct MenuItem: View {
private var destinationView: some View
init(destinationView: View) {
self.destinationView = destinationView
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> Error: Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements.
2nd try:
struct MenuItem: View {
private var destinationView: some View
init<V>(destinationView: V) where V: View {
self.destinationView = destinationView
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> Error: Cannot assign value of type 'V' to type 'some View'.
Final try:
struct MenuItem: View {
private var destinationView: some View
init<V>(destinationView: V) where V: View {
self.destinationView = destinationView as View
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> Error: Cannot assign value of type 'View' to type 'some View'.
I hope someone can help me. There must be a way if NavigationLink can accept some View as an argument.
Thanks ;D
To sum up everything I read here and the solution which worked for me:
struct ContainerView<Content: View>: View {
#ViewBuilder var content: Content
var body: some View {
content
}
}
This not only allows you to put simple Views inside, but also, thanks to #ViewBuilder, use if-else and switch-case blocks:
struct SimpleView: View {
var body: some View {
ContainerView {
Text("SimpleView Text")
}
}
}
struct IfElseView: View {
var flag = true
var body: some View {
ContainerView {
if flag {
Text("True text")
} else {
Text("False text")
}
}
}
}
struct SwitchCaseView: View {
var condition = 1
var body: some View {
ContainerView {
switch condition {
case 1:
Text("One")
case 2:
Text("Two")
default:
Text("Default")
}
}
}
}
Bonus:
If you want a greedy container, which will claim all the possible space (in contrary to the container above which claims only the space needed for its subviews) here it is:
struct GreedyContainerView<Content: View>: View {
#ViewBuilder let content: Content
var body: some View {
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
If you need an initializer in your view then you can use #ViewBuilder for the parameter too. Even for multiple parameters if you will:
init(#ViewBuilder content: () -> Content) {…}
The way Apple does it is using function builders. There is a predefined one called ViewBuilder. Make it the last argument, or only argument, of your init method for MenuItem, like so:
..., #ViewBuilder builder: #escaping () -> Content)
Assign it to a property defined something like this:
let viewBuilder: () -> Content
Then, where you want to diplay your passed-in views, just call the function like this:
HStack {
viewBuilder()
}
You will be able to use your new view like this:
MenuItem {
Image("myImage")
Text("My Text")
}
This will let you pass up to 10 views and use if conditions etc. though if you want it to be more restrictive you will have to define your own function builder. I haven't done that so you will have to google that.
You should make the generic parameter part of MenuItem:
struct MenuItem<Content: View>: View {
private var destinationView: Content
init(destinationView: Content) {
self.destinationView = destinationView
}
var body : some View {
// ...
}
}
You can create your custom view like this:
struct ENavigationView<Content: View>: View {
let viewBuilder: () -> Content
var body: some View {
NavigationView {
VStack {
viewBuilder()
.navigationBarTitle("My App")
}
}
}
}
struct ENavigationView_Previews: PreviewProvider {
static var previews: some View {
ENavigationView {
Text("Preview")
}
}
}
Using:
struct ContentView: View {
var body: some View {
ENavigationView {
Text("My Text")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You can pass a NavigationLink (or any other view widget) as a variable to a subview as follows:
import SwiftUI
struct ParentView: View {
var body: some View {
NavigationView{
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
}
struct ChildView<Content: View>: View {
var destinationView: Content
var title: String
init(destinationView: Content, title: String) {
self.destinationView = destinationView
self.title = title
}
var body: some View {
NavigationLink(destination: destinationView){
Text("This item opens the \(title) view").foregroundColor(Color.black)
}
}
}
struct ThirdView: View {
var body: some View {
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
The accepted answer is nice and simple. The syntax got even cleaner with iOS 14 + macOS 11:
struct ContainerView<Content: View>: View {
#ViewBuilder var content: Content
var body: some View {
content
}
}
Then continue to use it like this:
ContainerView{
...
}
I really struggled to make mine work for an extension of View. Full details about how to call it are seen here.
The extension for View (using generics) - remember to import SwiftUI:
extension View {
/// Navigate to a new view.
/// - Parameters:
/// - view: View to navigate to.
/// - binding: Only navigates when this condition is `true`.
func navigate<SomeView: View>(to view: SomeView, when binding: Binding<Bool>) -> some View {
modifier(NavigateModifier(destination: view, binding: binding))
}
}
// MARK: - NavigateModifier
fileprivate struct NavigateModifier<SomeView: View>: ViewModifier {
// MARK: Private properties
fileprivate let destination: SomeView
#Binding fileprivate var binding: Bool
// MARK: - View body
fileprivate func body(content: Content) -> some View {
NavigationView {
ZStack {
content
.navigationBarTitle("")
.navigationBarHidden(true)
NavigationLink(destination: destination
.navigationBarTitle("")
.navigationBarHidden(true),
isActive: $binding) {
EmptyView()
}
}
}
}
}
Alternatively you can use a static function extension. For example, I make a titleBar extension to Text. This makes it very easy to reuse code.
In this case you can pass a #Viewbuilder wrapper with the view closure returning a custom type that conforms to view. For example:
import SwiftUI
extension Text{
static func titleBar<Content:View>(
titleString:String,
#ViewBuilder customIcon: ()-> Content
)->some View {
HStack{
customIcon()
Spacer()
Text(titleString)
.font(.title)
Spacer()
}
}
}
struct Text_Title_swift_Previews: PreviewProvider {
static var previews: some View {
Text.titleBar(titleString: "title",customIcon: {
Image(systemName: "arrowshape.turn.up.backward")
})
.previewLayout(.sizeThatFits)
}
}
If anyone is trying to pass two different views to other view, and can't do it because of this error:
Failed to produce diagnostic for expression; please submit a bug report...
Because we are using <Content: View>, the first view you passed, the view is going to store its type, and expect the second view you are passing be the same type, this way, if you want to pass a Text and an Image, you will not be able to.
The solution is simple, add another content view, and name it differently.
Example:
struct Collapsible<Title: View, Content: View>: View {
#State var title: () -> Title
#State var content: () -> Content
#State private var collapsed: Bool = true
var body: some View {
VStack {
Button(
action: { self.collapsed.toggle() },
label: {
HStack {
self.title()
Spacer()
Image(systemName: self.collapsed ? "chevron.down" : "chevron.up")
}
.padding(.bottom, 1)
.background(Color.white.opacity(0.01))
}
)
.buttonStyle(PlainButtonStyle())
VStack {
self.content()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: collapsed ? 0 : .none)
.clipped()
.animation(.easeOut)
.transition(.slide)
}
}
}
Calling this View:
Collapsible {
Text("Collapsible")
} content: {
ForEach(1..<5) { index in
Text("\(index) test")
}
}
Syntax for 2 Views
struct PopOver<Content, PopView> : View where Content: View, PopView: View {
var isShowing: Bool
#ViewBuilder var content: () -> Content
#ViewBuilder var popover: () -> PopView
var body: some View {
ZStack(alignment: .center) {
self
.content()
.disabled(isShowing)
.blur(radius: isShowing ? 3 : 0)
ZStack {
self.popover()
}
.frame(width: 112, height: 112)
.opacity(isShowing ? 1 : 0)
.disabled(!isShowing)
}
}
}

SwiftUI TextField Simple Example not working

I tried to create a very simple TextField in SwiftUI but I cannot get it to work and I don't understand what I am doing wrong.
Xcode gives me an error message that says:
"Unable to infer complex closure return type; add explicit type to disambiguate."
I am not sure what to do. I found some other code examples for TextFields with SwiftUI on StackOverflow but keep getting the same error.
struct TextFieldExample : View {
#State var email: String = "Enter email address"
var body: some View {
VStack {
TextField($email)
Text("Your email is \(email)!")
}
}
}
struct ButtonTextField : View {
#State var text: String = ""
var body: some View {
HStack {
TextField($text,
placeholder: Text("type something here..."))
Button(action: {
// Closure will be called once user taps your button
print(self.$text)
}) {
Text("SEND")
}
}
}
}
Expected results = working TextField
Actual result = Error in Xcode
It seems the TextField view has been changed in a recent beta release. You should be able to create one using something like this:
struct MyView {
#State var myInput: String = ""
var body: some View {
TextField("placeholder text", text: $myInput)
}
}
In the recent beta release of Xcode TextField has been changed.
#State var email: String = ""
var body: some View {
TextField("Email", text: $email, onEditingChanged: { (isChanges) in
// On Editing Changed
}) {
// On Commit
}
.padding(.leading, 13).padding(.trailing, 13).padding(.top, UIScreen.main.bounds.size.height / 2)
.textContentType(.emailAddress)
.textFieldStyle(RoundedBorderTextFieldStyle.init())
}
First of all do you really need to combine these Views into a custom view? If yes than:
#State and BindableObject should be passed into the view to the property marked with #Binding keyword
Don't use the same name as some of the native classes have
struct MyTextField : View {
#Binding var email: String
var body: some View {
VStack {
Text("Your email is \(email)!")
TextField($email, placeholder: Text("Enter your email"))
}
}
}
Call it like this
#State private var email: String = ""
var body: some View {
MyTextField(email: $email)
}
TextField like SearchView - XCODE 11.3
struct SearchBarV: View {
#State var text: String = ""
var onEditingChanged: (Bool) -> Void = { _ in }
var onCommit: () -> Void = { }
var body: some View {
GeometryReader { metrics in
TextField("placeholder", text: self.$text, onEditingChanged: self.onEditingChanged, onCommit: self.onCommit)
.background(Color.gray.opacity(0.1))
.padding(EdgeInsets(top: 0.0, leading: 16.0, bottom: 0, trailing: 16.0))
.frame(width: metrics.size.width, height: 50)
.keyboardType(.emailAddress)
}
}
}
struct SearchBarV_Previews : PreviewProvider {
static var previews: some View {
SearchBarV()
}
}