SwiftUI Remove List padding fand Row spacing? - list

i am trying to remove the spacing & padding to List row's , its not working after spending hours trying many solutions .
List View :
import SwiftUI
struct Item {
let uuid = UUID()
let value: String
}
struct w_tasks: View {
#State private var items = [Item]()
var body: some View {
ZStack(alignment: .leading){
List(self.items, id: \.uuid) {item in
cl_task().listRowInsets(EdgeInsets())
}
.listStyle(SidebarListStyle())
.frame(width: UIScreen.main.bounds.width )
.onAppear {
DispatchQueue.main.async {
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
}
}
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
self.items.append(Item(value: "Item"))
}, label: {
Text("+")
.font(.system(size: 30))
.frame(width: 50, height: 50)
.foregroundColor(Color.white)
.padding(.bottom, 5)
})
.background(Color(hex : "#216D94"))
.frame(width: 50, height: 50)
.cornerRadius(25)
.padding()
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
}
}
}.background(Color.black)
}
}
struct w_tasks_Previews: PreviewProvider {
static var previews: some View {
w_tasks()
}
}
Row Bite :
import SwiftUI
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
//Swipe to custom options ,by "Jack" this option not yet available in SwiftUI
let drag = DragGesture(minimumDistance: 25, coordinateSpace: .local)
.onChanged {
if (self.offset.width > 0 ){ return }
self.offset.width = $0.translation.width
}.onEnded {
if $0.translation.width < -100 {
self.offset = .init(width: -100, height: 0)
} else {
self.offset = .zero
}
}
ZStack{
Rectangle().foregroundColor(.blue).offset(x: offset.width, y: offset.height)
.gesture(drag)
.animation(.easeIn, value: offset)
Text("test").foregroundColor(.white)
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 120,
maxHeight: .infinity,
alignment: .topLeading
)
}
}
struct cl_task_Previews: PreviewProvider {
static var previews: some View {
cl_task().previewLayout(.sizeThatFits)
}
}
And when i add The List inside NavigationView the divider is showing again and i can't remove it any idea why!

For testing and showing that there is no problem with massive data, I pre loaded 10_000 row. is that enough?
your issues:
1.you should make your Item type Identifiable, then you can put out uuid from your list or ForEach.
2.you should not gave frame size to your row, they can take max space automatically.
3.you can put your button over your View, and save some more coding, like I did.
4.you should not use CGSize for offset, because you are just working on one dimension, and CGFloat is enough.
5.you should and must use LazyVStack if your data is massive as you said 400 is to many, then use LazyVStack for sure.
struct Item: Identifiable {
let id: UUID = UUID()
let value: String
}
struct ContentView: View {
#State private var items: [Item] = [Item]()
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
ScrollView {
LazyVStack(spacing: 0) {
ForEach(items) {item in
RowView(stringOfText: item.value)
.frame(height: 120)
}
}
}
.background(Color.black)
.onAppear() { for _ in 0...10_000 { addNewData() } }
}
.overlay(addButton, alignment: .bottomTrailing)
.animation(.easeInOut)
}
var addButton: some View {
Button(action: { addNewData() }, label: {
Image(systemName: "plus.circle").foregroundColor(Color.white).font(Font.largeTitle.weight(Font.Weight.bold)).padding()
})
}
func addNewData() { items.append(Item(value: "item " + items.count.description)) }
}
struct RowView: View {
let stringOfText: String
#State private var offset: CGFloat = CGFloat()
var body: some View {
ZStack {
Color.blue
Text(stringOfText)
.foregroundColor(Color.white)
.padding()
}
.offset(x: offset)
.gesture(dragGesture)
}
var dragGesture: some Gesture {
DragGesture(minimumDistance: 25, coordinateSpace: .local)
.onChanged {
if (offset > 0 ){ return }
offset = $0.translation.width
}.onEnded {
if $0.translation.width < -100 {
offset = -100
} else {
offset = 0
}
}
}
}

