SwiftUI: listRowInsets not working as expected - xcode

listRowInsets(_:) is not working as expected when using List() and List(Data,id). in Example 1 below works perfectly with zero insets, while in Example 2 it does nothing.
Example 1:
struct ContentView: View {
var body: some View {
List {
Color.red
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
Color.blue
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
Color.yellow
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
}
The Result:
Example 2
struct ContentView: View {
var colors: [Color] = [.red, .blue, .yellow]
var body: some View {
List(colors, id: \.self) { color in
color.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
}
The Result:

I assume the reason is in used constructors. The .listRowInsets by documentation effects view being placed in List (directly).
The following works
var colors: [Color] = [.red, .blue, .yellow]
var body: some View {
List {
ForEach(colors, id: \.self) { color in
color.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
}

In addition to Asperi's answer, if you have sections, you need to apply the listRowInsets view modifier to the section, otherwise the setting is also going to be ignored.

Related

How Do i maintain Scrollview subitem height with Swiftui

I am new to swift and I am trying to wrap my view in Scrollview. The issue is that, when I wrap the content in the scrollview, the contents shrink. I have the images below.
sample code:
ScrollView(.vertical) {
GeometryReader { metrics in
HStack{
Button(action:{
isVisible = true
}, label: {
VStack(alignment: .center, spacing: 10){
Image(systemName: "book.fill")
.resizable()
.frame(width: 28, height: 22)
.padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
Text("Daily Reading")
.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
}.frame(maxWidth: metrics.size.width/2.3, maxHeight: .infinity)
.background(RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2))
})
Spacer()
Button(action: {
}, label: {
VStack(alignment: .center, spacing: 10){
Image("church")
.resizable()
.frame(maxWidth: 28, maxHeight: 22)
.padding(EdgeInsets(top: 15, leading: 0, bottom: 0, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
Text("Church Prayers")
.padding(EdgeInsets(top: 0, leading: 0, bottom: 15, trailing: 0))
.foregroundColor(CustomColor.primaryColor)
}.frame(maxWidth: metrics.size.width/2.3, maxHeight: .infinity)
.background(RoundedRectangle(cornerRadius: 15)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2))
})
}.frame(maxHeight: metrics.size.width/2)
.padding(.horizontal, 15)
.padding(.vertical, 7.5)
}
}
I have tried removing the GeometryReader but I am still getting the same result and I can't seem to find any helpful solution online. Thanks
on the HStack{...}, try replacing .frame(maxHeight: metrics.size.width/2) with .frame(height: metrics.size.width/2)

SwiftUI - Animating HUD / Pop Over like iOS Silent Mode

I'm trying to clone the following animation from iOS:
Here's my code. I'm stuck with the animation of the star. I'd for example like to shake it a little bit or rotate it around it's y-axis.
Here's my code:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
PopOver(image: "star.fill", color: .primary, title: "Thank You!")
}
}
struct PopOver: View{
var image: String
var color: Color
var title: String
#Environment(\.colorScheme) var scheme
var body: some View{
HStack(spacing: 10){
Image(systemName: image)
.font(.title3)
.foregroundColor(color)
Text(title)
.foregroundColor(.primary)
}
.padding(.vertical,10)
.padding(.horizontal)
.background(
scheme == .dark ? Color.black : Color.white
)
.clipShape(Capsule())
.shadow(color: Color.primary.opacity(0.1), radius: 5, x: 1, y: 5)
.shadow(color: Color.primary.opacity(0.03), radius: 5, x: 0, y: -5)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.offset(y: 0)
}
}
Can you tell me how this can be achieved?
Many Thanks!
you could try something like this approach:
struct ContentView: View {
#State var popUpPresented = false
var body: some View {
Button(action: {popUpPresented = true}) {
Text("click me")
}
.popover(isPresented: $popUpPresented, arrowEdge: .top) {
PopOver(image: "star.fill", color: .primary, title: "Thank You!")
}
}
}
struct PopOver: View{
var image: String
var color: Color
var title: String
#State var rotate = 0.0 // <-- here
#Environment(\.colorScheme) var scheme
var body: some View{
HStack(spacing: 10){
Image(systemName: image).font(.title3).foregroundColor(color)
// --- here ---
.rotation3DEffect(Angle.degrees(rotate), axis: (x: 0, y: 1, z: 0))
.task {
withAnimation(Animation.default.speed(0.3).delay(0).repeatForever(autoreverses: false)){
rotate = 360.0
}
}
Text(title).foregroundColor(.primary)
}
.padding(.vertical,10)
.padding(.horizontal)
.background(scheme == .dark ? Color.black : Color.white)
.clipShape(Capsule())
.shadow(color: Color.primary.opacity(0.1), radius: 5, x: 1, y: 5)
.shadow(color: Color.primary.opacity(0.03), radius: 5, x: 0, y: -5)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.offset(y: 0)
}
}

The textfield in my search bar will not allow for text to be entered (swiftUI)

I have tried to implement a search bar within my app (using swiftUI), which shows up when I build the app. However, it won't allow me to type into the actual text field. My code is below. I have been searching for solutions to this problem for awhile and can't seem to see any problems in my code. Is there something wrong with my TextField?
Code for search bar -
import SwiftUI
struct SearchBar: View {
#Binding var text: String
#State private var isEditing = false
var body: some View {
HStack {
TextField("Search...", text: $text)
// .foregroundColor(Color("Teal"))
// .background(Color("Grey"))
.overlay(
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(Color(UIColor.systemGray3))
.frame(minWidth:0, maxWidth: .infinity, alignment: .leading)
.padding(EdgeInsets.init(top: 0, leading: 30, bottom: 0, trailing: 20))
// Search icon
if isEditing {
Button(action: {
self.text = ""
}, label: {
Image(systemName: "multiply.circle")
.foregroundColor(Color(UIColor.systemGray3))
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 30))
// Delete button
})
}
}
).onTapGesture {
self.isEditing = true
}
if isEditing{
Button(action: {
self.isEditing = false
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
// Hide delete button when search bar is not selected
}){
}
}
}
}
}
Code implementing search bar into my view -
import SwiftUI
struct BusinessList: View {
#EnvironmentObject var modelData: ModelData
#State private var showFavoritesOnly = false
#State var searchText = ""
var filteredBusinesses: [Business] {
modelData.businesses.filter { business in
(!showFavoritesOnly || business.isFavorite)
}
}
var body: some View {
NavigationView {
ScrollView {
LazyVStack {
VStack {
SearchBar(text: $searchText)
.padding(.bottom)
.padding(.top)
.padding(.top)
.padding(.top)
.padding(.top)
// Search bar won't show text when 'typed into'
ScrollView(.horizontal, showsIndicators: false) {
HStack {
Button(action: {
showFavoritesOnly = true
}) {
Text("Favourites")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(Color.white)
.frame(width: 100.0, height: 30)
.background(Color("Teal"))
// How the button looks
.cornerRadius(25)
.zIndex(1)
.textCase(.uppercase)
.padding(EdgeInsets.init(top: 0, leading: 20, bottom: 0, trailing: 0))
}
Button(action: {
}) {
Text("Hospitality")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(Color.white)
.frame(width: 100.0, height: 30)
.background(Color("Teal"))
// How the button looks
.cornerRadius(25)
.zIndex(1)
.textCase(.uppercase)
}
Button(action: {
}) {
Text("Retail")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(Color.white)
.frame(width: 100.0, height: 30)
.background(Color("Teal"))
// How the button looks
.cornerRadius(25)
.zIndex(1)
.textCase(.uppercase)
}
Button(action: {
}) {
Text("Lifestyle")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(Color.white)
.frame(width: 110.0, height: 30)
.background(Color("Teal"))
// How the button looks
.cornerRadius(25)
.zIndex(1)
.textCase(.uppercase)
}
}
.padding(.bottom)
}
}
.background(Color(UIColor.white))
.shadow(radius: 6)
.padding(.bottom)
ForEach(filteredBusinesses) { business in
NavigationLink(destination: BusinessDetail(business: business)) {
BusinessRow(business: business)
}
}
}
}
.navigationBarHidden(true)
.ignoresSafeArea()
}
}
}
struct BusinessList_Previews: PreviewProvider {
static var previews: some View {
BusinessList()
}
}
your code works for me with minor changes to the colors, nothing major. Maybe the colors did not show your typing, but the text was there.
This is the test I did:
import SwiftUI
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct SearchBar: View {
#Binding var text: String
#State private var isEditing = false
var body: some View {
HStack {
TextField("Search...", text: $text)
// .foregroundColor(Color("Teal"))
// .background(Color("Grey"))
.overlay(
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
.frame(minWidth:0, maxWidth: .infinity, alignment: .leading)
.padding(EdgeInsets.init(top: 0, leading: 30, bottom: 0, trailing: 20))
// Search icon
if isEditing {
Button(action: {
self.text = ""
}, label: {
Image(systemName: "multiply.circle")
.foregroundColor(.gray)
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 30))
// Delete button
})
}
}
).onTapGesture {
self.isEditing = true
}
if isEditing{
Button(action: {
self.isEditing = false
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
// Hide delete button when search bar is not selected
}){
}
}
}
}
}
struct ContentView: View {
#State var searchText = ""
var body: some View {
SearchBar(text: $searchText)
.frame(width: 222, height: 55).padding(.horizontal, 20)
.border(.red)
}
}
EDIT:
Your new code works for me, when you remove
.shadow(radius: 6)
and
.ignoresSafeArea()

