So I am trying to show a different UI if a number is above 34
However somehow the code is triggering above 3. Not quite sure why it triggering at > 3 instead of > 34
if self.speed > "\(String(34))" {
VStack(alignment: .center){
Text("YOUR SPEED IS")
.multilineTextAlignment(.center)
.lineSpacing(30)
.padding(20)
.font(.system(size: 30, weight: .heavy, design: .default))
.foregroundColor(Color.gray)
Text(String(self.speed))
.multilineTextAlignment(.center)
.lineSpacing(30)
.padding(20)
.font(.system(size: 50, weight: .heavy, design: .default))
.foregroundColor(Color.red)
Text("Our system detected you driving or moving too fast")
.multilineTextAlignment(.center)
.font(.system(size: 12, weight: .light, design: .default))
.foregroundColor(Color.gray)
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
).background(Color.black)
}
I am wondering if I am doing the if statement correctly?
I am getting the speed from the users location (note I need the speed in KM)
static let Speed = 0
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
lastKnownLocation = locations.last
if(lastKnownLocation!.coordinate.latitude != LocationManager.LMlat && lastKnownLocation!.coordinate.longitude != LocationManager.LMlong)
{
//This fetches the users speed and coverts it to KM
let km = String(format: "%.0f",lastKnownLocation!.speed * 3.6)
LocationManager.Speed = Int(km) ?? 0
//We then check to see if the users speed is above 2.5km and if so we update.
if(km > String(2.5)){
print("Updating latest location")
print("speed: \(km)")
LocationManager.LMlat = lastKnownLocation!.coordinate.latitude
LocationManager.LMlong = lastKnownLocation!.coordinate.longitude
updateServerLocation(latitude: LocationManager.LMlat, longitude: LocationManager.LMlong, speed: km)
}
}
}
Note it won't let me save it as an Int
if Int(self.speed)! > 34 {
or
if Int(self.speed) ?? 0 > 34 {
Instead of turning 34 into a String, turn self.speed into an Int or Double.
Honestly though, self.speed should probably be an Int to begin with.
Related
I want to show in the user interface of the future data in accordance with the design. But in the design, the 1st person should appear in the middle, and the 2nd place person should appear on the left. The third person should be on the far right. how can i show this in list loop. I am sharing my codes with you as an example. So in summary, the first 3 successful users will be forwarded to me in order of success. How can I get this display?
struct TopSortingUIView: View {
var topSortingList : [TopSorting] = TopSortingList.three
var body: some View {
HStack(spacing:24){
VStack{
Image("mangaa")
.resizable()
.scaledToFill()
.frame(width: 77, height: 77)
.clipShape(Circle())
.shadow(radius: 8)
.shadow(color: Color.init(red: 0.973, green: 0.976, blue: 0.98), radius: 4.15)
.padding(.top, 75)
Text("User1")
.font(.system(size: 12))
.foregroundColor(.secondary)
Text("2000 P")
.bold()
.font(.system(size: 12))
.foregroundColor(.black)
}
VStack{
Image("King")
Image("mangaa")
.resizable()
.scaledToFill()
.frame(width: 77, height: 77)
.clipShape(Circle())
.shadow(radius: 8)
.shadow(color: Color.init(red: 0.973, green: 0.976, blue: 0.98), radius: 4.15)
Text("User2")
.font(.system(size: 12))
.foregroundColor(.secondary)
Text("2824 P")
.bold()
.font(.system(size: 12))
.foregroundColor(.black)
}
VStack{
Image("mangaa")
.resizable()
.scaledToFill()
.frame(width: 77, height: 77)
.clipShape(Circle())
.shadow(radius: 8)
.shadow(color: Color.init(red: 0.973, green: 0.976, blue: 0.98), radius: 4.15)
.padding(.top, 75)
Text("User3")
.font(.system(size: 12))
.foregroundColor(.secondary)
Text("600P")
.bold()
.font(.system(size: 12))
.foregroundColor(.black)
}
}
}
}
struct TopSorting {
let rank : Int
let photoUrl: String
let userName: String
let name: String
let data : String
}
struct TopSortingList {
static let three = [
TopSorting(rank: 1, photoUrl: "mangaa", userName: "user1", name: "us1", data: "2824Ap"),
TopSorting(rank: 2, photoUrl: "mangaa", userName: "user2", name: "us2", data: "2000Ap"),
TopSorting(rank: 3, photoUrl: "mangaa", userName: "user3", name: "us3", data: "600Ap")
]
}
I'm trying to achieve the look you see in the photo. The data and image of the 1st user should be higher than the others
You will have to sort the items in the array with a custom function.
There are many ways of doing this. Here is something that can be reused.
//Protocol that requires that the Model has the rank variable (needed for array extension)
protocol RankingProtocol{
var rank : Int {get}
}
//Declare conformance to the protocol
struct TopSorting: RankingProtocol {
let rank : Int
let photoUrl: String
let userName: String
let name: String
let data : String
}
//Create an extension for any array that has objects that conform to the RankingProtocol
extension Array where Element : RankingProtocol{
func zigZagRankSort() -> Self{
var new: Self = []
//Reposition the objects based on the original index (add to the front or back)
for (idx, item) in self.sorted(by: { lhs, rhs in
lhs.rank < rhs.rank
}).enumerated(){
if idx % 2 != 0{
new.insert(item, at: 0)
}else{
new.append(item)
}
}
return new
}
}
Then with a ForEach and some minor adjustments you can display the objects.
struct TopSortingUIView: View {
var topSortingList : [TopSorting] = TopSortingList.three
var body: some View {
HStack(spacing:24){
ForEach(topSortingList.zigZagRankSort(), id:\.rank) { list in
VStack{
if list.rank == 1{
Image("King")
}
Image(list.photoUrl)
.resizable()
.scaledToFill()
.frame(width: 77, height: 77)
.clipShape(Circle())
.shadow(radius: 8)
.shadow(color: Color.init(red: 0.973, green: 0.976, blue: 0.98), radius: 4.15)
.padding(.top, 75)
Text(list.userName)
.font(.system(size: 12))
.foregroundColor(.secondary)
Text(list.data)
.bold()
.font(.system(size: 12))
.foregroundColor(.black)
}.padding(.bottom, list.rank == 1 ? 75 : nil)
}
}
}
}
I would suggest something like :
// Podium position view
struct TopSortingPositionView: View {
var topSorting: TopSorting
var body: some View {
VStack{
// only for first
if topSorting.rank == 1 {
Image("King")
}
Image(topSorting.photoUrl)
.resizable()
.scaledToFill()
.frame(width: 77, height: 77)
.clipShape(Circle())
.shadow(radius: 8)
.shadow(color: Color.init(red: 0.973, green: 0.976, blue: 0.98), radius: 4.15)
.modifier(ImageOffset(rank: topSorting.rank))
Text(topSorting.userName)
.font(.system(size: 12))
.foregroundColor(.secondary)
Text(topSorting.data)
.bold()
.font(.system(size: 12))
.foregroundColor(.black)
}
}
// the view modifier enable to apply the offset depending on the rank
// you can put here other modifier for the image
struct ImageOffset: ViewModifier {
var rank: Int
func body(content: Content) -> some View {
if rank == 1 {
content
} else {
// only for second and third
content
.padding(.top, 75)
}
}
}
}
struct TopSortingUIView: View {
var topSortingList : [TopSorting] = TopSortingList.three
var body: some View {
HStack(spacing:24){
// no need for a loop for 3 element
TopSortingPositionView(topSorting: topSortingList[1])
TopSortingPositionView(topSorting: topSortingList[0])
TopSortingPositionView(topSorting: topSortingList[2])
}
}
}
}
I am trying to optimize a UI with VStacks and spacers in between. The UI is ideally designed for the iPhone 13 Pro screen size (left). For smaller devices, the intention is that the spacers will shrink in a certain way that the UI still looks appealing.
I tried to achieve this by using frames for the Spacers with minHeight, idealHeight and maxHeight. The intended layout appears on the iPhone 13 Pro, but on a smaller device like the iPhone SE the spacers don't scale down to the minWidth. How can I fix that?
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 0) {
// Top Space
Spacer()
.frame(minHeight: 16, idealHeight: 32, maxHeight: .infinity)
.fixedSize()
// VStack 1
VStack(spacing: 0) {
// Image placeholder
Rectangle()
.fill(Color.red)
.frame(height: 175)
Spacer()
.frame(minHeight: 15, idealHeight: 62, maxHeight: .infinity)
.fixedSize()
Text("Abc")
.frame(height: 100)
}
.background(Color.gray)
// Middle Space
Spacer()
.frame(minHeight: 22, idealHeight: 100, maxHeight: .infinity)
.fixedSize()
// VStack 2
VStack(spacing: 0) {
// Image placeholder
Rectangle()
.fill(Color.red)
.frame(height: 100)
Spacer()
.frame(minHeight: 15, idealHeight: 35, maxHeight: .infinity)
.fixedSize()
// Image placeholder
Rectangle()
.fill(Color.red)
.frame(height: 195)
}
.background(Color.gray)
// Bottom Space
Spacer()
.frame(minHeight: 16, idealHeight: 45, maxHeight: .infinity)
.fixedSize()
}
.edgesIgnoringSafeArea(.all)
}
}
I'd suggest to wrap everything in another VStack and use it's spacing.
You can read out the UIScreen bounds in the init of the view and compare it to the bounds of all devices.
struct SpacerTest: View {
var spacing: CGFloat
init() {
let screenHeight = UIScreen.main.bounds.size.height
if screenHeight < 500 {
self.spacing = 20
} else if screenHeight < 600 {
self.spacing = 50
} else {
self.spacing = 100
}
}
var body: some View {
VStack(spacing: spacing) {
Text("Spacing Test")
Text("Spacing Test")
}
}
}
I wanted to build a Playground which stores my notes for my next examination using either Xcode playgrounds or just Swift Playgrounds. However, I attempted to build a list with an arrow at the side for navigation in Playgrounds, but with the lack of information after searching lots of tutorials, there's no way I could create a navigation list on
Swift Playgrounds. So I switched to Xcode playgrounds. But I could not seem to load the LiveView.
Note: no errors shown. Xcode playgrounds displays "Successful" but nothing is shown.
import SwiftUI
import PlaygroundSupport
//--------------------------------------------------------------//
// Weighted Asesstment III Notes
// Subject: Science
// Written in: English & SwiftUI
struct IntroView: View {
// arrays cus I wanna put this to a list
let expTech = ["Chromatography","Evaporation", "Distillation", "Dissolving","Magnetic Attraction", "Filtration"]
let expUse = ["Chromatography",
"Method: Paper",
"Used for: ",
"Evaporation",
"Method: Heating",
"Used for: Separating salt & water",
"Distillation",
"Method: Heating of liquid mixture with different boiling points",
"eg. Used for: Obtaining pure water from alcohol",
"Dissolving",
"Method",
"Used for",
"Magnetic Attraction",
//I need complete silence lol
//Iron nickel cobalt steel
"Method: Magnets (I,N,C,S)",
"Used for: Separating magnetic objects from non magnets",
"Filtration",
"Method: Filtering/Use of filter paper",
"Used for: Separating mixture of insoluble solid from liquid"]
var body: some View {
// ZStack
ZStack {
// background color
Color.white
// VStack
VStack {
LinearGradient(gradient: Gradient(colors: [.white, .gray, .black]), startPoint: .leading, endPoint: .trailing)
.mask(Text("WA 3 Sci Notes: M5C7")
.font(.system(size: 30, weight: .bold, design: .monospaced)))
.foregroundColor(Color.black)
.offset(x: 10, y: -325)
.padding()
Text("Types of experimental techniques")
.foregroundColor(Color.black)
.offset(x: -100, y: -710)
.font(.system(size: 25, weight: .semibold))
}
ZStack {
Rectangle()
.frame(width: 340, height: 240)
.cornerRadius(20)
.scaledToFill()
.shadow(color: Color.black, radius: 10)
.offset(x: -100, y: -120)
// list
List(expTech, id: \.self) { expTech in Text(expTech) }
.frame(width: 350, height: 250, alignment: .center)
.cornerRadius(25)
.offset(x: -100, y: -120)
}
Text("Uses of Experimental Techniques")
.foregroundColor(Color.blue)
.offset(x: 80, y: 40)
.font(.system(size: 25, weight: .semibold))
ZStack {
VStack {
Rectangle()
.frame(width: 600, height: 250)
.cornerRadius(20)
.scaledToFill()
.shadow(color: Color.black, radius: 5)
.offset(x: 5, y: 530)
}
}
}
}
}
PlaygroundPage.current.setLiveView(IntroView())
The issue could be that your View doesn't render properly. I put your code into an Xcode project (not a storyboard) and it looks like this:
You can even see it rendering weirdly in the playground:
I have a vertical ScrollView with a ForEach loop that has HStack's inside with Text, Image, and Two Text's. I'd like to keep each row's items in alignment with each other. I've attempted to wrap in a VStack with alignment .leading but did nothing. The issue I'm having is the text doesn't line up. Still very new to SwiftUI so any help would be appreciated.
ScrollView(.vertical) {
ForEach(self.daily.forecast, id: \.date) { forecast in
HStack (spacing : 10){
Text(forecast.date ?? "")
.fontWeight(.bold)
Spacer()
RequestImage(Url("IMAGE_URL"))
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.clipped()
Spacer()
Text("\(forecast.maxTemp)")
.fontWeight(.bold)
Text("\(forecast.minTemp)")
.fontWeight(.bold)
}
}
}
.padding(.all, 15)
.onAppear() {
authorize {_ in
loadForecast()
}
}
UPDATED:
I was able to get a bit closer but things still aren't aligned to where I'd like them to be.
ScrollView(.vertical) {
ForEach(self.daily.forecast, id: \.date) { forecast in
HStack (spacing : 10){
Text(date)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 45)
Spacer()
RequestImage(Url("IMAGE_URL"))
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.frame(minWidth: 50)
.clipped()
Spacer()
Text(maxTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 45)
Text(minTemp)
.font(.title3)
.fontWeight(.bold)
.foregroundColor(Color.secondary)
.frame(minWidth: 45)
}
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
}
}
.padding(.all, 15)
.onAppear() {
authorize {_ in
loadForecast()
}
}
Here is a demo of possible solution. Prepared with Xcode 12.4 / iOS 14.4
struct DemoWeatherLayout: View {
private var dayOfTheWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sut"]
var body: some View {
ScrollView {
VStack {
ForEach(dayOfTheWeek, id: \.self) {
WeatherRowView(day: $0,
icon: ["sun.max", "cloud.sun", "cloud", "cloud.snow"].randomElement()!,
low: Array(-5..<0).randomElement()!,
high: Array(1..<15).randomElement()!)
}
}.padding()
}
}
}
struct WeatherRowView: View {
var day: String
var icon: String
var low: Int
var high: Int
var body: some View {
HStack {
Text(day)
.frame(maxWidth: .infinity, alignment: .leading)
Image(systemName: icon)
.frame(maxWidth: .infinity, alignment: .leading)
HStack {
Text("+XXº").foregroundColor(.clear)
.overlay(Text(String(format: "%+d", low)), alignment: .leading)
Text("+XXº").foregroundColor(.clear)
.overlay(Text(String(format: "%+d", high)), alignment: .leading)
}
}
}
}
Three suggestions:
add alignment parameter to HStack:
HStack(alignment: .lastTextBaseline, spacing: 10) { ... //others options: .top, .center, .firstTextBaseline...
Add minLength parameter to Spacer:
Spacer(minLength: 0) but with spacing: 10 in HStack it is a bit redundant. You can remove spacing: 10 for Spacer(minLength: 10)
Add a Spacer(minLength: 0) at the end after Text("\(forecast.minTemp)").fontWeight(.bold)
I'm going to accept #Asperi answer as correct. The UI has indeed changed since to better fit said labels etc. Appreciate everyone's else. The code is very much ugly but works. Not sure if it's 100% correct.
HStack (spacing: 10){
Text(date)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
Spacer()
RequestImage(Url("IMAGE_URL_HERE"))
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.frame(minWidth: 55)
.clipped()
Spacer()
Text(maxTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 50)
.background(Color.orange)
.cornerRadius(5)
Text(minTemp)
.font(.title3)
.fontWeight(.bold)
.frame(minWidth: 50)
.background(Color.blue)
.cornerRadius(5)
}
I'm using SwiftUI to create something like an alert popup, which I present from UIKit code using UIHostingController. The view looks like this:
VStack(spacing: 0) {
// Some text ...
HStack(spacing:0) {
Button(action: self.onCancel) { Text("Cancel") }
.padding().inExpandingRectangle().fixedSize(horizontal: false, vertical: true)
// This divider is the problem
Divider() // .fixedSize()
Button(action: self.onDelete) { Text("Delete") }
.padding().inExpandingRectangle().fixedSize(horizontal: false, vertical: true)
}
}.frame(minHeight: 0)
The inExpandingRectangle is something I found in another stackoverflow question. It centers the text in each side of the HStack.
extension View {
func inExpandingRectangle() -> some View {
ZStack {
Rectangle().fill(Color.clear)
self
}
}
}
It looks like this. Garbage.
If I put the .fixedSize() on the divider, it does this. Not horrible, but the divider is stupid looking and doesn't expand to the size of the buttons.
Here is a demo of possible simplified alternate, without that artificial extension. Tested with Xcode 11.4 / iOS 13.4.
Divider() // or Rectangle().fill(Color.gray).frame(height: 1)
HStack {
Button(action: {}) { Text("Cancel").fixedSize() }
.padding().frame(maxWidth: .infinity)
Divider() // or Rectangle().fill(Color.gray).frame(width: 1)
Button(action: {}) { Text("Delete").fixedSize() }
.padding().frame(maxWidth: .infinity)
}.fixedSize(horizontal: false, vertical: true)
Note: It worth also to consider custom divider, like
Rectangle().fill(Color.gray).frame(width: 1) // or any other color
than might give much appropriate visual feedback, like
Putting a fixedSize() modifier on the HStack instead of the Divider fixies the problem.
var body : some View {
VStack(spacing: 0) {
// Some text ...
Text("gsfdsfkajflkasdjflkas,jdflaskjf")
HStack(spacing:0) {
Button(action: {print("hi")}) { Text("Cancel") }
.padding().inExpandingRectangle().fixedSize(horizontal: true, vertical: true)
// This divider is the problem
Divider()
Button(action: {print("hello")}) { Text("Delete") }
.padding().inExpandingRectangle().fixedSize(horizontal: true, vertical: true)
}.fixedSize() <------- Insert this
}.frame(minHeight: 0)
}
Result:
You can try below code hope its help you (Xcode 11.2.1)
Note: Change Font, Frame and Color as per your requirement
var body: some View {
VStack(spacing: 0) {
Text("Delete")
.font(Font.system(size: 20, weight: .bold))
Text("Are you sure you want to delete ?")
.font(Font.system(size: 18, weight: .regular))
.padding([.top,.bottom], 15)
Rectangle().fill(Color.gray.opacity(0.5)).frame(height:0.5)
HStack(spacing:0) {
Button(action: {
//Your action
}) {
Text("Cancel")
.foregroundColor(Color.black)
.font(Font.system(size: 18, weight: .medium))
}
.frame(minWidth: 150, maxWidth: .infinity, minHeight: 40, maxHeight: 40, alignment: .center)
Rectangle().fill(Color.gray.opacity(0.5)).frame(width:0.5,height:20)
Button(action: {
//Your action
}) {
Text("Delete")
.font(Font.system(size: 18, weight: .medium))
.foregroundColor(Color.red)
}
.frame(minWidth: 150, maxWidth: .infinity, minHeight: 40, maxHeight: 40, alignment: .center)
}
}
}
Output :