So this is what I have
The method you tried will work, but not on Lists, nest a ForEach inside of your list and then attach that modifier and you should be good. Also of course just tweak your modifiers to your liking of course.
Also, the way to get the spacing from between the list rows is setting a height limit on them. I just set 50 but again, modify as you see fit.
struct Item {
let uuid = UUID()
let value: String
}
struct w_tasks: View {
#State private var items = [Item]()
var body: some View {
ZStack(alignment: .leading){
// List(self.items, id: \.uuid)
List {
ForEach(self.items, id: \.uuid) { item in
cl_task().listRowInsets(EdgeInsets(.init(top: 20, leading: -20, bottom: 20, trailing: -20)))
.frame(height: 50)
}
}
.listStyle(InsetListStyle())
.frame(width: UIScreen.main.bounds.width )
.onAppear {
DispatchQueue.main.async {
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
self.items.append(Item(value: "Item"))
}
}
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
self.items.append(Item(value: "Item"))
}, label: {
Text("+")
.font(.system(size: 30))
.frame(width: 50, height: 50)
.foregroundColor(Color.white)
.padding(.bottom, 5)
})
.background(Color("#216D94"))
.frame(width: 50, height: 50)
.cornerRadius(25)
.padding()
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
}
}
}.background(Color.black)
}
}
struct w_tasks_Previews: PreviewProvider {
static var previews: some View {
w_tasks()
}
}
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
//Swipe to custom options ,by "Jack" this option not yet available in SwiftUI
let drag = DragGesture(minimumDistance: 25, coordinateSpace: .local)
.onChanged {
if (self.offset.width > 0 ){ return }
self.offset.width = $0.translation.width
}.onEnded {
if $0.translation.width < -100 {
self.offset = .init(width: -100, height: 0)
} else {
self.offset = .zero
}
}
ZStack{
Rectangle().foregroundColor(.blue).offset(x: offset.width, y: offset.height)
.gesture(drag)
.animation(.easeIn, value: offset)
Text("test").foregroundColor(.white)
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 120,
maxHeight: .infinity,
alignment: .topLeading
)
}
}
struct cl_task_Previews: PreviewProvider {
static var previews: some View {
cl_task().previewLayout(.sizeThatFits)
}
}

Related

How to have a Navigation link open a different view?