How to use if statement with struct in SwiftUI?

I am trying to use an if statement with a bool value in a struct to then see if a content view should be shown using that data. I keep getting the error "Ambiguous reference to member 'indices'" but I know this is not the actual problem it is just swiftUI saying there's an error on the forEach when it is the thing inside the forEach. This is the struct definition where needsToBeDeleted is false by default because it should be shown when first created
import Foundation
struct SEvent {
var eventName:String;
var timeSpent:String;
var timeStarted:Date;
var lastStarted:Date?;
var needsToBeDeleted = false;
}
and this is the piece where I am iterating over an array of the events
ForEach(arrayOfEvents.indices, id: \.self) { index in
if !self.arrayOfEvents[index].needsToBeDeleted {
EventContentView(eventName: self.arrayOfEvents[index].eventName, timeSpent:
self.arrayOfEvents[index].timeSpent, shouldDelete:
self.$arrayOfEvents[index].needsToBeDeleted)
}
}
Also this is the array declaration if that helps
#State private var arrayOfEvents = [SEvent]();
Edit:
This is the event content view code
import SwiftUI
struct EventContentView: View {
var eventName:String;
var timeSpent:String;
var startStop = ["Start", "Stop"];
#State var deleteTrigger = false;
var buttonColor = [Color.blue, Color.yellow]
#State var i = 0;
#Binding var shouldDelete:Bool;
var body: some View {
VStack{
VStack{
Text("\(eventName)")
.frame(minWidth: 0, idealWidth: 150, maxWidth: 200, minHeight: 0, idealHeight: 50, maxHeight: 75, alignment: .center)
Text("\(timeSpent)")
.frame(minWidth: 0, idealWidth: 150, maxWidth: 200, minHeight: 0, idealHeight: 50, maxHeight: 100, alignment: .leading)
if !deleteTrigger {
HStack {
Button(action: {
if self.i == 0{
self.i = 1
}
else if self.i == 1 {
self.i = 0
}
}) {
Text(startStop[i])
}
.foregroundColor(buttonColor[i])
.frame(minWidth: 0, idealWidth: 50, maxWidth: 100, minHeight: 0, idealHeight: 20, maxHeight: 40, alignment: .leading)
Button(action: {
self.deleteTrigger = true;
}) {
Text("Delete")
}
.foregroundColor(.red)
.animation(.interactiveSpring(response: 1, dampingFraction: 0.5, blendDuration: 1.5))
.frame(minWidth: 0, idealWidth: 50, maxWidth: 100, minHeight: 0, idealHeight: 20, maxHeight: 40, alignment: .trailing)
}
}
else{
HStack {
Button(action: {
self.shouldDelete = true
}) {
Text("Delete")
}
.foregroundColor(.red)
.frame(minWidth: 0, idealWidth: 50, maxWidth: 100, minHeight: 0, idealHeight: 20, maxHeight: 40, alignment: .leading)
Button(action: {
self.deleteTrigger = false;
}) {
Text("Don't Delete")
}
.foregroundColor(.green)
.animation(.easeInOut)
.frame(minWidth: 0, idealWidth: 50, maxWidth: 100, minHeight: 0, idealHeight: 20, maxHeight: 40, alignment: .trailing)
}
}
}
.frame(minWidth: 0, maxWidth: 200, minHeight: 20, idealHeight: 30, maxHeight: 150, alignment: .center)
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 5.0)
.stroke(Color.black, lineWidth: 1)
.shadow(radius: 5)
)
.padding()
}
}
and the specific part that deletes the view is this button where it changes the binding variable shouldDelete to true which changes the needsToBeDeleted element of the SEvent Struct in arrayOfEvents to true
Button(action: {
self.shouldDelete = true
})
{
Text("Delete")
}
You can use it like this
var body: some View {
ForEach(arrayOfEvents.indices, id: \.self) { index -> AnyView in
if !self.arrayOfEvents[index].needsToBeDeleted {
return AnyView(EventContentView(eventName: self.arrayOfEvents[index].eventName, timeSpent:
self.arrayOfEvents[index].timeSpent, shouldDelete:
self.$arrayOfEvents[index].needsToBeDeleted))
} else {
return AnyView(EmptyView())
}
}
}

