How to make "the smooth table" in swiftUI - swiftui

I have android screen and i want copy it to swiftui ios screen.
Android:
iOS:
But i try to make it in swiftui. How you see text dont have baseline and gravity parameters, how i make it in android. Help me please make equivalent simple screen.
My swiftui code:
struct WeatherView: View {
var weather: WeatherMainModel
var body: some View {
VStack {
VStack {
Text("Description: \(weather.weather[0].component3())")
Text("Visibility: \(weather.visibility) meters")
Text("Main: \(weather.weather[0].main)")
}
VStack {
Text("Temperature Data")
HStack {
VStack {
HStack {
Text("Temperature: \(temperatureString(value: weather.mainData.temperature))")
.font(.system(size: 15))
Spacer()
}
HStack {
Text("Temperature fels like: \(temperatureString(value: weather.mainData.temperatureFeelsLike))")
.font(.system(size: 15))
Spacer()
}
}
VStack {
HStack {
Text("Temperature max: \(temperatureString(value: weather.mainData.temperatureMax))")
.font(.system(size: 15))
Spacer()
}
HStack {
Text("Temperature min: \(temperatureString(value: weather.mainData.temperatureMin))")
.font(.system(size: 15))
Spacer()
}
}
}.padding(.horizontal, 5)
}.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1)
)
Spacer()
}.padding(.horizontal)
}
private func temperatureString(value: Float) -> String {
return String(format: "%.2f", value)
}
}

Your second screen texts differ from first one, but I assume you wanted something like below (of corse padding/spacing/fonts can be tuned)
Prepared with Xcode 12.1 / iOS 14.1
struct DemoView: View {
var body: some View {
VStack {
Text("Description")
Text("Visibility")
Text("main")
VStack {
Text("Temperature Data")
HStack(alignment: .top) {
Text("Temperature: 38 dsa das das das da sd")
.frame(maxWidth: .infinity, alignment: .leading)
Text("Temperature Max: 38")
.frame(maxWidth: .infinity, alignment: .leading)
}
HStack(alignment: .top) {
Text("Temperature fels like: 38")
.frame(maxWidth: .infinity, alignment: .leading)
Text("Temperature Min: 38")
.frame(maxWidth: .infinity, alignment: .leading)
}
}.padding(.top)
Spacer()
}.padding(.horizontal, 8)
}
}

Related

SwiftUI transition is not working when in HSack

I have a VStack which wraps a number elements wrapped inside another HStack, I want to add a simple bottom to top transition on load, but it does not have any effect on the output:
var body: some View {
let bottomPadding = ScreenRectHelper.shared.bottomPadding + 150
GeometryReader { geometry in
ZStack {
VisualEffectViewSUI(effect: UIBlurEffect(style: .regular))
.edgesIgnoringSafeArea(.all)
VStack(alignment: .center) {
Spacer()
HStack {
VStack(alignment: .leading, spacing: 15) {
ForEach(items, id: \.id) { item in
HStack(alignment: .center) {
Image(item.imageName)
.resizable()
.scaledToFit()
.frame(width: 24)
Spacer()
.frame(width: 15)
Text("\(item.text)")
.foregroundColor(.white)
.transition(.move(edge: .bottom))
}
.contentShape(Rectangle())
.onTapGesture {
/// Do something
}
}
}
}
.frame(width: geometry.size.width, height: nil, alignment: .center)
}.zIndex(1)
.frame(width: geometry.size.width, height: nil, alignment: .center)
.padding(.bottom, bottomPadding)
}.background(
LinearGradient(gradient: Gradient(colors: [gradientColor.opacity(0),gradientColor]), startPoint: .top, endPoint: .bottom)
)
}.edgesIgnoringSafeArea(.all)
}
This SwiftUI view is added to a UIKit view controller and that view controller is presented modally.
.transition only works if you insert something conditionally into the view.
I'm not totally sure what you want to achieve, but if you want the whole view to slide from the bottom, this would work.
struct ContentView: View {
#State private var showText = false
let bottomPadding: CGFloat = 150
var body: some View {
ZStack {
if showText { // conditional view to make .transition work
// VisualEffectViewSUI(effect: UIBlurEffect(style: .regular))
// .edgesIgnoringSafeArea(.all)
VStack(alignment: .center) {
Spacer()
HStack {
VStack(alignment: .leading, spacing: 15) {
ForEach(0 ..< 3) { item in
HStack(alignment: .center) {
Image(systemName: "\(item).circle")
.resizable()
.scaledToFit()
.frame(width: 24)
Spacer()
.frame(width: 15)
Text("Item \(item)")
.foregroundColor(.white)
}
}
}
}
}
.frame(maxWidth: .infinity)
.padding(.bottom, bottomPadding)
.background(
LinearGradient(gradient: Gradient(colors: [.blue.opacity(0), .blue]),
startPoint: .top, endPoint: .bottom)
)
.edgesIgnoringSafeArea(.all)
.transition(.move(edge: .bottom)) // here for whole modal view
}
Button("Show modal") {
withAnimation {
showText.toggle()
}
}
}
}
}

Limit the number of dots in Page Tab View Swiftui

