I'm creating a flashcard view for language education. The first iteration consisted of flipping cards to front and back. The second iteration consisted of an addition of a swipe-based interface. The third iteration was meant to combine the previous two; however I'm having animation visualization issues (i.e. the third flip animation doesn't look like the first iteration).
first and third iteration gif displaying issue
first iteration code:
struct CardBack : View {
let width : CGFloat
let height : CGFloat
let firLanguage: String
let wordClass: String
let accuracy: String
let definition: String
#Binding var degree : Double
var body: some View {
ZStack {
VStack {
HStack {
Text(wordClass)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal, 5)
.padding(.top, 5)
.font(.system(size: 15))
Text(firLanguage)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.trailing, 5)
.padding(.top, 5)
.font(.system(size: 15))
Text(accuracy)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.trailing, 5)
.padding(.top, 5)
.font(.system(size: 15))
Spacer()
Image(systemName: "command.circle.fill")
.font(.system(size: 29))
.padding(.horizontal, 5)
.padding(.top, 5)
.foregroundColor(Color.gray)
}
Spacer()
HStack {
Text("word analysis subview")
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal, 5)
.padding(.bottom, 5)
.font(.system(size: 15))
Spacer()
}
}
.frame(width: 350, height: 190)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
VStack {
Spacer()
Text(definition)
.font(.title)
Spacer()
}
.frame(width: 350, height: 90)
.background(Color.white)
.cornerRadius(0)
.shadow(radius: 1)
}
.rotation3DEffect(Angle(degrees: degree), axis: (x: 1, y: 0, z: 0))
}
}
struct CardFront : View {
let width : CGFloat
let height : CGFloat
let secLanguage: String
let wordClass: String
let accuracy: String
let term: String
#Binding var degree : Double
var body: some View {
ZStack {
VStack {
HStack {
Text(wordClass)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal, 5)
.padding(.top, 5)
.font(.system(size: 15))
Text(secLanguage)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.trailing, 5)
.padding(.top, 5)
.font(.system(size: 15))
Text(accuracy)
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.trailing, 5)
.padding(.top, 5)
.font(.system(size: 15))
Spacer()
Image(systemName: "command.circle.fill")
.font(.system(size: 29))
.padding(.horizontal, 5)
.padding(.top, 5)
.foregroundColor(Color.gray)
}
Spacer()
HStack {
Text("word analysis subview")
.padding(10)
.background(Color.gray.opacity(0.1))
.cornerRadius(10)
.padding(.horizontal, 5)
.padding(.bottom, 5)
.font(.system(size: 15))
Spacer()
}
}
.frame(width: 350, height: 190)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
VStack {
Spacer()
Text(term)
.font(.title)
Spacer()
}
.frame(width: 350, height: 90)
.background(Color.white)
.cornerRadius(0)
.shadow(radius: 1)
}
.rotation3DEffect(Angle(degrees: degree), axis: (x: 1, y: 0, z: 0))
}
}
struct CardFlipView: View {
//MARK: Variables
#State var backDegree = 0.0
#State var frontDegree = -90.0
#State var isFlipped = true
let width : CGFloat = 200
let height : CGFloat = 250
let durationAndDelay : CGFloat = 0.3
let firLanguage: String = "English"
let secLanguage: String = "Spanish"
let wordClass: String = "Verb"
let accuracy: String = "63%"
let term: String = "hablar"
let definition: String = "to talk"
//MARK: Flip Card Function
func flipCard () {
isFlipped = !isFlipped
if isFlipped {
withAnimation(.linear(duration: durationAndDelay)) {
backDegree = 90
}
withAnimation(.linear(duration: durationAndDelay).delay(durationAndDelay)){
frontDegree = 0
}
} else {
withAnimation(.linear(duration: durationAndDelay)) {
frontDegree = -90
}
withAnimation(.linear(duration: durationAndDelay).delay(durationAndDelay)){
backDegree = 0
}
}
}
//MARK: View Body
var body: some View {
ZStack {
CardBack(width: width, height: height, firLanguage: firLanguage, wordClass: wordClass, accuracy: accuracy, definition: definition, degree: $frontDegree)
CardFront(width: width, height: height, secLanguage: secLanguage, wordClass: wordClass, accuracy: accuracy, term: term, degree: $backDegree)
}.onTapGesture {
flipCard ()
}
}
}
third iteration code:
struct Word: Hashable, CustomStringConvertible {
var id: Int
let front: String
let back: String
let term: String
let definition: String
let accuracy: Int
let wordclass: String
var description: String {
return "\(term), id: \(id)"
}
}
struct ContentView3: View {
/// List of words
#State var words: [Word] = [
Word(id: 0, front: "Spanish", back: "English", term: "to speak", definition: "hablar", accuracy: 63, wordclass: "Verb"),
Word(id: 1, front: "Spanish", back: "English", term: "to eat", definition: "comer", accuracy: 63, wordclass: "Verb"),
//Word(id: 2, front: "Spanish", back: "English", term: "to think", definition: "pensar", accuracy: 63, wordclass: "Verb"),
//Word(id: 3, front: "Spanish", back: "English", term: "to live", definition: "vivir", accuracy: 63, wordclass: "Verb"),
//Word(id: 4, front: "Spanish", back: "English", term: "to write", definition: "escribir", accuracy: 63, wordclass: "Verb"),
]
/// Return the CardViews width for the given offset in the array
/// - Parameters:
/// - geometry: The geometry proxy of the parent
/// - id: The ID of the current user
private func getCardWidth(_ geometry: GeometryProxy, id: Int) -> CGFloat {
let offset: CGFloat = CGFloat(words.count - 1 - id) * 10
return geometry.size.width - offset
}
/// Return the CardViews frame offset for the given offset in the array
/// - Parameters:
/// - geometry: The geometry proxy of the parent
/// - id: The ID of the current user
private func getCardOffset(_ geometry: GeometryProxy, id: Int) -> CGFloat {
return CGFloat(words.count - 1 - id) * 10
}
private var maxID: Int {
return self.words.map { $0.id }.max() ?? 0
}
var body: some View {
VStack {
GeometryReader { geometry in
LinearGradient(gradient: Gradient(colors: [Color.init(#colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)), Color.init(#colorLiteral(red: 1, green: 0.9882352941, blue: 0.862745098, alpha: 1))]), startPoint: .bottom, endPoint: .top)
.frame(width: geometry.size.width * 1.5, height: geometry.size.height)
.background(Color.yellow)
.clipShape(Circle())
.offset(x: -geometry.size.width / 4, y: -geometry.size.height / 6)
VStack(spacing: 24) {
Spacer()
ZStack {
ForEach(self.words, id: \.self) { word in
Group {
// Range Operator
if (self.maxID - 3)...self.maxID ~= word.id {
CardView(word: word, onRemove: { removedWord in
// Remove that user from our array
self.words.removeAll { $0.id == removedWord.id }
})
.animation(.spring())
.frame(width: self.getCardWidth(geometry, id: word.id), height: 400)
.offset(x: 0, y: self.getCardOffset(geometry, id: word.id))
}
}
}
}
Spacer()
}
}
}.padding()
}
}
//MARK: CardView
struct CardView: View {
#State private var translation: CGSize = .zero
#State private var swipeStatus: LikeDislike = .none
#State var backDegree = 0.0
#State var frontDegree = -90.0
#State var isFlipped = true
let durationAndDelay : CGFloat = 0.3
var word: Word
private var onRemove: (_ word: Word) -> Void
private var thresholdPercentage: CGFloat = 0.5 // when the user has draged 50% the width of the screen in either direction
private enum LikeDislike: Int {
case like, dislike, none
}
init(word: Word, onRemove: #escaping (_ word: Word) -> Void) {
self.word = word
self.onRemove = onRemove
}
private func getGesturePercentage(_ geometry: GeometryProxy, from gesture: DragGesture.Value) -> CGFloat {
gesture.translation.width / geometry.size.width
}
func flipCard () {
isFlipped = !isFlipped
if isFlipped {
withAnimation(.linear(duration: durationAndDelay)) {
backDegree = 90
}
withAnimation(.linear(duration: durationAndDelay).delay(durationAndDelay)){
frontDegree = 0
}
} else {
withAnimation(.linear(duration: durationAndDelay)) {
frontDegree = -90
}
withAnimation(.linear(duration: durationAndDelay).delay(durationAndDelay)){
backDegree = 0
}
}
}
var body: some View {
GeometryReader { geometry in
VStack(alignment: .leading) {
ZStack(alignment: self.swipeStatus == .like ? .topLeading : .topTrailing) {
if self.swipeStatus == .like {
Text("YES")
.font(.headline)
.padding()
.cornerRadius(10)
.foregroundColor(Color.green)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.green, lineWidth: 3.0)
).padding(24)
.rotationEffect(Angle.degrees(-45))
} else if self.swipeStatus == .dislike {
Text("NO")
.font(.headline)
.padding()
.cornerRadius(10)
.foregroundColor(Color.red)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.red, lineWidth: 3.0)
).padding(.top, 45)
.rotationEffect(Angle.degrees(45))
}
ZStack {
CardFront2(word: word, degree: $frontDegree)
CardBack2(word: word, degree: $backDegree)
}.onTapGesture {
flipCard ()
}
}
}
.animation(.interactiveSpring())
.offset(x: self.translation.width, y: 0)
.rotationEffect(.degrees(Double(self.translation.width / geometry.size.width) * 1), anchor: .bottom)
.gesture(
DragGesture()
.onChanged { value in
self.translation = value.translation
if (self.getGesturePercentage(geometry, from: value)) >= self.thresholdPercentage {
self.swipeStatus = .like
} else if self.getGesturePercentage(geometry, from: value) <= -self.thresholdPercentage {
self.swipeStatus = .dislike
} else {
self.swipeStatus = .none
}
}.onEnded { value in
// determine snap distance > 0.5 (half the width of the screen)
if abs(self.getGesturePercentage(geometry, from: value)) > self.thresholdPercentage {
self.onRemove(self.word)
} else {
self.translation = .zero
}
}
)
}
}
}
struct CardFront2 : View {
var word: Word
#Binding var degree : Double
var body: some View {
ZStack {
HStack {
VStack(alignment: .leading, spacing: 6) {
HStack {
Text("\(self.word.front)") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Text("\(self.word.wordclass)") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Text("\(self.word.accuracy)%") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Spacer()
Image(systemName: "info.circle")
.foregroundColor(.gray)
}.padding(.top, 15)
HStack {
Spacer()
Text("\(self.word.definition)")
.font(.title)
.bold()
Spacer()
}.padding(.vertical, 15)
}
Spacer()
}
.padding(.horizontal, 10)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
}
.rotation3DEffect(Angle(degrees: degree), axis: (x: 0, y: 1, z: 0))
}
}
struct CardBack2 : View {
var word: Word
#Binding var degree : Double
var body: some View {
ZStack {
HStack {
VStack(alignment: .leading, spacing: 6) {
HStack {
Text("\(self.word.back)") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Text("\(self.word.wordclass)") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Text("\(self.word.accuracy)%") ///add toggleability
.font(.subheadline)
.foregroundColor(.gray)
.padding(7)
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
.cornerRadius(10)
Spacer()
Image(systemName: "info.circle")
.foregroundColor(.gray)
}.padding(.top, 15)
HStack {
Spacer()
Text("\(self.word.term)")
.font(.title)
.bold()
Spacer()
}.padding(.vertical, 15)
}
Spacer()
}
.padding(.horizontal, 10)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
}
.rotation3DEffect(Angle(degrees: degree), axis: (x: 0, y: 1, z: 0))
}
}
I tried moving the .onTapGesture onto different parent views. I have really tried playing with all things animation for a few hours now, and I haven't been able to crack it. I want the card flip on iteration 3 to mirror that of iteration 1.
To update you guys on my complete fix.
At first I was clueless, then I identified the GeometryReader{} (GR) under CardView() as potentially the issue; however, it was actually the unnecessary VStack{} directly under the GR that it was reading from, instead of the ZStack{}. Outlined below.
GeometryReader { geometry in
VStack { // <-REMOVED
ZStack(alignment: self.swipeStatus == .yes ? .topLeading : .topTrailing) {
if self.swipeStatus == .yes {...} else if self.swipeStatus == .no {...}
ZStack {
CardFront2(word: word, degree: $frontDegree)
CardBack2(word: word, degree: $backDegree)
}.onTapGesture {
flipCard ()
}
}
After removing the above outlined code I was able to see more of the animation take place; however it still wasn't complete. I identified an animation in the ContentView() causing it. Outlined below.
ZStack {
ForEach(self.words, id: \.self) { word in
Group {
if (self.maxID - 3)...self.maxID ~= word.id {
CardView2(word: word, onRemove: { removedWord in
self.words.removeAll { $0.id == removedWord.id }
})
.animation(.spring()) // <-REMOVED
.frame(width: self.getCardWidth(geometry, id: word.id), height: 400)
.offset(x: 0, y: self.getCardOffset(geometry, id: word.id))
}
}
}
}
I'm quite self-taught, so I consistently need shoving in the right direction. Thank you both for your pointers!
I keep getting a compiler error that's not allowing my app to build.
Below is where I declared the variable showLogOutChoice.
struct HomeView: View {
#EnvironmentObject var userInfo: UserInfo
var showLogOutChoice = false
I then tried to use the value as a trigger for the actionsheet, and it's the compiler is throwing the error that it's not in scope.
.toolbar {
ToolbarItem(placement:.navigationBarLeading){
Button {
} label: {
VStack{
Image("CombIcon")
.resizable()
.frame(width: 40, height: 40)
Text("Menu")
}
}
}
ToolbarItem(placement:.navigationBarTrailing){
Button {
showLogOutChoice = true
} label: {
Text("Log Out ")
}
.confirmationDialog(Text:"Are You Sure You Want To Log Out?", isPresented: $showLogOutChoice , titleVisibility: .visible) {
FBAuth.logout(completion: <#T##(Result<Bool, Error>) -> Void#>)
}
}
}
}
}
The variable should still be in scope, and it's not having the same issue when I change the variable to true. So I'm confused. I tried cleaning the build folder and deleting the derived data but still nothing has changed any suggestions.
I'll copy the full file and leave it below as well for reference. PLEASE HELP!
struct HomeView: View {
#EnvironmentObject var userInfo: UserInfo
var showLogOutChoice = false
//TO DO connect picture to display if picture is not found display person fill
//TO DO add scroll view
var body: some View {
let screenSize: CGRect = UIScreen.main.bounds
let screenHeight = screenSize.height
let screenWidth = screenSize.width
NavigationView{
VStack{
VStack{
if (userInfo.user.profilePictureUrl == "")
{
Image( systemName: "person.fill")
.font(.system(size: 120))
.padding()
.foregroundColor(.black)
}
else{
WebImage(url: URL(string: userInfo.user.profilePictureUrl))
.resizable()
.scaledToFill()
.frame(width: 120, height: 120)
.clipped()
.cornerRadius(120)
}
}
.overlay(RoundedRectangle(cornerRadius: 120)
.stroke(Color.black, lineWidth: 1))
VStack{
Text("Hello \(userInfo.user.firstName)")
.font(.custom("coolvetica", size: 55))
}
VStack(alignment: .leading){
VStack(alignment:.leading){
Text("Your Upcoming Appointment")
.font(.custom("coolvetica", size: 30))
}
ZStack{
RoundedRectangle(cornerRadius: 13, style: .continuous)
.frame(width: screenWidth * 0.9, height: screenHeight * 0.1)
.foregroundColor(.white)
.shadow(color: Color.black.opacity(0.3), radius: 3, x: 0, y: 6)
Text("Holy Grail Appointment - Nov. 19th, 2021 8:00 AM")
.font(.custom("coolvetica", size: 18))
}.padding(.bottom)
HStack{
Button {
//TO DO book an appointment action
} label: {
Text("Book An Appointment")
.font(.custom("coolvetica", size: 20))
.frame(maxWidth: screenWidth * 0.8, minHeight: 20 )
.padding()
.foregroundColor(.white)
.background(Color("steelteal"))
.cornerRadius(42)
}
// Button {
// //TO DO reschedule an appointment action
// // may just make it able to only book an appointment for now
// } label: {
// Text("Reschedule Appointment")
// .font(.custom("coolvetica", size: 15))
// .padding()
// .foregroundColor(.white)
// .background(Color("steelteal"))
// .cornerRadius(42)
//
// }
}
VStack{
Text("My Hair Journey W/ Shei")
.font(.custom("coolvetica", size: 30))
}
HStack{
// need to create logic to save pictures and a note to a specific user
// create checkin page where pictures can be added the date and a note
// create display screen that will pop out with full information once photo is click
// if no checkins/updates are found then display text, no updates found would you like to add one with button
// allow shei to also add updates to individual users
Image( systemName: "person.fill")
.font(.system(size: 80))
.padding()
.foregroundColor(.black)
.overlay(RoundedRectangle(cornerRadius: 2)
.stroke(Color.black, lineWidth: 1))
Image( systemName: "person.fill")
.font(.system(size: 80))
.padding()
.foregroundColor(.black)
.overlay(RoundedRectangle(cornerRadius: 2)
.stroke(Color.black, lineWidth: 1))
Image( systemName: "person.fill")
.font(.system(size: 80))
.padding()
.foregroundColor(.black)
.overlay(RoundedRectangle(cornerRadius: 2)
.stroke(Color.black, lineWidth: 1))
}
}
}
.toolbar {
ToolbarItem(placement:.navigationBarLeading){
Button {
} label: {
VStack{
Image("CombIcon")
.resizable()
.frame(width: 40, height: 40)
Text("Menu")
}
}
}
ToolbarItem(placement:.navigationBarTrailing){
Button {
showLogOutChoice = true
} label: {
Text("Log Out ")
}
.confirmationDialog(Text:"Are You Sure You Want To Log Out?", isPresented: $showLogOutChoice , titleVisibility: .visible) {
FBAuth.logout(completion: <#T##(Result<Bool, Error>) -> Void#>)
}
}
}
}
}
}
I am completely new to SwiftUI so I hope this is not a stupid question. In my project I have a home view (a map) and a Menu button in the top right corner. Upon clicking that button my menu is gonna slide in from the left. For each of the menu items I want to use NavigationLink to jump to the next detail views.
Now here is the problem: When I click on the menu items (eg. Payments) I get the view but my button and my map are still on top of that view and I cant get rid of it, or at least I dont know how.. :(.
I saw a few similar questions but I couldnt make it work for my case.
This is my view when the menu view is true
This is my problem view. When I click on eg. Payments I cant get rid of the Map and the button in that view
This is my HomeView (The Map and the button)code:
import SwiftUI
struct HomeView: View {
#State var showMenu = false
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
withAnimation {
self.showMenu = false
}
}
}
return GeometryReader { geometry in
ZStack(alignment: .leading) {
if self.showMenu {
SlideInMenuView()
.frame(width: geometry.size.width/1)
.transition(.move(edge: .leading))
}
HomeSupportView()
.frame(width: geometry.size.width, height: geometry.size.height)
.cornerRadius(20)
.scaleEffect(self.showMenu ? 0.8 : 1)
.offset(x: self.showMenu ? 150 : 0, y : self.showMenu ? 50 : 0)
.disabled(self.showMenu ? true : false)
MenuButton(showMenu: self.$showMenu)
}
.gesture(drag)
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
struct MenuButton: View {
#Binding var showMenu: Bool
var body: some View {
Button(action: {
withAnimation {
self.showMenu.toggle()
}
}){
Image(systemName: "line.horizontal.3")
.imageScale(.large)
.frame(width: 100, height: 60)
.background(Color.black)
.clipShape(Circle())
.opacity(0.8)
.foregroundColor(.white)
.rotationEffect(.degrees(self.showMenu ? 90 : 0))
.scaleEffect(self.showMenu ? 1.2 : 1)
}
.padding(.top, -380)
}
}
This is my menu view code with my try of making the NavigationLink work. I tried it on the "Payments" HStack in multiple versions but I just cant make it work
import SwiftUI
struct SlideInMenuView: View {
#State private var showingPaymentDetails = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Profile")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 150.0)
HStack {
Image(systemName: "person.2.fill")
.foregroundColor(.gray)
.imageScale(.large)
Text("Matches")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
NavigationLink(destination:
PaymentDetailsView())
{
HStack {
Image(systemName: "creditcard")
.foregroundColor(.gray)
.imageScale(.large)
Text("Payments")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
}
HStack {
Image(systemName: "hammer")
.foregroundColor(.gray)
.imageScale(.large)
Text("Settings")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
Spacer()
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(.all)
}
}
}
struct SlideInMenuView_Previews: PreviewProvider {
static var previews: some View {
SlideInMenuView()
}
}
If anyone knows how to help me out here...
Thank you very much in advance guys.
Stay healthy.
Cheers,
LeBob
#Chris: This is how I want it to be. I put in 4 consecutive screenshots with the respective clicks.
***** UPDATED ANSWER *****
thank you for your clarifying pictures
try this:
import SwiftUI
class Global : ObservableObject {
#Published var showMenu = true
#Published var showMenuButton = true
}
struct PaymentDetailsView : View {
#EnvironmentObject var global : Global
var body: some View {
Text("payment")
.onAppear() {
withAnimation() {
self.global.showMenuButton = false
}
}
.onDisappear() {
withAnimation() {
self.global.showMenuButton = true
}
}
}
}
struct HomeSupportView : View {
#EnvironmentObject var global : Global
var body: some View {
ZStack {
Rectangle().fill(Color.blue)
Text("home")
}
}
}
struct SlideInMenuView: View {
#EnvironmentObject var global : Global
#State private var showingPaymentDetails = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Profile")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 150.0)
HStack {
Image(systemName: "person.2.fill")
.foregroundColor(.gray)
.imageScale(.large)
Text("Matches")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
NavigationLink(destination:
PaymentDetailsView().environmentObject(self.global))
{
HStack {
Image(systemName: "creditcard")
.foregroundColor(.gray)
.imageScale(.large)
Text("Payments")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
}
HStack {
Image(systemName: "hammer")
.foregroundColor(.gray)
.imageScale(.large)
Text("Settings")
.foregroundColor(.gray)
.font(.headline)
}
.padding(.top, 30)
Spacer()
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(.all)
}
}
}
struct SlideInMenuView_Previews: PreviewProvider {
static var previews: some View {
SlideInMenuView().environmentObject(Global())
}
}
struct ContentView: View {
#EnvironmentObject var global : Global
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
withAnimation {
self.global.showMenu = false
}
}
}
return GeometryReader { geometry in
ZStack(alignment: .leading) {
if self.global.showMenu {
SlideInMenuView()
.environmentObject(self.global)
.frame(width: geometry.size.width/1)
.transition(.move(edge: .leading))
.zIndex(3)
}
HomeSupportView()
.environmentObject(self.global)
.frame(width: geometry.size.width, height: geometry.size.height)
.cornerRadius(20)
.scaleEffect(self.global.showMenu ? 0.8 : 1)
.offset(x: self.global.showMenu ? 150 : 0, y : self.global.showMenu ? 50 : 0)
.disabled(self.global.showMenu ? true : false)
.zIndex((2))
MenuButton().environmentObject(self.global)
.zIndex(4)
}
.gesture(drag)
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(Global())
}
}
struct MenuButton: View {
#EnvironmentObject var global: Global
var body: some View {
Button(action: {
withAnimation {
self.global.showMenu.toggle()
}
}){
if self.global.showMenuButton {
Image(systemName: "line.horizontal.3")
.imageScale(.large)
.frame(width: 100, height: 60)
.background(Color.black)
.clipShape(Circle())
.opacity(0.8)
.foregroundColor(.white)
.rotationEffect(.degrees(self.global.showMenu ? 90 : 0))
.scaleEffect(self.global.showMenu ? 1.2 : 1)
} else {
EmptyView()
}
}
.padding(.top, -380)
}
}
SwiftUI has a zIndex() modifier that you can use to order the views.
This could help in your situation.
I'm using SwiftUI with Version 11.3.1 (11C504).
I Implement Tab bar on the Screen and that screen will come after the navigation from login Screen.
If navigation displayMode is .automatic so i’am showing a white space(which is in bordered with black line in picture) when I scroll a list in up side. Otherwise navigation title show.
And When I set displayMode, .inline so it works perfect. And when I run a project so many time so some time it works perfect and some time showing a space.
i mentioned a white space in the picture with black border.
//ContentView
struct ContentView: View {
var body: some View {
HomeTabView()
}
}
//HomeTabView
struct HomeTabView: View {
#State private var selection = 0
//Inclose user intraface of tab View.
var body: some View {
TabView(selection: $selection){
TestListView().tabItem {
Image(systemName: "book.fill")
Text("Learn")
}.tag(0)
Text("Community").tabItem {
Image(systemName: "globe")
Text("Community")
}.tag(1)
//Add Notification List on the Screen.
Text("Notification").tabItem {
Image(systemName: "bell.fill")
Text("Notification")
}.tag(3)
//Add Account on the Tab Bar
Text("Account").tabItem {
Image(systemName: "person.circle.fill")
Text("Account")
}.tag(4)
}.accentColor(.pink)
.navigationBarTitle("SwiftUI")
}
}
TestListView
struct TestListView: View {
var body: some View {
VStack{
List(1...10, id: \.self){ num in
ListCards()
}
}.edgesIgnoringSafeArea(.all)
}
}
//ListCards
struct ListCards: View {
var body: some View {
ZStack{
RoundedRectangle(cornerRadius: 16)
.frame(height: 180)
.foregroundColor(.white)
.shadow(radius: 5)
VStack(alignment: .leading, spacing: 10){
HStack(alignment: .top){
Rectangle()
.frame(width: 100, height: 100)
.cornerRadius(16)
.foregroundColor(.pink)
VStack(alignment: .leading, spacing: 4){
Text("SwiftUI")
.font(.title)
Text("Description of title")
.foregroundColor(.gray)
}
}
.padding()
}.padding(.leading, 2)
}.padding(.all, 6)
}
}
You need to change your HomeTabView in this way:
var body: some View {
TabView(selection: $selection) {
NavigationView {
TestListView()
.navigationBarTitle("SWIFTUI")
}.tabItem {
Image(systemName: "book.fill")
Text("Learn")
}.tag(0)
NavigationView {
Text("Community")
}.tabItem {
Image(systemName: "globe")
Text("Community")
}.tag(1)
//Add Notification List on the Screen.
NavigationView {
Text("Notification")
}.tabItem {
Image(systemName: "bell.fill")
Text("Notification")
}.tag(3)
//Add Account on the Tab Bar
NavigationView {
Text("Account")
}.tabItem {
Image(systemName: "person.circle.fill")
Text("Account")
}.tag(4)
}.accentColor(.pink)
}
also, remove .edgesIgnoringSafeArea(.all) from TestListView
I have a SwiftUI list/detail app with many data fields that are all the same except of
course for the data. I am trying to extract a view but cannot seem to get the
connections correct.
The data is in Core Data and the entity of note is Patient. I pass a patient record to
the detail view. Everything works when the code is repeated for each data field.
While I don't think the issue is with the custom modifier, for clarity I have included
the code for the custom modifier that adds a clear button. Strangely, I could not
find a built-in SwiftUI TextField clear button.
Here is the relevant code for an individual data element - this works:
var patient: Patient
#State private var updatedTitle: String = "No Title"
//title
VStack(alignment: .leading) {
Text("Person Title:")
.padding(.leading, 5)
.font(.headline)
HStack {
TextField("Enter a Title", text: $updatedTitle)
.frame(minWidth: 0, maxWidth: .infinity)
.padding(.trailing, -25)
.padding(.leading, 5)
.frame(height: 45)
.onAppear {
self.updatedTitle = self.patient.title ?? ""
}
Text("")
.frame(width: 35, height: 35)
.modifier(ClearButton(text: self.$updatedTitle))
.padding(.trailing, 15)
.padding(.leading, -20)
}
.background(Color("TextFieldBackground")).cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray, lineWidth: 1)
)
.padding(.leading, 10)
.padding(.trailing, 10)
}.padding(10)
This is my attempt to extract a subview:
struct MyDataCell {
#Binding var tfData: String
var passedInLabel: String
var patient: Patient
var body: some View {
VStack(alignment: .leading) {
Text(passedInLabel)
.padding(.leading, 5)
.font(.headline)
HStack {
TextField("Enter a Title", text: $tfData)
.frame(minWidth: 0, maxWidth: .infinity)
.padding(.trailing, -25)
.padding(.leading, 5)
.frame(height: 45)
.onAppear {
self.tfData = self.patient.title ?? ""
}
Text("")
.frame(width: 35, height: 35)
.modifier(ClearButton(text: $tfData))
.padding(.trailing, 15)
.padding(.leading, -20)
}
.background(Color("TextFieldBackground")).cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray, lineWidth: 1)
)
.padding(.leading, 10)
.padding(.trailing, 10)
}.padding(10)
}
}
This is the line of code I use to call the subview - the compiler instantly complains
with an error that has nothing to do with this line.
MyDataCell(tfData: $updatedTitle, passedInLabel: "Patient Title", patient: patient)
As mentioned, this is the code for the custom modifier:
struct ClearButton: ViewModifier {
#Binding var text: String
public func body(content: Content) -> some View {
HStack {
content
Button(action: {
self.text = ""
}) {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.secondary)
}
}
}
}
Xcode Version 11.2 beta 2 (11B44) I have tried both the simulator and a device. Any
guidance would be appreciated.
MyDataCell needs to confirm to View - struct MyDataCell: View {
A property needs to be passed in that is the actual attribute for the Entity. In this case pass in the string of patient.title instead of passing the Entity, Patient. Then in .onAppear use that string.
Lastly, remember the max 10 item per view - break the list into groups.