import SwiftUI
struct ContentView: View {
#State private var selectedDate: Date = Date()
var body: some View {
DatePicker("›", selection: self.$selectedDate)
.datePickerStyle(GraphicalDatePickerStyle() )
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
once you Tapp on the date picker the graph becomes fixed
anyone know of away around this thanks!
It seems like a bug. But You can fix it by adding horizontal padding or adding custom padding (padding should be > 15)
struct ContentViewDate: View {
#State private var selectedDate: Date = Date()
var body: some View {
DatePicker("", selection: $selectedDate)
.datePickerStyle(GraphicalDatePickerStyle())
.padding(.horizontal) // <<-- Add horizontal padding or set .padding(15)
}
}
Related
I am using SwiftUi 3.0 and I am new to it . I am learning about ObservedObjects . What I am trying to do is update the count of a variable every time that I close a view . This is the entire small app . The screen starts at DataUpdateView view when I click Next View I go to DataUpdateView2 view . Once I close DataUpdateView2 and go back to the original view I want to have the
Text("Score Count \(progress.score)")
score number increase by 1 since in the second view I do a +1 every time that I close that view . Any suggestions would be great
import SwiftUI
class UserProgress: ObservableObject {
#Published var score = 0
}
struct DataUpdateView: View {
#State var nextView = false
#StateObject var progress = UserProgress()
var body: some View {
VStack {
Text("Score Count \(progress.score)")
Text("Next View")
.onTapGesture {
nextView = true
}.fullScreenCover(isPresented: $nextView, content: {
DataUpdateView2()
})
}
}
}
struct DataUpdateView_Previews: PreviewProvider {
static var previews: some View {
DataUpdateView()
}
}
struct DataUpdateView2: View {
#ObservedObject var progress = UserProgress()
#Environment(\.presentationMode) var presentationMode
var body: some View {
Text("Back")
.onTapGesture {
progress.score += 1
self.presentationMode.wrappedValue.dismiss()
}
}
}
struct DataUpdateView2_Previews: PreviewProvider {
static var previews: some View {
DataUpdateView2()
}
}
You're probably not seeing the first view update since both views are instantiating their own UserProgress(). You need to pass the object you already created in the first view along to the second in the initializer
So In DataUpdateView:
.fullScreenCover(isPresented: $nextView, content: {
DataUpdateView2(progress: progress)
})
}
And then in DataUpdateView2:
struct DataUpdateView2: View {
#ObservedObject var progress: UserProgress
#Environment(\.presentationMode) var presentationMode
// ...
}
So now the second view is receiving the object from the first rather than creating its own.
Note: If you are not using an ObservableObject, then take a look at the second part.
In this specific situation, you don't even need a Binding variable, you can just use the .onDisappear method. .onDisappear Documentation.
import SwiftUI
class UserProgress: ObservableObject {
#Published var score = 0
}
struct DataUpdateView: View {
#State var nextView = false
#StateObject var progress = UserProgress()
var body: some View {
VStack {
Text("Score Count \(progress.score)")
Text("Next View")
.onTapGesture {
nextView = true
}.fullScreenCover(isPresented: $nextView, content: {
DataUpdateView2()
})
}
}
}
struct DataUpdateView_Previews: PreviewProvider {
static var previews: some View {
DataUpdateView()
}
}
struct DataUpdateView2: View {
#ObservedObject var progress = UserProgress()
#Environment(\.presentationMode) var presentationMode
var body: some View {
Text("Back")
.onTapGesture{
presentationMode.wrappedValue.dismiss()
print("Dismissed!")
}
.onDisappear{
//This is called when the view disappears.
progress.score += 1
}
}
}
struct DataUpdateView2_Previews: PreviewProvider {
static var previews: some View {
DataUpdateView2()
}
}
Second Part
If you want the variable to update when the view closes, you could use the .onDisappear method and a Binding value. An example implementation of this is below:
struct ViewOne: View{
#State var number = 0
var body: some View{
VStack{
Text("Number: \(number)")
NavigationLink(destination: ViewTwo(variable: $number)){
Text("Go To View Two")
}
}
}
}
struct ViewTwo: View{
#Binding var variable: Int
var body: some View{
//Content of view 2 here
Text("View Two")
.onDisappear{
//This is called when the view disappears
variable += 1
}
}
}
In short you need to use same view model in both views. A possible and seems simplest approach in your code is to inject view model from first view to second via environment object, like
#StateObject var progress = UserProgress()
var body: some View {
VStack {
Text("Score Count \(progress.score)")
Text("Next View")
.onTapGesture {
nextView = true
}.fullScreenCover(isPresented: $nextView, content: {
DataUpdateView2()
.environmentObject(progress) // << here !!
})
and use it internally, like
struct DataUpdateView2: View {
#EnvironmentObject var progress: UserProgress // << injected automatically !!
i am learning swiftui now and I am newbie for stackoverflow, I find a question,this is my code. I want to change the #State nopubName in sink ,but it's not work,the print is always "Nimar", I don't know why
struct ContentView: View {
#State var nopubName: String = "Nimar"
private var cancellable: AnyCancellable?
var stringSubject = PassthroughSubject<String, Never>()
init() {
cancellable = stringSubject.sink(receiveValue: handleValue(_:))
}
func handleValue(_ value: String) {
print("handleValue: '\(value)'")
self.nopubName = value
print("in sink "+nopubName)
}
var body: some View {
VStack {
Text(self.nopubName)
.font(.title).bold()
.foregroundColor(.red)
Spacer()
Button("sink"){
stringSubject.send("World")
print(nopubName)
}
}
}
}
You should only access a state property from inside the view’s body, or from methods called by it.
https://developer.apple.com/documentation/swiftui/state
You can get that functionality working in an ObservableObject and update an #Published To keep the UI updated
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
You don't need to use Combine, If you are within the View, you can change the value of #State variables directly
struct ContentView: View {
#State var nopubName: String = "Nimar"
var body: some View {
VStack {
Text(self.nopubName)
.font(.title).bold()
.foregroundColor(.red)
Spacer()
Button("sink"){
nopubName = "World"
}
}
}
}
I'm currently developing an application using SwiftUI.
This app has 3 structs
①ContentView
②FirstView
③SecondView
These 3 structs do page transition in Tab View.
And this app has a common variable type of Bool using ObservableObject annotation.
I want to change to appear and disappear Text View in the FirstView and the SecondView depends on the condition of the variable, but the FirstView doesn't change a view as I expected...
How can I solve this situation?
Here are the codes:
ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
FirstView()
.tabItem {
Text("First")
}.tag(1)
SecondView()
.tabItem {
Text("Second")
}.tag(2)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
FirstView.swift
import SwiftUI
struct FirstView: View {
#ObservedObject var firstCheck: ViewModel = ViewModel()
var body: some View {
VStack{
if firstCheck.check == true{
Text("checked")
}
}
}
}
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView()
}
}
SecondView.swift
import SwiftUI
struct SecondView: View {
#ObservedObject var secondCheck = ViewModel()
var body: some View {
VStack{
Toggle(
isOn: $secondCheck.check
){
Text("change")
}
if self.secondCheck.check == true{
Text("checked")
}
}
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView()
}
}
ViewModel.swift
import Foundation
final class ViewModel: ObservableObject {
#Published var check: Bool = false
}
Xcode: Version 11.7
Keep object in one place, can be parent view
struct ContentView: View {
#ObservedObject var viewModel = ViewModel()
// #StateObject var viewModel = ViewModel() // SwiftUI 2.0
var body: some View {
TabView {
// .. other code here
}
.environmentObject(viewModel) // << inject here
}
}
and then use in both views like (for second the same)
struct FirstView: View {
#EnvironmentObject var firstCheck: ViewModel // declare only
// will be injected by type
var body: some View {
VStack{
if firstCheck.check == true{
Text("checked")
}
}
}
}
I just updated to Xcode 11.4 and it's broken my code. I am storing some user settings in an ObservableObject as follows:
class UserSettings: ObservableObject {
#Published var cardOrder = UserDefaults.standard.integer(forKey: "Card Order")
#Published var cardTheme = UserDefaults.standard.integer(forKey: "Card Theme")
#Published var translation = UserDefaults.standard.integer(forKey: "Translation")
#Published var overdueFirst = UserDefaults.standard.bool(forKey: "Overdue First")
#Published var randomNum = 0
}
This is my main menu, the settings environment object is successfully passed down to the Settings view where I'm able to save and retrieve user selections.
struct ContentView: View {
#State var settings = UserSettings()
var body: some View {
SubView().environmentObject(settings)
}
}
struct SubView: View {
#EnvironmentObject var settings: UserSettings
var body: some View {
List {
NavigationLink (destination: Flashcard()){
HStack {
Image(systemName: "rectangle.on.rectangle.angled")
Text(verbatim: "Study")
}
}
NavigationLink (destination: Settings()) {
HStack {
Image(systemName: "gear")
Text(verbatim: "Settings")
}
}
}
}
}
But in my flashcard view, I am getting an error: Fatal error: No ObservableObject of type UserSettings found. A View.environmentObject(_:) for UserSettings may be missing as an ancestor of this view.: file SwiftUI, line 0
The error is on line 13 where I initiate Frontside. In the original code, I just called the Frontside subview, but I thought to solve the error I had to add .environmentObject(settings), but even after adding it my app compiles but crashes as soon I go to the Flashcard view.
struct Flashcard: View {
#EnvironmentObject var settings: UserSettings
#State var colour = UserDefaults.standard.integer(forKey: "Card Theme") * 6
#State private var showResults: Bool = false
#State private var fullRotation: Bool = false
#State private var showNextCard: Bool = false
var body: some View {
let zstack = ZStack {
Frontside(id: $settings.randomNum, sheet: $showingSheet, rotate: $fullRotation, invis: $showNextCard, col: $colour).environmentObject(self.settings)
//
Backside(id: $settings.randomNum, sheet: $showingSheet, bookmark: $bookmarked, results: $showResults, rotate: $fullRotation, invis: $showNextCard, col: $colour, trans: $translation).environmentObject(self.settings)
//
}
}
Does anyone know what I'm doing wrong? This code compiled and ran fine in the previous Xcode.
I think you should pass settings object to FlashCard and Settings as well.
try this:
struct ContentView: View {
#State var settings = UserSettings()
var body: some View {
SubView().environmentObject(settings)
}
}
struct SubView: View {
#EnvironmentObject var settings: UserSettings
var body: some View {
List {
NavigationLink (destination: Flashcard().environmentObject(settings)){
HStack {
Image(systemName: "rectangle.on.rectangle.angled")
Text(verbatim: "Study")
}
}
NavigationLink (destination: Settings().environmentObject(settings)) {
HStack {
Image(systemName: "gear")
Text(verbatim: "Settings")
}
}
}
}
}
An #EnvironmentObject has to be filled with an #StateObject, an #ObservedObject or an ObservableObject directly NOT an #State
struct ContentView: View {
//#ObservedObject
#StateObject var settings = UserSettings()
var body: some View {
SubView().environmentObject(settings)
}
}
Note: UserSettings has to be an ObservableObject
Apple documentation on managing model data
struct BookReader: App {
#StateObject var library = Library()
var body: some Scene {
WindowGroup {
LibraryView()
.environmentObject(library)
}
}
}
struct LibraryView: View {
#EnvironmentObject var library: Library
// ...
}
I'm running iOS 14.3 in the simulator and in my case the error was about my environmentObject NavigationController. It was resolved by modifying ContentView() with .environmentObject(NavigationController()) in the SceneDelegate and, if you want the preview to work, also in ContentView_Previews.
import SwiftUI
#main
// there is a file with the name of your "projectApp" (JuegosSwiftUIApp in my case)
struct JuegosSwiftUIApp: App {
var body: some Scene {
WindowGroup {
DatosIniciales() // any view
.environmentObject(Datos()) // this solved it (Datos() is class type Observableobject)
}
}
}
Swiftui: I can show the data from db in list ,but it shown nothing in picker, how can I fix it
here is my ContentView:
import SwiftUI
struct ContentView: View {
#ObservedObject var model = PostListViewModel()
#State private var selectedStrength = 0
var body: some View {
// List(model.posts) { post in
// Text(post.name)
// }
Picker(selection: $selectedStrength, label: Text("picker")) {
ForEach(model.posts) { post in
Text(post.name)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
try this or something similar:
ForEach(model.posts, id: \.self) { post in
Text(post.name)
}