Building a Tinder-like swipe feature on SwiftUI - swift

I am trying to build a tinder-like swipe feature but I have an issue. All the cards get stacked together on the first screen like in the screenshot below:
It is supposed to look like below
Here is my code:
MainView
NavigationView {
VStack () {
ZStack {
ForEach(outingsVM.outings, id: \.dateId) { outing in
CardView(outing: outing)
}
}
}
}
CardView
ZStack {
VStack {
HStack {
Text("\(outing.name), \(outing.age)")
}
.frame(width: 320, alignment: .leading)
HStack (alignment: .center) {
Image(systemName: "figure.walk.circle")
Text("\(outing.place)")
}
.frame(width: 320, alignment: .leading)
HStack {
Image(systemName: "calendar.circle")
Text("\(outing.date) \(outing.time)")
}
.frame(width: 320, alignment: .leading)
HStack {
Image(systemName: "creditcard.circle")
Text("\(outing.payment)")
}
.frame(width: 320, alignment: .leading)
// }
HStack (){
Spacer()
//accept date
Button {
showingModal = true
} label: {
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 50))
.foregroundColor(.green)
}
Spacer()
//reject date
Button {
swipeCard(width: -200)
} label: {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 50))
.foregroundColor(.red)
}
Spacer()
}
.frame(width: 320)
.padding()
}
}
How can I fix this?

You need to add a background to your CardView, e.g.
struct CardView: View {
var body: some View {
VStack {
}
.padding()
.background(RoundedRectangle(cornerRadius: 8).fill(.white))
}
}

Related

VStack inside NavigationLink

I am trying to VStack an Image and a Text inside a NavigationLink.
This is my code:
NavigationLink(destination: ContentView()){
Circle()
.fill(Color.green)
.frame(width: 50, height:50)
.overlay(Image(systemName: "arrow.up"))
Text("Send")
.foregroundColor(Color.white)
}
VStack {
if item.title == "Send"{
NavigationLink(destination: ContentView()) {
VStack {
Circle()
.fill(Color.green)
.frame(width: 50, height:50)
.overlay(Image(systemName: "arrow.up"))
Text("Send")
.foregroundColor(Color.black)
}
}
}}
If I try to VStack inside the NavigationLink then nothing would compile. If I try to VStack everything, then the image and the text would still show next to each other.
I am trying to achieve the right example:
This should work
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("new View")) {
ZStack {
Circle()
.fill(Color.green.opacity(0.7))
.frame(width: 70, height: 70)
VStack {
Image(systemName: "square.and.arrow.up")
.renderingMode(.template)
.foregroundColor(.white)
Text("send")
.foregroundColor(.white)
}
}
}
}
}
}
I wasn't able to replicate your issue. The following compiles and displayed as desired.
VStack {
NavigationLink(destination: ContentView()) {
VStack {
Circle()
.fill(Color.green)
.frame(width: 50, height:50)
.overlay(Image(systemName: "arrow.up"))
Text("Send")
.foregroundColor(Color.white)
}
}
}

Ways to display data in SwiftUI - Alternatives to List

I'm display how many steps I have taken but don't want it in a list. What should I use instead? Thanks
NavigationView {
List(steps, id: \.id) { step in
VStack(spacing: 15){
Text("\(step.count)")
.font(.custom(customFont, size: 100))
.fontWeight(.semibold)
.multilineTextAlignment(.center)
.opacity(5)
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.padding(.bottom, -45)
HStack{
Text("Steps Today")
.font(.custom(customFont, size: 40))
.multilineTextAlignment(.center)
}
.frame(maxWidth: .infinity, alignment: .center)
}
following #aheze and generally speaking it should look something like this:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
LazyVStack {
ForEach(steps, id: \.id) { step in
NavigationLink {
// here comes the destination view, this is only dummy
Text("I walked \(step.count) steps")
} label: {
Text("\(step.count)")
.font(.system(size: 100))
.fontWeight(.semibold)
}
}
}
}
.navigationBarHidden(true)
}
}
}

SwiftUI: ignoreSafeArea causing extra whitespace in View

I'm just learning how to use SwiftUI and seem to be having an issue with the ignoreSafeArea() call on a view.
This is my original View:
But when I add ignoreSafeArea to the View it causes strange whitespace errors:
Here is the code I'm using for the main view.
var body: some View {
VStack {
Image("Banner")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(height: self.show ? 120 : 70, alignment: .bottomLeading)
.blur(radius: self.show ? 0 : 2)
.clipped()
.ignoresSafeArea()
HStack {
VStack(alignment: .leading) {
Text(user.name)
.font(.title)
HStack {
Text(user.screenName)
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
}
}
Spacer()
UserImage(user: user, show: self.$show)
}
.padding()
if self.show {
Divider()
HStack {
Text(user.userDetailsDescription)
.font(.subheadline.weight(.light))
Spacer()
}.padding(.leading)
}
}
}
You should apply the modifier to the VStack instead, so it doesn't just affect Image("Banner").
Change this:
VStack {
Image("Banner")
/* ... */
.ignoresSafeArea()
/* ... */
}
To this:
VStack {
Image("Banner")
/* ... */
/* ... */
}
.ignoresSafeArea(edges: .top)
Incorrect code
Correct code
Alternatively, you could replace the Image with a placeholder space (Color.clear). Then, put the Image inside .background(). This way, the image's frame won't affect any other spacing.
struct ContentView: View {
let show = true
var body: some View {
VStack {
/// placeholder
Color.clear
.frame(height: self.show ? 120 : 70)
.background(
Image("Banner")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(alignment: .bottomLeading)
.blur(radius: self.show ? 0 : 2)
.ignoresSafeArea() /// ignoresSafeArea inside `.background`
)
HStack {
VStack(alignment: .leading) {
Text("User name")
.font(.title)
HStack {
Text("User screen name")
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
}
}
Spacer()
Circle()
.fill(Color.green)
.frame(width: 100, height: 100)
.offset(x: 0, y: -50)
}
.padding()
if self.show {
Divider()
HStack {
Text("Description")
.font(.subheadline.weight(.light))
Spacer()
}.padding(.leading)
}
Spacer()
}
}
}
Result:

SwiftUI Shape Scale Size Such that HStack size does not increase

I'm trying to make the circles fit into the HStack such that the HStack size does not increase.
How can I make the circles fit without specifying a fixed frame?
struct ContentView: View {
var body: some View {
NavigationView {
Form {
HStack {
Circle()
.fill(Color.red)
.aspectRatio(1, contentMode: .fit)
Text("Hello")
}
HStack {
Circle()
.fill(Color.blue)
.aspectRatio(1, contentMode: .fit)
Text("Hello")
}
}
}
}
}
Here is a sample of various containers to chose from. SwiftUI will do all the layout, automatically handle rotations and device resolutions.
struct CirclesView: View {
var body: some View {
VStack(spacing: 0) {
Label("Circles", systemImage: "circle").font(.system(size: 24, weight: .black, design: .rounded)).foregroundColor(.pink)
HStack {
Circle()
.foregroundColor(.yellow)
.frame(width: 32, height: 32)
Text("This is a yellow circle")
Spacer()
}
Circle()
.foregroundColor(.orange)
.shadow(radius: 10)
.frame(width: 75)
Divider()
HStack {
VStack {
Circle().foregroundColor(.blue)
Text("Blue").font(.title3)
HStack {
Circle().foregroundColor(.purple)
Text("Purple").font(.caption)
}
}
.padding()
.background(Color.yellow)
ZStack(alignment: Alignment(horizontal: .center, vertical: .center)) {
Circle().foregroundColor(.green)
Text("Green").foregroundColor(.primary)
}
}
}
}
}

How can I switch 2 different views inside same "Main" view? SwiftUI

I have next problem with my SwiftUI view: I have "User View" , in this view I have 2 buttons - "Saved" and "My achievement". When user tapped on any button , it will show different views (for example: like TabBar).
It will be switch on same screen , not transition to the other view.
Photo
I can create another views , and put it into my , if it needs.
Hope your understand my quick English.
Thank You for help!
Code:
import SwiftUI
struct MainPage: View {
///State variable for default selected tag
#State var selectedView = 3
///Body-view for the main screen
var body: some View {
TabView(selection: $selectedView) {
//MARK: - First screen (1st view)
VStack {
Text("First View")
}///1st Global VStack
.tabItem {
Label("First Item", systemImage: "1.circle")
}.tag(1)
//MARK: - Scond screen (2nd view)
VStack {
Text("Second View")
}///2nd Global VStack
.tabItem {
Label("Second Item", systemImage: "2.circle")
}
.tag(2)
//MARK: - Profile screen (3rd view)
ZStack(alignment: .top) {
Color.clear
HStack(alignment: .center){
VStack {
HStack() {
HStack() {
Button(action: {}, label: {
Image(systemName: "person")
.resizable()
.scaledToFit()
.frame(width: 35 , height: 35)
.foregroundColor(.gray)
})
.padding(.leading , -30)
.padding(.trailing, 20)
Text("User")
.bold()
.font(.custom("title", size: 24))
.lineLimit(1)
}.padding(.trailing , 110)
.frame(width: 260)
Button(action: {}, label: {
Image(systemName: "gearshape")
.resizable()
.scaledToFit()
.frame(width: 35 , height: 35)
.foregroundColor(.gray)
})
}
HStack(spacing: 30) {
Image(systemName: "")
Button(action: {
}, label: {
Text("Saved")
.foregroundColor(.gray)
.font(.custom("title", size: 17))
.lineLimit(1)
})
Image(systemName: "")
Button(action: {}, label: {
Text("My achievement")
.foregroundColor(.gray)
.font(.custom("title", size: 17))
.lineLimit(1)
})
}.frame(width: 300, height: 30, alignment: .center)
HStack(alignment: .center ,spacing: 10){
VStack(alignment: .leading , spacing: 20) {
}.frame(width: 160, height: 2, alignment: .leading)
.background(Color.blue)
.padding(10)
VStack(alignment: .trailing){
}.frame(width: 100, height: 2, alignment: .trailing)
.background(Color.red)
.padding()
}.frame(width: 420, height: 2, alignment: .center)
.background(Color.gray)
.padding(10)
}
}///Top HStack
.frame(width: 300, height: 70, alignment: .center)
.padding()
}///3rd Global ZStack
.tabItem {
Label("Third item", systemImage: "3.circle")
}.tag(3)
//MARK: - End
}
}
}
You could do it with a segmented picker like this.
struct ExampleView: View
{
#State private var selectedView = 0
private let pickerOptions = ["Saved", "Achievements"]
var body: some View {
VStack {
HStack {
Text("ExampleView")
.font(.title)
.bold()
Spacer()
} //: HStack
.padding()
Divider()
Picker(selection: $selectedView, label: Text("")) {
ForEach(0..<pickerOptions.count) {
Text(self.pickerOptions[$0])
} //: ForEach
} //: Picker
.pickerStyle(SegmentedPickerStyle())
.padding()
if selectedView == 0
{
SavedView()
}
else if selectedView == 1
{
AchievementsView()
}
}
}
}