How to remove tab navigator's bottom border (react-navigation)

In react navigation v5, when implementing a materialTopTabNavigator, how can I remove the bottom horizontal border separating the tab menu and individual tab pages?
I've tried borderWidth, borderBottomWidth, borderTopWidth in tabBarOptions.style to no avail.
screenOptions={{
tabBarStyle: {
borderTopWidth: 0
}
}
The bottom line is not a border, but a shadow (on iOS) and elevation (on Android). So the fix is:
<Tab.Navigator
tabBarOptions={{
style: {
elevation: 0, // for Android
shadowOffset: {
width: 0, height: 0 // for iOS
},
}
}}
>
// ...
In addition, on Android, when tapping the icon, an indicator line briefly appears at the bottom. Make that invisible by setting the elevation prop in indicatorStyle:
<Tab.Navigator
tabBarOptions={{
indicatorStyle: {
width: 0, height: 0, elevation: 0,
}
>
// ...
<Tab.Navigator
tabBarOptions={{
activeTintColor: "#fff",
inactiveTintColor: "#fff",
activeBackgroundColor: "#090D20",
inactiveBackgroundColor: "#192665",
style: {
backgroundColor: "#192665",
height: 60,
borderTopColor: "red", //Change Like This
},
}}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="ContactsScreen" component={ContactsScreen} />
</Tab.Navigator>[enter image description here][1]
tabBarOptions: {
style: {
// Remove border top on both android & ios
borderTopWidth: 0,
borderTopColor: "transparent",
elevation: 0,
shadowColor : '#5bc4ff',
shadowOpacity: 0,
shadowOffset: {
height: 0,
},
shadowRadius: 0,
}
}

Resources