I like to make a default style for my textfields. But some parts should be customizable from the view.
I be sure that I use not the correct way, because I got a error:
struct MaxTextFieldStyle: TextFieldStyle {
#State var icon: Image?
#State var framesize: Int = 0
func _body(configuration: TextField<Self._Label>) -> some View {
HStack {
if icon != nil {
icon
.foregroundColor(Color(UIColor.systemGray4))
}
configuration
}
.padding()
.overlay {
RoundedRectangle(cornerRadius: 8, style: .continuous)
.stroke(Color(UIColor.systemGray4), lineWidth: 2)
}
if(framesize > 0) { .frame(width: framesize) }
.frame(maxWidth: .infinity, alignment: .trailing)
.keyboardType(.decimalPad)
}
}
How can I add, that if be a framesize bigger then 0, that it would added?
Extracting the majority of the custom View into a function makes it easy to implement what you are asking for.
struct MaxTextFieldStyle: TextFieldStyle {
#State var icon: Image?
#State var framesize: Int = 0
func _body(configuration: TextField<Self._Label>) -> some View {
if(framesize > 0) {
makeView(configuration)
.frame(width: framesize)
.keyboardType(.decimalPad)
} else {
makeView(configuration)
.frame(maxWidth: .infinity, alignment: .trailing)
.keyboardType(.decimalPad)
}
}
func makeView(_ configuration: TextField<Self._Label>): some View {
HStack {
if icon != nil {
icon
.foregroundColor(Color(UIColor.systemGray4))
}
configuration
}
.padding()
.overlay {
RoundedRectangle(cornerRadius: 8, style: .continuous)
.stroke(Color(UIColor.systemGray4), lineWidth: 2)
}
}
}
Related
I want to recreate system picker behavioral with two options in wheels with SwiftUI and faced ton of problem. Some of this I solved but some still unsolved. I have pop-ups with different views inside. One of the view it's a DatePicker with displayedComponents: .hourAndMinute. And other one is two Pickers inside HStack. My question is how to make Pickers make look like in system: without white spacing between?
struct MultyPicker: View {
#State var value = 1
#State var value2 = 1
var body: some View {
ZStack(alignment: .bottom) {
Color.black.opacity(0.5)
ZStack {
VStack {
Text("Header")
.font(.title3)
.fontWeight(.bold)
HStack(spacing: 0) {
Picker(selection: $value, label: Text("")) {
ForEach(1..<26) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
Picker(selection: $value2, label: Text("")) {
ForEach(25..<76) { number in
Text("\(number)")
.tag("\(number)")
}
}
.pickerStyle(WheelPickerStyle())
.compositingGroup()
.clipped(antialiased: true)
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 34)
.foregroundColor(.white)
)
}
.padding(.horizontal)
.padding(.bottom, 50)
}
.edgesIgnoringSafeArea([.top, .horizontal])
}
}
// This extension for correct touching area
extension UIPickerView {
open override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: super.intrinsicContentSize.height)
}
}
Want to achive looks like that with one grey line in selected value
//
// Test2.swift
// Test
//
// Created by Serdar Onur KARADAĞ on 26.08.2022.
//
import SwiftUI
struct Test2: View {
#State var choice1 = 0
#State var choice2 = 0
var body: some View {
ZStack {
Rectangle()
.fill(.gray.opacity(0.2))
.cornerRadius(30)
.frame(width: 350, height: 400)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("HEADER")
HStack(spacing: 0) {
Picker(selection: $choice1, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
Picker(selection: $choice2, label: Text("C1")) {
ForEach(0..<10) { n in
Text("\(n)").tag(n)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.clipped()
}
}
}
}
}
struct Test2_Previews: PreviewProvider {
static var previews: some View {
Test2()
}
}
SwiftUI multi-component Picker basically consists of several individual Picker views arranged horizontally. Therefore, we start by creating an ordinary Picker view for our first component. I am using Xcode version 13.4.1(iOS 15.0).
import SwiftUI
struct ContentView: View {
#State var hourSelect = 0
#State var minuteSelect = 0
var hours = [Int](0..<24)
var minutes = [Int](0..<60)
var body: some View {
ZStack {
Color.black
.opacity(0.5)
.ignoresSafeArea()
.preferredColorScheme(.light)
Rectangle()
.fill(.white.opacity(1))
.cornerRadius(30)
.frame(width: 300, height: 350)
VStack {
Text("Header")
HStack(spacing: 0) {
Picker(selection: $hourSelect, label: Text("")) {
ForEach(0..<self.hours.count) { index in
Text("\(self.hours[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
Picker(selection: $minuteSelect, label: Text("")) {
ForEach(0..<self.minutes.count) { index in
Text("\(self.minutes[index])").tag(index)
}
}
.pickerStyle(.wheel)
.frame(minWidth: 0)
.compositingGroup()
.clipped()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Output :
When I make dropdown list menu in SwiftUi, dropdown list shows behind of other Component View, I've tried to zIndex(1) at the last of the VStack, and I've tried .overlay at the top of the Stack but it didn't solve my problem, I've shared below code and I've shared screenshot of the problem, how can I solve this problem? thanks...
import SwiftUI
struct DropdownOption: Hashable {
let key: String
let value: String
public static func == (lhs: DropdownOption, rhs: DropdownOption) -> Bool {
return lhs.key == rhs.key
}
}
struct DropdownRow: View {
var option: DropdownOption
var onOptionSelected: ((_ option: DropdownOption) -> Void)?
var body: some View {
Button(action: {
if let onOptionSelected = self.onOptionSelected {
onOptionSelected(self.option)
}
}) {
HStack {
Text(self.option.value)
.font(.system(size: 14))
.foregroundColor(Color.black)
Spacer()
}
}
.padding(.horizontal, 16)
.padding(.vertical, 5)
}
}
struct Dropdown: View {
var options: [DropdownOption]
var onOptionSelected: ((_ option: DropdownOption) -> Void)?
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
ForEach(self.options, id: \.self) { option in
DropdownRow(option: option, onOptionSelected: self.onOptionSelected)
}
}
}
.frame(minHeight: CGFloat(options.count) * 30, maxHeight: 250)
.padding(.vertical, 5)
.background(Color.white)
.cornerRadius(5)
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.gray, lineWidth: 1)
)
}
}
struct DropdownSelector: View {
#State private var shouldShowDropdown = false
#State private var selectedOption: DropdownOption? = nil
var placeholder: String
var options: [DropdownOption]
var onOptionSelected: ((_ option: DropdownOption) -> Void)?
private let buttonHeight: CGFloat = 45
var body: some View {
Button(action: {
self.shouldShowDropdown.toggle()
}) {
HStack {
Text(selectedOption == nil ? placeholder : selectedOption!.value)
.font(.system(size: 14))
.foregroundColor(selectedOption == nil ? Color.gray: Color.black)
Spacer()
Image(systemName: self.shouldShowDropdown ? "arrowtriangle.up.fill" : "arrowtriangle.down.fill")
.resizable()
.frame(width: 9, height: 5)
.font(Font.system(size: 9, weight: .medium))
.foregroundColor(Color.black)
}
}
.padding(.horizontal)
.cornerRadius(5)
.frame(width: .infinity, height: self.buttonHeight)
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.gray, lineWidth: 1)
)
.overlay(
VStack {
if self.shouldShowDropdown {
Spacer(minLength: buttonHeight + 10)
Dropdown(options: self.options, onOptionSelected: { option in
shouldShowDropdown = false
selectedOption = option
self.onOptionSelected?(option)
})
}
}, alignment: .topLeading
)
.background(
RoundedRectangle(cornerRadius: 5).fill(Color.white)
)
}
}
calling DropDownList
ZStack(alignment:.top){
HStack {
Group {
DropdownSelector(
placeholder: "Choose Aircraft Type",
options: options,
onOptionSelected: { option in
print(option)
})
.padding(.horizontal)
}
}.padding(.top, 50)
HStack {
Group {
DropdownSelector(
placeholder: "Choose Simulator Type",
options: optionsSimulator,
onOptionSelected: { option in
print(option)
})
.padding(.horizontal)
}
}.padding(.top, 50)
}
I have a messaging interface. When user types in to the texteditor it will be append to messagesDBArray and will be displayed in textview. Once new messages are there it should scroll to the bottom. But I'm having issues.
Errors: no errors
RoundedRectangle background colour green overflows from corners (does not crop as rounded)
TextEditor (not textview) is not transparent (so it can have rounded rectangle color underneath)
proxy.scrollTo(id, anchor: .bottom) does not scrolls to the last message.
import SwiftUI
final class ViewModel: ObservableObject {
#Published var messagesDBArray : [SingleMessageBubbleModel] = []
}
struct SingleMessageBubbleModel: Identifiable {
let id = UUID()
var text: String
var received: Bool
var timeStamp: Date
}
var messagesDBArray : [SingleMessageBubbleModel] = []
struct ContentView: View {
#ObservedObject private var messageArrayObservedObject = ViewModel()
#State private var showOnTheSpotMessaging: Bool = true
#State var textTyped: String = ""
var body: some View {
VStack (alignment: .center) {
ZStack (alignment: .center) {
HStack () {
RoundedRectangle(cornerRadius: 25, style: .continuous)
.stroke(Color.brown, lineWidth: 1)
.frame(width: 300, alignment: Alignment.top )
.padding([.bottom], 5)
.clipped()
.background(Color.green)
}
HStack () {
ScrollViewReader { proxy in
ScrollView {
LazyVStack {
ForEach(
messageArrayObservedObject.messagesDBArray,
id: \.id
) {
message in MessageBubble(message: message)
}
}
}
.frame(alignment: .center)
.background(Color.clear)
.padding (.vertical, 5)
.padding (.horizontal,5)
.padding(.bottom, 5)
.onChange(
of: messageArrayObservedObject.messagesDBArray.count
) { id in
// When the lastMessageId changes, scroll to the bottom of the conversation
withAnimation {
proxy.scrollTo(id, anchor: .bottom)
}
}
}
.frame( height: 200, alignment: .center)
}
.frame(width: 295, alignment: Alignment.center )
}
HStack () {
VStack {
ZStack (alignment: .center) {
HStack () {
RoundedRectangle(cornerRadius: 25, style: .continuous)
.stroke(Color.brown , lineWidth: 1)
.frame(width: 295, alignment: Alignment.top )
.padding([.bottom], 5)
.clipped()
.background(Color.green)
// .background(Color("#E5F2E4"))
}
HStack () {
TextEditor (text: $textTyped)
.frame(height: 200, alignment: .leading)
.padding(.horizontal, 10)
.background(.clear)
}
}
.frame(width: 290, alignment: Alignment.top )
.padding(.top, 5)
}
}
}
}
struct MessageBubble: View {
var message: SingleMessageBubbleModel
#State private var showTime = false
var body: some View {
VStack(alignment: message.received ? .leading : .trailing) {
HStack {
Text(message.text)
.padding()
.background(message.received ? Color.gray : Color.blue)
.cornerRadius(30)
}
.frame(maxWidth: 300, alignment: message.received ? .leading : .trailing)
.onTapGesture {
withAnimation {
showTime.toggle()
}
}
}
.frame(maxWidth: .infinity, alignment: message.received ? .leading : .trailing)
.padding(message.received ? .leading : .trailing)
.padding(.horizontal, 4)
}
}
for the first error you should use that code instead of your code where you make a background with RoundRectangle the same to your base rectangle and make the fill of that the color you want which is green
RoundedRectangle(cornerRadius: 25, style: .continuous)
.stroke(Color.brown, lineWidth: 1).background(RoundedRectangle(cornerRadius: 25).fill(Color.green))
.frame(width: 300, alignment: Alignment.top )
.padding([.bottom], 5)
.clipped()
the second issue in your ContentView you should init your UITextView background color to clear and after that make your textEditor Color clear using that code
init() {
UITextView.appearance().backgroundColor = .clear
}
and make your textEditor background clear
TextEditor (text: $textTyped)
.frame(height: 200, alignment: .leading)
.padding(.horizontal, 10)
.background(Color.clear)
and the third issue is that i think you are using the array count but you should use the id of each message so when if we suppose that the last message-id is 728398 in your onChange
onChange(of: messageArrayObservedObject.messagesDBArray.count) { id in
// When the lastMessageId changes, scroll to the bottom of the conversation
withAnimation {
print("ididididid\(id)")
proxy.scrollTo(messageArrayObservedObject.messagesDBArray.last, anchor: .bottom)
}
}
your are using the ( messageArrayObservedObject.messagesDBArray.count )counts of messages like 5 message so you are scrolling to 5 not to the id of message which is 728398
I am currently having trouble with my Custom Tab Bar there is a gray area above it (Tab View) that controls each tab but I need that to go under my custom tab bar but functionality of the TabView still be in effect and be used with the icons. You can hide the Tab bar with UITabBar.apperance() which gets rid of the gray area but no longer has any functions.. but I need that gray area to go under the tabs. If that makes sense?
Home.swift
import SwiftUI
struct Home: View {
//Hiding Tab Bar..
init() {
UITabBar.appearance().isHidden = false
}
var body: some View {
VStack(spacing: 0){
//Tab View...
TabView{
Color.blue
.tag("house.circle")
Color.green
.tag("pencil")
Color.pink
.tag("magnifyingglass")
Color.red
.tag("bell")
Color.yellow
.tag("cart")
}
//Custom Tab Bar...
CustomTabBar()
}
.ignoresSafeArea()
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
//Extending View To Get Screen Frame...
extension View {
func getRect()->CGRect {
return UIScreen.main.bounds
}
}
CustomTabBar.swift
import SwiftUI
struct CustomTabBar: View {
var body: some View {
HStack(spacing: 0){
// Tab Bar Button...
TabBarButton(systemName: "house.circle")
.background(Color.blue)
TabBarButton(systemName: "pencil")
.background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(systemName: "bell")
.background(Color.red)
TabBarButton(systemName: "cart")
.background(Color.yellow)
}
.padding(.top)
//Decreasing the extra padding added...
.padding(.vertical, -0)
.padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
.background(Color.white)
}
}
struct CustomTabBar_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}
}
}
//extending view to get safe area...
extension View {
func getSafeArea()-> UIEdgeInsets {
return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
struct TabBarButton: View {
var systemName: String
var body: some View{
Button(action: {
}, label: {
VStack(spacing: 8){
Image(systemName)
.resizable()
//Since its asset image...
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:28, height: 28)
}
.frame(maxWidth: .infinity)
})
}
}
EDIT: SECOND IMAGE I am hiding the tab bar setting it to true instead of false.
//Hiding Tab Bar..
init() {
UITabBar.appearance().isHidden = true
}
you could try this to "cover" the original TabView bar:
In Home replace VStack with ZStack.
and
struct CustomTabBar: View {
var body: some View {
VStack (alignment: .leading) {
Spacer()
HStack(spacing: 0) {
TabBarButton(systemName: "house.circle").background(Color.blue)
TabBarButton(systemName: "pencil").background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(systemName: "bell").background(Color.red)
TabBarButton(systemName: "cart").background(Color.yellow)
}
}
.padding(.bottom, getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
.background(Color.white)
}
}
you will then need to implement the action of each of your CustomTabBar buttons.
EDIT1:
ok, as I mentioned you need to implement the actions for your buttons.
There are many ways to do this, this is just one approach:
struct CustomTabBar: View {
#Binding var tagSelect: String
var body: some View {
VStack (alignment: .leading) {
Spacer()
HStack(spacing: 0) {
TabBarButton(tagSelect: $tagSelect, systemName: "house.circle").background(Color.blue)
TabBarButton(tagSelect: $tagSelect, systemName: "pencil").background(Color.green)
Button(action: {}, label: {
Image(systemName: "magnifyingglass")
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:24, height:24)
.foregroundColor(.white)
.padding(20)
.background(Color.green)
.clipShape(Circle())
//Shadows
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
})
.tag("magnifyingglass")
TabBarButton(tagSelect: $tagSelect, systemName: "bell").background(Color.red)
TabBarButton(tagSelect: $tagSelect, systemName: "cart").background(Color.yellow)
}
}
.padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
// no background or use opacity, like this
.background(Color.white.opacity(0.01)) // <-- important
}
}
extension View {
func getSafeArea()-> UIEdgeInsets {
return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
struct TabBarButton: View {
#Binding var tagSelect: String
var systemName: String
var body: some View{
Button(action: {tagSelect = systemName }, label: {
VStack(spacing: 8){
Image(systemName)
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width:28, height: 28)
}
.frame(maxWidth: .infinity)
})
}
}
struct Home: View {
#State var tagSelect = "house.circle"
init() {
UITabBar.appearance().isHidden = false
}
var body: some View {
ZStack {
TabView (selection: $tagSelect) {
Color.blue.tag("house.circle")
Color.green.tag("pencil")
Color.pink.tag("magnifyingglass")
Color.red.tag("bell")
Color.yellow.tag("cart")
}
CustomTabBar(tagSelect: $tagSelect)
}
.ignoresSafeArea()
}
}
extension View {
func getRect()->CGRect {
return UIScreen.main.bounds
}
}
I set the width of a SwiftUI Button to 0 to "deactivate" it.
If the with of the button is set to 0, the button disappears as expected, but clicking in the left edge of the yellow Stack activates the Button.
Why does this happen?
How can I avoid it?
struct ContentView: View {
#State var zeroWidth = false
var body: some View {
VStack{
ButtonLine( leftButtons: [ButtonAttr( label: "LB1",
action: {print("LB1")},
iconSystemName : "person"
)],
zeroWidth: zeroWidth
)
Button("Toggle width \(zeroWidth ? "On" : "Off" ) "){ self.zeroWidth.toggle() }
}
}
}
struct ButtonLine: View {
let leftButtons : [ButtonAttr]
let zeroWidth : Bool
var body: some View {
HStack(spacing: 0) {
ForEach(leftButtons.indices, id: \.self)
{ i in
HStack(spacing: 0.0)
{
Button(action: { self.leftButtons[i].action() }) {
ButtonLabel( singleline: false,
buttonAttr: self.leftButtons[i]
)
.padding(0)
//.background(Color.green) // not visible
}
.buttonStyle(BorderlessButtonStyle())
.frame( width: self.zeroWidth ? 0 : 100, height: 50)
.background(Color.green)
.clipped()
.foregroundColor(Color.white)
.padding(0)
}
// .background(Color.blue) // not visible
}
// .background(Color.blue) // not visible
Spacer()
Text("CONTENT")
.background(Color.green)
.onTapGesture {
print("Content tapped")
}
Spacer()
}
.background(Color.yellow)
.onTapGesture {
print("HS tapped")
}
}
}
struct ButtonLabel: View {
var singleline : Bool
var buttonAttr : ButtonAttr
var body: some View {
VStack (spacing: 0.0) {
Image(systemName: buttonAttr.iconSystemName).frame(height: singleline ? 0 : 20).clipped()
.padding(0)
.background(Color.blue)
Text(buttonAttr.label)
.padding(0)
.background(Color.blue)
}
.padding(0)
.background(Color.red)
}
}
struct ButtonAttr
{ let label : String
let action: ()-> Void
let iconSystemName : String
}
Instead of tricky "deactivate", just use real remove, like below
HStack(spacing: 0.0)
{
if !self.zeroWidth {
Button(action: { self.leftButtons[i].action() }) {
ButtonLabel( singleline: false,
buttonAttr: self.leftButtons[i]
)
.padding(0)
//.background(Color.green) // not visible
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 100, height: 50)
.background(Color.green)
.clipped()
.foregroundColor(Color.white)
.padding(0)
}
}.frame(height: 50) // to keep height persistent
there is very simple explanation.
try next snippet
struct ContentView: View {
var body: some View {
Text("Hello").padding().border(Color.yellow).fixedSize().frame(width: 0)
}
}
Why?
.frame(..)
is defined as a function of View, which return another View, as any kind of View modifier. The resulting View has .zero sized frame, as expected.
It is really true? Let's check it!
struct ContentView: View {
var body: some View {
HStack(spacing: 0) {
Rectangle()
.fill(Color.orange)
.frame(width: 100, height: 100)
Text("Hello")
.padding()
.border(Color.black)
.fixedSize()
.frame(width: 0, height: 0)
Rectangle()
.fill(Color.green)
.frame(width: 100, height: 100)
.blendMode(.exclusion)
}
}
}
Just add .clipped modifier to your Text View
struct ContentView: View {
var body: some View {
HStack(spacing: 0) {
Rectangle()
.fill(Color.orange)
.frame(width: 100, height: 100)
Text("Hello")
.padding()
.border(Color.black)
.fixedSize()
.frame(width: 0, height: 0)
.clipped()
Rectangle()
.fill(Color.green)
.frame(width: 100, height: 100)
.blendMode(.exclusion)
}
}
}
and the Text "disappears" ...
It disappears from the screen, but not from View hierarchy!. Change the code again
struct ContentView: View {
var body: some View {
HStack(spacing: 0) {
Rectangle()
.fill(Color.orange)
.frame(width: 100, height: 100)
Text("Hello")
.padding()
.border(Color.black)
.fixedSize().onTapGesture {
print("tap")
}
.frame(width: 0, height: 0)
.clipped()
Rectangle()
.fill(Color.green)
.frame(width: 100, height: 100)
.blendMode(.exclusion)
}
}
}
and you see, that there is still some "invisible" area sensitive on tap gesture
You can disable you Button by adding a .disabled(self.zeroWidth)
Button(action: { self.leftButtons[i].action() }) {
ButtonLabel( singleline: false,
buttonAttr: self.leftButtons[i]
)
.padding(0)
//.background(Color.green) // not visible
}
.disabled(self.zeroWidth)
.buttonStyle(BorderlessButtonStyle())
.frame( width: self.zeroWidth ? 0 : 100, height: 50)
.background(Color.green)
.clipped()
.foregroundColor(Color.white)
.padding(0)
You can debug the view hierarchy by clicking that icon in xcode: