Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 10 days ago.
Improve this question
I get an error when i can press "fix", it will change my code to
timerString = Int((Date().timeIntervalSince( self.startTime)), format: "\(timerString)") - but then I get an error "No exact matches in a call to initializer" and I don't know what to do...
So, here is my code earlier "fixing" which as I said gives me an error too.
I want to multiply integer - timerString and get an integer too.
struct DayOnWorkView: View {
#State private var ifTapped = false
// #State var isTimerRunning = false // it was for timer
#State private var startTime = Date()
#State private var timerString = 0
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
NavigationView {
ZStack {
BackgroundView()
VStack(alignment: .center) {
Button(action: {
self.ifTapped.toggle()
}, label: {
Image(systemName: ifTapped ? "person.crop.circle.badge.checkmark" : "person.crop.circle.badge.xmark")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.onTapGesture {
if !ifTapped {
timerString = 0
startTime = Date()
}
ifTapped.toggle()
}
Text(ifTapped ? "Online" : "Offline")
.font(.system(size: 30, design: .rounded))
.onTapGesture {
if !ifTapped {
timerString = 0
startTime = Date()
}
ifTapped.toggle()
}
})
.tint(ifTapped ? Color.green : Color.red)
.shadow(radius: 30)
.opacity(0.9)
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.offset(y: 150)
}
VStack {
// timer
Text(String(timerString))
.font(Font.system(.largeTitle, design: .monospaced))
.foregroundColor(Color.white)
.onReceive(timer) { _ in
if self.ifTapped {
timerString = Int(format: "\(timerString)", (Date().timeIntervalSince( self.startTime)))
}
}
Text("\(timerString)")
.offset(y: 150)
}
}
}
}
}
Related
I'm trying to recreate a popular game: Heads up, basically the user has to try to guess the name putting the phone on his head, with friends' suggestions...if he raises the head he skips the word, if he lowers the head it means he guessed the name and he earns a point. He has limited time. I need that every time the user raises/lowers his head, the array's name changes, and each name must appear only once. Any suggestions?
This is my code:
import SwiftUI
import CoreMotion
struct ContentView: View {
let motionManager = CMMotionManager()
let queue = OperationQueue()
#State private var roll = Double.zero
#State private var people = ["John", "Marcus", "Steve", "Eric", "Philip"].shuffled()
#State private var randomPerson = Int.random(in: 0...4)
let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
#State private var timeRemaining = 10
#State private var score = 0
var body: some View {
NavigationView {
ZStack {
//Show a red background and "SKIP" if the user raises head
if roll < 1 {
Color.red
.ignoresSafeArea()
Text("SKIP")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
} else if roll > 2.1 {
//Show a green background and "CORRECT" if user lowers head
Color.green
.ignoresSafeArea()
Text("CORRECT")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.onAppear {
score += 1
}
} else {
//Otherwise show a cyan back with array's name
Color.cyan
.ignoresSafeArea()
Text(people[randomPerson])
.font(.largeTitle)
.bold()
.foregroundColor(.white)
}
Text("\(timeRemaining)")
.font(.system(size: 39))
.padding(.bottom, 200)
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
Text("Score: \(score)")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.padding(.top, 200)
}
.onAppear {
//Detect device motion
self.motionManager.startDeviceMotionUpdates(to: self.queue) { (data: CMDeviceMotion?, error: Error?) in
guard let data = data else {
print("Error: \(error!)")
return
}
let attitude: CMAttitude = data.attitude
DispatchQueue.main.async {
self.roll = attitude.roll
}
}
}
}
.navigationViewStyle(.stack)
}
}
You can do like this:
a state variable for current selected person
#State private var currerntPerson : String = ""
a function to get random person
getRandomPerson()
change TextView show selected person name:
Text(currerntPerson)
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.onAppear {
getRandomPerson()
}
====
All code here:
let motionManager = CMMotionManager()
let queue = OperationQueue()
#State private var roll = Double.zero
#State private var people = ["John", "Marcus", "Steve", "Eric", "Philip"].shuffled()
#State private var randomPerson = Int.random(in: 0...4)
let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
#State private var timeRemaining = 10
#State private var score = 0
#State private var currerntPerson : String = ""
var body: some View {
NavigationView {
ZStack {
//Show a red background and "SKIP" if the user raises head
if roll < 1 {
Color.red
.ignoresSafeArea()
Text("SKIP")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
} else if roll > 2.1 {
//Show a green background and "CORRECT" if user lowers head
Color.green
.ignoresSafeArea()
Text("CORRECT")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.onAppear {
score += 1
}
} else {
//Otherwise show a cyan back with array's name
Color.cyan
.ignoresSafeArea()
Text(currerntPerson)
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.onAppear {
getRandomPerson()
}
}
Text("\(timeRemaining)")
.font(.system(size: 39))
.padding(.bottom, 200)
.onReceive(timer) { _ in
if timeRemaining > 0 {
timeRemaining -= 1
}
}
Text("Score: \(score)")
.font(.largeTitle)
.bold()
.foregroundColor(.white)
.padding(.top, 200)
}
.onAppear {
//Detect device motion
self.motionManager.startDeviceMotionUpdates(to: self.queue) { (data: CMDeviceMotion?, error: Error?) in
guard let data = data else {
print("Error: \(error!)")
return
}
let attitude: CMAttitude = data.attitude
DispatchQueue.main.async {
self.roll = attitude.roll
}
}
}
}
.navigationViewStyle(.stack)
}
func getRandomPerson() {
if people.count > 0 {
let index = Int.random(in: 0..<people.count)
currerntPerson = people[index]
people.remove(at: index)
}
}
I can not understand why the timer does not work, and the text does not scroll automatically.
I tried to do so:
ForEach(0..<numberText)
But I got such an error:
Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'some View' conform to 'TableRowContent'
Full code:
let numberText = ["text1","text2","text3","text4"]
struct TextNew: View {
private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
#State private var index = 0
let textdata = TextData.getAllText()
var body: some View {
GeometryReader { proxy in
TabView(selection: $index) {
ForEach(numberText, id: \.self) { num in
Text("\(num)")
.font(.system(size: 10))
.foregroundColor(.white)
.tag(num)
.padding(.bottom, 50)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.frame(height: 80)
.onReceive(timer, perform: { _ in
withAnimation {
index = index < numberText.count ? index + 1 : 0
}
})
}
}
}
Thanks for any help, I'm new
Try this:
struct TextNew: View {
private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
#State private var index = 1
#State private var selectedNum: String = ""
var body: some View {
GeometryReader { proxy in
TabView(selection: $selectedNum) {
ForEach(numberText, id: \.self) { num in
Text("\(num)")
.font(.system(size: 10))
.foregroundColor(.white)
.padding(.bottom, 50)
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.onReceive(timer, perform: { _ in
withAnimation {
index = index < numberText.count ? index + 1 : 1
selectedNum = numberText[index - 1]
}
})
}
}
}
Explanation:
The reason for this not working is the type mismatch between your .tag and the $index in your TabView declaration. These have to match. By the way you do not need the .tag here as you are setting it to .self in your ForEach loop.
It's very hard to explain without a recording from a second device that I don't have, but when I try to slide my slider, it will stop when my finger is definitely still moving.
I have my code posted below. I'd be happy to answer any questions and explain whatever. I'm sure it's something really simple that I should know. Any help would be very much appreciated, thanks!
import SwiftUI
class SettingsViewModel: ObservableObject {
#Published var selectedTips = [
10.0,
15.0,
18.0,
20.0,
25.0
]
func addTip() {
selectedTips.append(0.0)
selectedTips.sort()
}
func removeTip(index: Int) {
selectedTips.remove(at: index)
selectedTips = selectedTips.compactMap{ $0 }
}
}
struct SettingsTipsView: View {
#StateObject var model = SettingsViewModel()
var body: some View {
List {
HStack {
Text("Edit Suggested Tips")
.font(.title2)
.fontWeight(.semibold)
Spacer()
if(model.selectedTips.count < 5) {
Button(action: { model.addTip() }, label: {
Image(systemName: "plus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
})
.buttonStyle(BorderlessButtonStyle())
}
}
ForEach(model.selectedTips, id: \.self) { tip in
let i = model.selectedTips.firstIndex(of: tip)!
//If I don't have this debug line here then the LAST slider in the list tries to force the value to 1 constantly, even if I remove the last one, the new last slider does the same. It's from a separate file but it's pretty much the same as the array above. An explanation would be great.
Text("\(CalculatorViewModel.suggestedTips[i])")
HStack {
Text("\(tip, specifier: "%.0f")%")
Slider(value: $model.selectedTips[i], in: 1...99, label: { Text("Label") })
if(model.selectedTips.count > 1) {
Button(action: { model.removeTip(index: i) }, label: {
Image(systemName: "minus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
})
.buttonStyle(BorderlessButtonStyle())
}
}
}
}
}
}
Using id: \.self within a List or ForEach is a dangerous idea in SwiftUI. The system uses it to identify what it expects to be unique elements. But, as soon as you move the slider, you have a change of ending up with a tip value that is equal to another value in the list. Then, SwiftUI gets confused about which element is which.
To fix this, you can use items with truly unique IDs. You should also try to avoid using indexes to refer to certain items in the list. I've used list bindings to avoid that issue.
struct Tip : Identifiable {
var id = UUID()
var tip : Double
}
class SettingsViewModel: ObservableObject {
#Published var selectedTips : [Tip] = [
.init(tip:10.0),
.init(tip:15.0),
.init(tip:18.0),
.init(tip:20.0),
.init(tip:25.0)
]
func addTip() {
selectedTips.append(.init(tip:0.0))
selectedTips = selectedTips.sorted(by: { a, b in
a.tip < b.tip
})
}
func removeTip(id: UUID) {
selectedTips = selectedTips.filter { $0.id != id }
}
}
struct SettingsTipsView: View {
#StateObject var model = SettingsViewModel()
var body: some View {
List {
HStack {
Text("Edit Suggested Tips")
.font(.title2)
.fontWeight(.semibold)
Spacer()
if(model.selectedTips.count < 5) {
Button(action: { model.addTip() }, label: {
Image(systemName: "plus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
})
.buttonStyle(BorderlessButtonStyle())
}
}
ForEach($model.selectedTips, id: \.id) { $tip in
HStack {
Text("\(tip.tip, specifier: "%.0f")%")
.frame(width: 50) //Otherwise, the width changes while moving the slider. You could get fancier and try to use alignment guides for a more robust solution
Slider(value: $tip.tip, in: 1...99, label: { Text("Label") })
if(model.selectedTips.count > 1) {
Button(action: { model.removeTip(id: tip.id) }, label: {
Image(systemName: "minus.circle.fill")
.renderingMode(.original)
.font(.title3)
.padding(.horizontal, 10)
})
.buttonStyle(BorderlessButtonStyle())
}
}
}
}
}
}
I have a textfield which is supposed to log the units of a food product someone has eaten, which is then used to calculate the total number of calories, protein, etc. that the user consumed. But when the value is entered on the textfield, the units variable isn't updated. How can I fix this?
This is my code:
#State var selectFood = 0
#State var units = 0
#State var quantity = 1.0
#State var caloriesInput = 0.0
#State var proteinInput = 0.0
#State var carbsInput = 0.0
#State var fatsInput = 0.0
var body: some View {
VStack {
Group {
Picker(selection: $selectFood, label: Text("What did you eat?")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.white))
{
ForEach(database.productList.indices, id: \.self) { i in
Text(database.productList[i].name)
}
}
.pickerStyle(MenuPickerStyle())
Spacer(minLength: 25)
Text("How much did you have?")
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.white)
.frame(alignment: .leading)
//Textfield not working.
TextField("Units", value: $units, formatter: NumberFormatter())
.padding(10)
.background(Color("Settings"))
.cornerRadius(10)
.foregroundColor(Color("Background"))
.keyboardType(.numberPad)
Button (action: {
self.quantity = ((database.productList[selectFood].weight) * Double(self.units)) / 100
caloriesInput = database.productList[selectFood].calories * quantity
proteinInput = database.productList[selectFood].protein * quantity
carbsInput = database.productList[selectFood].carbs * quantity
fatsInput = database.productList[selectFood].fats * quantity
UIApplication.shared.hideKeyboard()
}) {
ZStack {
Rectangle()
.frame(width: 90, height: 40, alignment: .center)
.background(Color(.black))
.opacity(0.20)
.cornerRadius(15)
;
Text("Enter")
.foregroundColor(.white)
.fontWeight(.bold)
}
}
}
}
}
This is an issue with NumberFormatter that has been going on for a while. If you remove the formatter it updates correctly.
This is a workaround. Sadly it requires 2 variables.
import SwiftUI
struct TFConnection: View {
#State var unitsD: Double = 0
#State var unitsS = ""
var body: some View {
VStack{
//value does not get extracted properly
TextField("units", text: Binding<String>(
get: { unitsS },
set: {
if let value = NumberFormatter().number(from: $0) {
print("valid value")
self.unitsD = value.doubleValue
}else{
unitsS = $0
//Remove the invalid character it is not flawless the user can move to in-between the string
unitsS.removeLast()
print(unitsS)
}
}))
Button("enter"){
print("enter action")
print(unitsD.description)
}
}
}
}
struct TFConnection_Previews: PreviewProvider {
static var previews: some View {
TFConnection()
}
}
I have a line of code that sets the background of Text to an Image that is fetched by finding the first three letters of the string. For some reason this won't run and keeps giving me the error above. Any ideas on how I can fix this?
There are a lot of images that need to be set as the backgrounds for multiple different pieces of text. I believe I have the right idea by using the prefix of the string, but it seems like Xcode is having difficulty/won't run this.
Pretty sure this specific line is giving me issues, but would love some feedback.
.background(Image(colorOption.prefix(3)).resizable())
import SwiftUI
struct ColorView: View {
// #ObservedObject var survey = Survey()
#ObservedObject var api = ColorAPIRequest(survey: DataStore.instance.currentSurvey!)
#State var showingConfirmation = true
#State var showingColorView = false
#State var tempSelection = ""
#EnvironmentObject var survey: Survey
//#EnvironmentObject var api: APIRequest
var colorOptionsGrid: [[String]] {
var result: [[String]] = [[]]
let optionsPerRow = 4
api.colorOptions.dropFirst().forEach { colorOption in
if result.last!.count == optionsPerRow { result.append([]) }
result[result.count - 1].append(colorOption)
}
return result
}
var body: some View {
VStack {
Text("Select Tape Color")
.font(.system(size:70))
.bold()
.padding(.top, 20)
NavigationLink("", destination: LengthView(), isActive: $showingColorView)
HStack {
List {
ForEach(colorOptionsGrid, id: \.self) { colorOptionRow in
HStack {
ForEach(colorOptionRow, id: \.self) { colorOption in
Button(action: {
// self.survey.length = lengthOption
self.tempSelection = colorOption
self.showingConfirmation = false
}
) {
ZStack {
Color.clear
Text(colorOption.prefix(3))
.font(.title)
.foregroundColor(self.tempSelection == colorOption ? Color.white : Color.black)
.frame(width: 200, height: 100)
.background(Image(colorOption.prefix(3)).resizable())
//Image(colorOption.prefix(3)).resizable()
}
}.listRowBackground(self.tempSelection == colorOption ? Color.pink : Color.white)
.multilineTextAlignment(.center)
}
}
}
}.buttonStyle(PlainButtonStyle())
}
Button(action: {
self.survey.color = self.tempSelection
self.showingColorView = true
self.showingConfirmation = true
}) {
Text("Press to confirm \(tempSelection)")
.bold()
.padding(50)
.background(Color.pink)
.foregroundColor(.white)
.font(.system(size:40))
.cornerRadius(90)
}.isHidden(showingConfirmation)
.padding(.bottom, 50)
}
}
}
The compiler actually gives a fairly decent suggestion when it tells you to break the expression up. The simplest you can do is extract the background image into a separate function like this:
func backgroundImage(for colorOption: String) -> some View {
Image(String(colorOption.prefix(3))).resizable()
}
and then replace the call to
.background(Image(colorOption.prefix(3)).resizable())
with
.background(self.backgroundImage(for: colorOption))
Also note that I wrapped colorOption.prefix(3) in a String constructor, simply because .prefix(_:) returns a Substring, but the Image(_:) constructor requires a String.