I am trying to use the PageTabview option to allow a user to move through a series of pages whose data is coming from a JSON file. I want to be able to limit the number of visible dots to 5 or 6 even if there are many values in the field. What I don't want is to have 25 dots if there are twenty-five values in the field. How would I do that? I want to be able to show indicator like an arrow that tells the user there is more to come...Thank you.
My code is below:
struct TopicsExperienceCards: View {
#Binding var closeExperience: Bool
let etype: EItype
var body: some View {
//start of content of zstack layout
ZStack {
VStack(spacing: 20) {
HStack{
Rectangle()
.fill(Color.white)
.frame(width: 300, height: 1, alignment: .center)
Spacer()
Button(action: {
closeExperience = false })
{
Image(systemName:"xmark")
.foregroundColor(Color(etype.accentcolor))
.padding()
}
} //HSTACK
TabView {
ForEach(etype.experience,id: \.self) { item in
// Display the content of a card //
VStack (alignment:.center, spacing:0){
Text(item)
.padding()
.frame(width:300, height:300, alignment:.center)
Divider()
Spacer()
Text("Room for an image")
Spacer()
Spacer()
}//VSTACK
//End of display of content of the card //
} //: FOREACH
} //: TABVIEW
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.onAppear {
setupAppearance() }
} //VSTACK
} //: ZStack
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.white)
.overlay(
RoundedRectangle(cornerRadius: 16)
.strokeBorder()
.foregroundColor(Color(etype.accentcolor)))
.cornerRadius(16.0)
.padding()
}
}
struct TopicsExperienceCards_Previews: PreviewProvider {
static let etypes: [EItype] = Bundle.main.decode("eibasestructure.json")
static var previews: some View {
TopicsExperienceCards(closeExperience:.constant(true),etype:etypes[1])
}
}
enter image description here
System dots view is limited to around 10 dots, maybe depending on the device. You can't change this value.
Instead of that you can hide system one, and create your own view with dots. As an example you can follow this article, so at the end you'll have something like this:
#State var currentIndex = 0
var body: some View {
//start of content of zstack layout
ZStack {
printUI(currentIndex)
VStack(spacing: 20) {
HStack{
Rectangle()
.fill(Color.white)
.frame(width: 300, height: 1, alignment: .center)
Spacer()
Button(action: {
closeExperience = false })
{
Image(systemName:"xmark")
.foregroundColor(Color.red)
.padding()
}
} //HSTACK
TabView(selection: $currentIndex.animation()) {
ForEach(etype.experience.indices,id: \.self) { i in
let item = etype.experience[i]
// Display the content of a card //
VStack (alignment:.center, spacing:0){
Text(item)
.padding()
.frame(width:300, height:300, alignment:.center)
Divider()
Spacer()
Text("Room for an image")
Spacer()
Spacer()
}//VSTACK
//End of display of content of the card //
} //: FOREACH
} //: TABVIEW
.tabViewStyle(PageTabViewStyle())
.onAppear {
setupAppearance()
}
Fancy3DotsIndexView(numberOfPages: etype.experience.count, currentIndex: currentIndex)
.padding()
.background(Color.green)
.clipShape(Capsule())
} //VSTACK
} //: ZStack
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.background(Color.white)
.overlay(
RoundedRectangle(cornerRadius: 16)
.strokeBorder()
.foregroundColor(Color.red)
)
.cornerRadius(16.0)
.padding()
}
Result:

Center Image in VStack leading alignment

I'm having troubles figuring out the proper solution to centre an Image inside a VStack with an alignment of .leading. I've attempted and got these results but is there a more efficient way instead of adding two Spacer()'s in an HStack?
struct ContentView: View {
var body: some View {
ZStack {
ScrollView {
VStack (alignment: .leading, spacing: 10) {
Text("Title ")
HStack {
Spacer()
Image(systemName:"star.fill")
.resizable()
.frame(width: 20, height: 20, alignment: .center)
Spacer()
}
Divider()
}
}
}
.padding(.all)
}
}
Here is a solution. Tested with Xcode 12.1 / iOS 14.1
ScrollView {
VStack (alignment: .leading, spacing: 10) {
Text("Title ")
Image(systemName:"star.fill")
.resizable()
.frame(width: 20, height: 20)
.frame(maxWidth: .infinity, alignment: .center)
Divider()
}
}

ScrollView text alignment SwiftUI

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)
}

Button with image for SwiftUI 2

I want to add button with image inside of the view like twitter button with image for SwiftUI 2, but it is not padding to any directions.
struct WeatherView: View {
var body: some View {
VStack(alignment: .leading, spacing:0){
Button(action: {}) {
Image("cloud")
.padding()
.background(Color.blue)
.foregroundColor(Color.white)
.clipShape(Circle())
.shadow(radius: 8)
}
HStack(spacing: 5){
Text("Rainy")
.font(.largeTitle)
.fontWeight(.medium)
Spacer()
Button(action: {
}) {
Image("menu").resizable().frame(width: 24, height: 24)
}
}
.foregroundColor(Color("black"))
.padding()
Spacer()
}
}
}
Is there any solution for this problem.
I hope you are doing well.
This code should do the trick.
VStack {
Spacer()
Button(action: {}) {
Image(systemName: "cloud.fill")
.padding()
.background(Color.blue)
.foregroundColor(Color.white)
.clipShape(Circle())
.shadow(radius: 8)
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
.padding()
By putting the button in a VStack, and putting a spacer before it, you will push the button to the bottom of the screen. Then by putting a frame on it, and making the width to be .infinity, and giving it alignment trailing, you will further push the button to the trailing side of the screen, which in this case results in making the button at the bottom right corner.
Edit: Included full code
struct WeatherView: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 5) {
Text("Rainy")
.foregroundColor(.black)
.font(.largeTitle)
.fontWeight(.medium)
Spacer()
Button(action: {}) {
Image("menu").resizable().frame(width: 24, height: 24)
}
}
.foregroundColor(Color("black"))
.padding()
VStack {
Spacer()
Button(action: {}) {
Image("cloud")
.padding()
.background(Color.blue)
.foregroundColor(Color.white)
.clipShape(Circle())
.shadow(radius: 8)
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
.padding()
}
}
}