I keep trying to have the navigation links in the surveys list in contentView to open detailView when selected. I keep getting errors Missing argument for parameter 'newsurvey' in call Insert 'newsurvey: <#Survey#>'
Here's the home view
struct ContentView: View {
#State var surveys: [Survey] = []
#State var isPresented = false
#State var selectedTab: Int = 0
#State private var path = [String]()
let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
return formatter
}()
var body: some View {
ZStack {
VStack{
NavigationView {
VStack {
Text("")
.frame(height: 0)
.navigationBarTitleDisplayMode(.inline)
//reduces navbartitle height
.toolbar {
ToolbarItem(placement: .principal) {
Image("RR_Logo_Primary_Full_Color")
.resizable()
.frame(width: 275.0, height: 55.0)
}
}
List(surveys) { survey in
NavigationLink(destination: DetailView(newsurvey: survey)) //must be within navigationview
{
HStack{
ZStack {
Rectangle()
.frame(width: 400, height: 100.0)
.foregroundColor(.white)
.cornerRadius(4)
HStack (alignment: .top) {
VStack (alignment: .leading) {
Text(survey.customerName)
.offset(x: -60, y: -2)
.font(.custom("Roboto-Light", size: 24))
Text(survey.lineName)
.offset(x: -60, y: -5)
.font(.custom("Roboto-Light", size: 18))
Text("# of conveyors")
.offset(x: -60)
}
VStack {
Text(dateFormatter.string(from: survey.date))
.font(.custom("Roboto-Light", size: 18))
.offset(x: 60)
}
}
}
}
}
}
.listRowInsets(EdgeInsets())
}
}
.environment(\.defaultMinListHeaderHeight, 1)
CustomTabBar(surveys: $surveys, isPresented: $isPresented)
.frame(height: 60, alignment: .bottom)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I tried the following code below but I keep getting not in scope error.
#State var newsurvey: Survey
#State var surveys: [Survey] = []
#State private var conveyorName = ""
#State private var masterTag = ""
#State private var showAddConveyorSheet = false
#State private var conveyors: [Conveyor] = []
var body: some View {
NavigationView {
VStack {
List {
ForEach(conveyors, id: \.name) { conveyor in
NavigationLink(destination: ConveyorTrack(conveyor: conveyor)) {
Text(conveyor.name)
}
}
}
Button(action: {
self.showAddConveyorSheet = true
}) {
Text("Add Conveyor")
}
}
.navigationBarTitle("Conveyors", displayMode: .inline)
.sheet(isPresented: $showAddConveyorSheet) {
VStack {
HStack {
TextField("Conveyor Name", text: $conveyorName)
TextField("Master Tag", text: $masterTag)
.onTapGesture {
// open camera and scan text here
}
}
Button(action: {
self.conveyors.append(Conveyor(id: self.conveyorName, name: self.conveyorName, masterTag: self.masterTag))
self.conveyorName = ""
self.masterTag = ""
self.showAddConveyorSheet = false
}) {
Text("Save")
}
}
}
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(newsurvey: survey)
}
}

SwiftUI : How I can hide the navigationBar when the keyboard is shown

enter image description here
Please check attached image file, that is situation of mine.
I tried to make this view, but when the keyboard is shown. The main view and navigationBar is mixed.
I hope to hide the navigationBar when I touched the textfield and keyboard is shown.
How I treat that? Thank you all
This is source code below.
import SwiftUI
struct FlashCardView: View {
#EnvironmentObject var itemModel : ItemModel
var item : Item
#State var isGeneral : Bool = true
#State var inputAnswer : String = ""
#State var showAlert : Bool = false
#State var isAnswer : Bool = false
#State var randomWord : (String, String) = ("", "")
var body: some View {
VStack {
HStack {
if let group = item.group {
Text("Game with ' \(group) '")
.font(.title3.bold())
.lineLimit(1)
.padding()
.background(
Color.yellow
.frame(height : 4)
.offset(y : 24)
)
}
}
HStack {
Button(action: {
isGeneral = true
makeNewCard()
}, label: {
Text(isGeneral ? "General 🔥" : "General")
.font(.headline)
.foregroundColor(isGeneral ? .white : .black)
.frame(width : 140, height : 50)
.background(isGeneral ? .blue : .gray)
.cornerRadius(10)
.padding()
})
.shadow(color: .gray.opacity(0.5), radius: 3, x: 3, y: 3)
Spacer()
Button(action: {
isGeneral = false
makeNewCard()
}, label: {
Text(!isGeneral ? "Favorite 🔥" : "Favorite")
.font(.headline)
.foregroundColor(!isGeneral ? .white : .black)
.frame(width : 140, height : 50)
.multilineTextAlignment(.center)
.background(!isGeneral ? .blue : .gray)
.cornerRadius(10)
.padding()
})
.disabled(item.children.filter({$0.isFavorite}).isEmpty)
.shadow(color: .gray.opacity(0.5), radius: 3, x: 3, y: 3)
}
Text(randomWord.0)
.font(.title2.bold())
.frame(maxWidth : .infinity)
.frame(height : UIScreen.main.bounds.height*0.33)
.multilineTextAlignment(.center)
.background(.ultraThinMaterial)
.cornerRadius(20)
.shadow(color: .gray.opacity(0.4), radius: 3, x: 3, y: 3)
.padding()
TextField("What is the answer?", text: $inputAnswer)
.frame(maxWidth : .infinity)
.frame(height : 60)
.font(.body)
.multilineTextAlignment(.center)
.autocapitalization(.none)
.submitLabel(.done)
.onSubmit {
if randomWord.1 == inputAnswer {
self.showAlert.toggle()
self.isAnswer = true
self.inputAnswer = ""
} else {
self.showAlert.toggle()
self.isAnswer = false
self.inputAnswer = ""
}
}
Divider()
.padding(.horizontal)
.padding(.vertical, -10)
Button(action: {
if randomWord.1 == inputAnswer {
self.showAlert.toggle()
self.isAnswer = true
self.inputAnswer = ""
} else {
self.showAlert.toggle()
self.isAnswer = false
self.inputAnswer = ""
}
}, label: {
Label("Check", systemImage: "checkmark.rectangle.fill")
.frame(maxWidth : .infinity)
.frame(height : 60)
.font(.headline)
.foregroundColor(.white)
.multilineTextAlignment(.center)
.background(Color.green)
.cornerRadius(10)
.shadow(color: .gray.opacity(0.4), radius: 3, x: 3, y: 3)
.padding()
})
.alert(isPresented : $showAlert) {
Alert(title: Text(isAnswer ? "Nice! that is answer!" : "Sorry, It was not answer.."), message: Text(isAnswer ? "You got an answer! Cool! 🥰" : "It's OK!, Keep studying! 😋"), dismissButton: .default(Text("OK")) {
makeNewCard()
})
}
.disabled(inputAnswer.count == 0)
} // vst
.padding()
.onAppear {
makeNewCard()
}
.navigationTitle("Flashcard Game 🎲")
}
}
extension FlashCardView {
func makeNewCard() {
if isGeneral == true {
randomWord = itemModel.makeRandomChildren(item: item)
} else {
randomWord = itemModel.makeRandomFavoriteChildren(item: item)
}
}
}
Add onEditingChanged to the keyboard and add a conditional to the navBar.
If the navBar doesn't hide when the user answers the question, add another toggle to onCommit.
import SwiftUI
struct ContentView: View {
#State var inputAnswer: String = ""
#State var isTyping: Bool = false
var body: some View {
NavigationView {
VStack(alignment: .center) {
Text("Hide navbar when user interacts with the textField")
.padding()
TextField("What is the answer?", text: $inputAnswer, onEditingChanged: {
self.isTyping = $0 // <= Toggle boolean if user interacts with the textField
})
.keyboardType(.default)
}
.navigationTitle("Home")
.navigationBarHidden(isTyping ? true : false) // <= hide on the condition of the boolean
}
}
}

Can't sheet with button in ListView SwiftUI

I have a list. In the List there are 2 buttons.
I want to click on each button to present another view with Sheet.
When I first click it it works, but the second time or another tap button it doesn't present the view. Hope you can help me.
My code
My design
Read up on how to use Buttons and sheets. Typically Buttons triggering a sheet is used like this:
EDIT: with suggestion from Philip Dukhov, replace:
Button("Learning") {
}.sheet(isPresented: $isLearning, content: {
LearningView()
})
.onTapGesture {
self.isLearning = true
}
with:
Button(action: {isLearning = true}) {
Text("Learning")
}
.sheet(isPresented: $isLearning) {
LearningView()
}
and do the same for "Test" button, with "isTest" instead of "isLearning" and "TestViewCategory()" instead of "LearningView()".
EDIT 2:
Update "TestView" with:
struct TestView: View {
var title = ""
let models = modelItems
var body: some View {
ScrollView {
VStack {
ForEach(models) { model in
TopicList(model: model)
}
}
}
.navigationBarTitle(title, displayMode: .inline)
.onAppear {
UITableView.appearance().separatorStyle = .none
}
.animation(.spring())
}
}
EDIT 3: here is the test code that works for me:
import SwiftUI
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
TestView()
}
}
}
struct ButtonView: View {
#State var isLearning: Bool = false
#State var isTest: Bool = false
var body: some View {
HStack {
Button(action: {isLearning = true}) {
Text("Learning")
}
.sheet(isPresented: $isLearning) {
Text("LearningView")
}
.font(.system(size: 16))
.frame(width: 132 , height: 48)
.background(Color(.white))
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color(#colorLiteral(red: 0.9259920716, green: 0.9261471629, blue: 0.9259716272, alpha: 1)), lineWidth: 1)
)
Button(action: {isTest = true}) {
Text("Test")
}
.sheet(isPresented: $isTest) {
Text("TestViewCategory")
}
.font(.system(size: 16))
.frame(width: 132 , height: 48)
.background(Color(.white))
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(Color(#colorLiteral(red: 0.9259920716, green: 0.9261471629, blue: 0.9259716272, alpha: 1)), lineWidth: 1)
)
}
}
}
struct TopicList: View {
// for testing
let model: String
#State private var showSubItem = false
var body: some View {
VStack {
HStack {
Image(systemName: showSubItem ? "arrow.up.circle" : "arrow.down.circle")
.resizable()
.frame(width: 26, height: 26)
.onTapGesture {
withAnimation {
showSubItem.toggle()
}
}
VStack {
VStack(alignment: .leading) {
Text("title")
.font(.custom("Poppins-Regular", size: 24))
.padding(.top,9)
.padding(.bottom,4)
HStack {
Text("Open date")
.font(.custom("Poppins-Regular", size: 12))
Text("Open date")
.font(.custom("Poppins-Regular", size: 12))
Text("Due date")
.font(.custom("Poppins-Regular", size: 12))
Text("Due date")
.font(.custom("Poppins-Regular", size: 12))
}
}
.padding(.leading,17)
.frame(width: 320, height: 70)
.fixedSize(horizontal: false, vertical: true)
if showSubItem {
ButtonView()
.padding(.top,12)
.fixedSize(horizontal: false, vertical: true)
.transition(.opacity)
.transition(.slide)
.padding(.bottom,13)
}
}
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(#colorLiteral(red: 0.9259920716, green: 0.9261471629, blue: 0.9259716272, alpha: 1)), lineWidth: 1)
)
}
}
}
}
struct TestView: View {
var title = "nav title"
let models = ["1","2","3"]
var body: some View {
ScrollView {
VStack {
ForEach(models, id: \.self) { model in
TopicList(model: model)
}
}
}
.navigationBarTitle(title, displayMode: .inline)
.onAppear {
UITableView.appearance().separatorStyle = .none
}
.animation(.spring())
}
}

SwiftUI DragGesture blocking List vertical scroll?

i am trying to add swipe inside list cell , swipe to show more options such as Delete, archive etc .
The swipe is working just fine , but the List ( vertical scroll ) is no longer scrolling up down .
Cell Bite :
import SwiftUI
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
//Swipe to custom options ,by "Jack" this option not yet available in SwiftUI
let drag = DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged {
if (self.offset.width > 0 ){ return }
self.offset.width = $0.translation.width
}.onEnded {
if $0.translation.width < -100 {
self.offset = .init(width: -100, height: 0)
} else {
self.offset = .zero
}
}
ZStack{
Rectangle().foregroundColor(.blue).offset(x: offset.width, y: offset.height)
.gesture(drag)
.animation(.easeIn, value: offset)
Text("test").foregroundColor(.white)
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 100,
maxHeight: .infinity,
alignment: .topLeading
)
}
}
struct cl_task_Previews: PreviewProvider {
static var previews: some View {
cl_task().previewLayout(.sizeThatFits)
}
}
List main view :
struct Item {
let uuid = UUID()
let value: String
}
struct w_tasks: View {
#State private var items = [Item]()
var body: some View {
ZStack {
List(self.items, id: \.uuid) {item in
cl_task()
}
.simultaneousGesture(DragGesture().onChanged({ value in
//Scrolled
}))
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
self.items.append(Item(value: "Item"))
}, label: {
Text("+")
.font(.system(size: 50))
.frame(width: 77, height: 70)
.foregroundColor(Color.white)
.padding(.bottom, 7)
})
.background(Color(hex : "#216D94"))
.cornerRadius(38.5)
.padding()
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
}
}
}
}
}
struct w_tasks_Previews: PreviewProvider {
static var previews: some View {
w_tasks()
}
}
I've posted my question after spending hours solving this issue as i am new to SwiftUI , any advice how to solve it ?
The solution is to give different distance for swipe, like below
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
// give 25 distance makes vertical scroll enabled !!
let drag = DragGesture(minimumDistance: 25, coordinateSpace: .local)
.onChanged {
Tested with Xcode 12.4 / iOS 14.4

NavigationView + TextField Background

I'm currently learning SwiftUI and building a todo list app. On the ContentView screen I've got a NavigationView and a button that pops up an "add new task" textfield into the list. I suspect this is not the correct way to implement this but when the textfield shows up the background color doesn't persist. For the life of me I can't figure out how to set the background color. If I move the textfield outside the NavigationView I can set the background but when the NavigationView shifts to make space for the textfield I get a bunch of black screen flicker. Any thoughts on how I can set the background color on the textfield when added to the list or fix the screen flicker when I move it out? Appreciate the help.
import SwiftUI
import UIKit
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(entity: ToDoItem.entity(), sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)]) var listItems: FetchedResults<ToDoItem>
#State private var newToDoItem = ""
#State private var showNewTask = false
#State var isEditing = false
#State var showTaskView = false
#State var bottomState = CGSize.zero
#State var showFull = false
#State var deleteButton = false
//this removes the lines in the list view
init() {
// To remove only extra separators below the list:
UITableView.appearance().tableFooterView = UIView()
// To remove all separators including the actual ones:
UITableView.appearance().separatorStyle = .none
UIScrollView.appearance().backgroundColor = .clear
//UITableView.appearance().backgroundColor = .clear
}
var body: some View {
ZStack{
VStack{
TitleView()
NavigationView {
List {
if showNewTask {
HStack{
TextField("New task", text: self.$newToDoItem, onEditingChanged: { (changed) in
}) {
print("onCommit")
self.addTask(taskTitle: self.newToDoItem)
self.saveTasks()
self.showNewTask.toggle()
self.newToDoItem = ""
}
.font(Font.system(size: 18, weight: .bold))
.foregroundColor(Color("Text"))
Button(action: {
self.newToDoItem = ""
self.showNewTask.toggle()
}) {
Image(systemName: "xmark.circle").foregroundColor(Color("button"))
.font(Font.system(size: 18, weight: .bold))
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.background(Color("addNewTask"))
.cornerRadius(10.0)
}
ForEach(listItems, id: \.self) {item in
HStack {
Button(action: {
item.isComplete = true
self.saveTasks()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5){
self.deleteTaskTest(item: item)
}
}) {
if (item.isComplete) {
Image(systemName: "checkmark.circle")
.font(Font.system(size: 25, weight: .bold))
.foregroundColor(Color(#colorLiteral(red: 0.1616941956, green: 0.9244045403, blue: 0.1405039469, alpha: 1)))
.padding(.trailing, 4)
} else {
Image(systemName: "circle")
.font(Font.system(size: 25, weight: .bold))
.foregroundColor(Color("button"))
.padding(.trailing, 4)
}
}
.buttonStyle(PlainButtonStyle())
ToDoItemView(title: item.title, createdAt: "\(item.createdAt)")
.onTapGesture {
self.showTaskView.toggle()
}
.onLongPressGesture(minimumDuration: 0.1) {
self.isEditing.toggle()
print("this is a long press test")
}
}
.listRowBackground(Color("background"))
}
.onMove(perform: moveItem)
.onDelete(perform: deleteTask)
}
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
.navigationBarTitle(Text("ToDay"), displayMode: .large)
.navigationBarHidden(true)
.background(Color("background"))
}
//ADD A NEW TASK BUTTON
HStack {
Spacer()
Button(action: {
self.showNewTask.toggle()
}) {
Image(systemName: "plus")
.font(.system(size: 18, weight: .bold))
.frame(width: 36, height: 36)
.background(Color("button"))
.foregroundColor(.white)
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
}
}
.padding()
}
.blur(radius: showTaskView ? 20 : 0)
.animation(.default)
.padding(.top, 30)
//BOTTOM CARD VIEW
TaskView()
.offset(x: 0, y: showTaskView ? 360 : 1000)
.offset(y: bottomState.height)
.animation(.timingCurve(0.2, 0.8, 0.2, 1, duration: 0.5))
.gesture(
DragGesture().onChanged { value in
self.bottomState = value.translation
if self.showFull {
self.bottomState.height += -300
}
if self.bottomState.height < -300 {
self.bottomState.height = -300
}
} .onEnded { value in
if self.bottomState.height > 50 {
self.showTaskView = false
}
if (self.bottomState.height < -100 && !self.showFull) || (self.bottomState.height < -250 && self.showFull){
self.bottomState.height = -300
self.showFull = true
} else {
self.bottomState = .zero
self.showFull = false
}
}
)
}
.background(Color("background").edgesIgnoringSafeArea(.all))
}
Finally got it to work. For whatever reason reworking the stacks fixed it.
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(entity: ToDoItem.entity(), sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)]) var listItems: FetchedResults<ToDoItem>
#State private var showCancelButton: Bool = false
#State private var newToDoItem = ""
#State private var showNewTask = false
#State var isEditing = false
#State var showTaskView = false
#State var bottomState = CGSize.zero
#State var showFull = false
#State var deleteButton = false
var itemName = ""
init() {
// To remove all separators including the actual ones:
UITableView.appearance().separatorStyle = .none
UITableView.appearance().backgroundColor = .clear
}
var body: some View {
ZStack {
VStack {
NavigationView {
VStack {
TitleView()
.padding(.top, 20)
.background(Color("background"))
// Enter new task view
if showNewTask {
HStack {
HStack {
TextField("New task", text: self.$newToDoItem, onEditingChanged: { (changed) in
}) {
self.addTask(taskTitle: self.newToDoItem)
self.saveTasks()
self.showNewTask.toggle()
self.newToDoItem = ""
}
.font(Font.system(size: 18, weight: .bold))
.foregroundColor(Color("Text"))
Button(action: {
self.newToDoItem = ""
self.showNewTask.toggle()
}) {
Image(systemName: "xmark.circle").foregroundColor(Color("button"))
.font(Font.system(size: 18, weight: .bold))
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.background(Color("addNewTask"))
.cornerRadius(10.0)
}
.background(Color("background"))
.padding(.horizontal)
}
List {
ForEach(listItems, id: \.self) {item in
HStack {
Button(action: {
item.isComplete = true
self.saveTasks()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5){
self.deleteTaskTest(item: item)
}
}) {
if (item.isComplete) {
Image(systemName: "checkmark.circle")
.font(Font.system(size: 25, weight: .bold))
.foregroundColor(Color(#colorLiteral(red: 0.1616941956, green: 0.9244045403, blue: 0.1405039469, alpha: 1)))
.padding(.trailing, 4)
} else {
Image(systemName: "circle")
.font(Font.system(size: 25, weight: .bold))
.foregroundColor(Color("button"))
.padding(.trailing, 4)
}
}
.buttonStyle(PlainButtonStyle())
ToDoItemView(title: item.title, createdAt: "\(item.createdAt)")
.onTapGesture {
//item.title = self.itemName
self.showTaskView.toggle()
}
.onLongPressGesture(minimumDuration: 0.1) {
self.isEditing.toggle()
print("this is a long press test")
}
}
.listRowBackground(Color("background"))
}
.onMove(perform: moveItem)
.onDelete(perform: deleteTask)
}
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
.navigationBarTitle(Text("ToDay"), displayMode: .large)
.navigationBarHidden(true)
.background(Color("background"))
}
.background(Color("background").edgesIgnoringSafeArea(.all))
}
HStack {
Spacer()
Button(action: {
//withAnimation(){
self.showNewTask.toggle()
//}
}) {
Image(systemName: "plus")
.font(.system(size: 18, weight: .bold))
.frame(width: 36, height: 36)
.background(Color("button"))
.foregroundColor(.white)
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
}
}
.padding()
}
.blur(radius: showTaskView ? 20 : 0)
//BOTTOM CARD VIEW
TaskView()
.offset(x: 0, y: showTaskView ? 360 : 1000)
.offset(y: bottomState.height)
.animation(.timingCurve(0.2, 0.8, 0.2, 1, duration: 0.5))
.gesture(
DragGesture().onChanged { value in
self.bottomState = value.translation
if self.showFull {
self.bottomState.height += -300
}
if self.bottomState.height < -300 {
self.bottomState.height = -300
}
} .onEnded { value in
if self.bottomState.height > 50 {
self.showTaskView = false
}
if (self.bottomState.height < -100 && !self.showFull) || (self.bottomState.height < -250 && self.showFull){
self.bottomState.height = -300
self.showFull = true
} else {
self.bottomState = .zero
self.showFull = false
}
}
)
}
.animation(.default)
.background(Color("background").edgesIgnoringSafeArea(.all))
}
func moveItem(indexSet: IndexSet, destination: Int){
let source = indexSet.first!
if source < destination {
var startIndex = source + 1
let endIndex = destination - 1
var startOrder = listItems[source].order
while startIndex <= endIndex {
listItems[startIndex].order = startOrder
startOrder = startOrder + 1
startIndex = startIndex + 1
}
listItems[source].order = startOrder
} else if destination < source {
var startIndex = destination
let endIndex = source - 1
var startOrder = listItems[destination].order + 1
let newOrder = listItems[destination].order
while startIndex <= endIndex {
listItems[startIndex].order = startOrder
startOrder = startOrder + 1
startIndex = startIndex + 1
}
listItems[source].order = newOrder
}
saveTasks()
self.isEditing.toggle()
}
func deleteTask(indexSet: IndexSet){
let source = indexSet.first!
let listItem = listItems[source]
//self.deleteButton.toggle()
managedObjectContext.delete(listItem)
saveTasks()
}
func deleteTaskTest(item: ToDoItem){
managedObjectContext.delete(item)
saveTasks()
}
func addTask(taskTitle: String) {
let newTask = ToDoItem(context: managedObjectContext)
newTask.title = taskTitle
newTask.order = (listItems.last?.order ?? 0) + 1
newTask.createdAt = Date()
}
func saveTasks() {
do {
try managedObjectContext.save()
} catch {
print(error)
}
}