SwiftUI combine views with Stack - ios

I am trying to create a design like this using text and image in a ZStack but my current implementation isn't showing the text at all, and I don't know why
ZStack {
Text("15")
.frame(alignment: .topTrailing)
.cornerRadius(10)
Image(systemName: agree ? "hand.thumbsup" : "hand.thumbsdown")
.frame(width: 40, height: 40)
.foregroundColor(agree ? .green : .red)
.background(.gray)
.cornerRadius(8)
}

In a ZStack, the views are stacked on the Z axis with the first defined views at the "bottom" of the stack. So, your text is currently covered up by the image, which is higher up on the stack. I've fixed this and added an offset to move the text to the top right, which also wasn't working in your code.
struct ContentView: View {
#State private var agree = true
var body: some View {
ZStack(alignment: .topTrailing) {
Image(systemName: agree ? "hand.thumbsup" : "hand.thumbsdown")
.frame(width: 60, height: 60)
.foregroundColor(agree ? .green : .red)
.background(.gray)
.cornerRadius(8)
Text("15")
.foregroundColor(Color.green)
.padding(6)
.background(
Circle()
.strokeBorder(Color.green, lineWidth: 2)
.background(Circle().foregroundColor(.white))
)
.offset(x: 10, y: -10)
}
}
}

Related

SwiftUI ZStack takes all screen height but should be fixed height

My code:
public var body: some View {
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
Text("Text")
.padding(.bottom, 42)
.foregroundColor(.red)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.background(Color.red)
}
makes ZStack takes almost all screen height. But I expect it will take height from .frame() method.
I have a workaround for you, it's a bit messed up but works
public var body: some View {
ZStack {
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.zIndex(0)
ZStack {
VStack {
VStack {
Text("Text")
.padding(.top, 42)
.foregroundColor(.red)
}
.frame(width: UIScreen.main.bounds.width, height: 182)
VStack {
Text("Your texts here")
}
.frame(width: UIScreen.main.bounds.width)
Spacer()
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
.zIndex(1)
}
.background(Color.red)
}
I simply made your ellipse on another layer and text on the other.
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.zIndex(0)
The .zIndex(0) makes sure that the view is in the background.
ZStack {
VStack { // This VStack contains all your text
VStack { // First VStack
Text("Text")
.padding(.top, 42)
.foregroundColor(.red)
}
.frame(width: UIScreen.main.bounds.width, height: 182)
VStack { //Second VStack
Text("Your texts here")
}
.frame(width: UIScreen.main.bounds.width)
Spacer()
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
.zIndex(1)
Here, the ZStack takes up the entire screen. We added a VStack which contains your texts.
The first VStack has your main label over the Ellipse, and its frame is hardcoded according to the height of the Ellipse (1/2 the height as the other half of the ellipse is outside the screen).
The second VStack starts from the end of our first VStack which was the functionality needed, finally added a spacer() so that the text is placed at the top rather than middle.
The zIndex(1) makes sure that is placed over the elements at zIndex(0)

View centered in superview with view on top of it in SwiftUI

I'm trying to achieve something that is quite easy in UIKit - one view that is always in in the center (image) and the second view (text) is on top of it with some spacing between two views. I tried many different approaches (mainly using alignmentGuide but nothing worked as I'd like).
code:
ZStack {
Rectangle()
.foregroundColor(Color.red)
VStack {
Text("Test")
.padding([.bottom], 20) // I want to define spacing between two views
Image(systemName: "circle")
.resizable()
.alignmentGuide(VerticalAlignment.center, computeValue: { value in
value[VerticalAlignment.center] + value.height
})
.frame(width: 20, height: 20)
}
}
.frame(width: 100, height: 100)
result:
As you can see image is not perfectly centered and it actually depends on the padding value of the Text. Is there any way to force vertical and horizontal alignment to be centered in the superview and layout second view without affecting centered view?
I think the “correct” way to do this is to define a custom alignment:
extension VerticalAlignment {
static var custom: VerticalAlignment {
struct CustomAlignment: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[VerticalAlignment.center]
}
}
return .init(CustomAlignment.self)
}
}
Then, tell your ZStack to use the custom alignment, and use alignmentGuide to explicitly set the custom alignment on your circle:
PlaygroundPage.current.setLiveView(
ZStack(alignment: .init(horizontal: .center, vertical: .custom)) {
Color.white
Rectangle()
.fill(Color.red)
.frame(width: 100, height: 100)
VStack {
Text("Test")
Circle()
.stroke(Color.white)
.frame(width: 20, height: 20)
.alignmentGuide(.custom, computeValue: { $0.height / 2 })
}
}
.frame(width: 300, height: 300)
)
Result:
You can center the Image by moving it to ZStack. Then apply .alignmentGuide to the Text:
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundColor(Color.red)
Text("Test")
.alignmentGuide(VerticalAlignment.center) { $0[.bottom] + $0.height }
Image(systemName: "circle")
.resizable()
.frame(width: 20, height: 20)
}
.frame(width: 100, height: 100)
}
}
Note that as you specify the width/height of the Image explicitly:
Image(systemName: "circle")
.resizable()
.frame(width: 20, height: 20)
you can specify the .alignmentGuide explicitly as well:
.alignmentGuide(VerticalAlignment.center) { $0[.bottom] + 50 }
Here is possible alternate, using automatic space consuming feature
Tested with Xcode 12 / iOS 14
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundColor(Color.red)
VStack(spacing: 0) {
Color.clear
.overlay(
Text("Test").padding([.bottom], 10),
alignment: .bottom)
Image(systemName: "circle")
.resizable()
.frame(width: 20, height: 20)
Color.clear
}
}
.frame(width: 100, height: 100)
}
}
Note: before I used Spacer() for such purpose but with Swift 2.0 it appears spacer becomes always just a spacer, ie. nothing can be attached to it - maybe bug.

Home page view background color in not on full screen in iPhone 11 Simulator

I am trying to build an app in SwiftUI and facing 1 challenge (Xcode Version 11.5) -
While running app on iPhone 11 simulator, background color is not coming on entire screen, bottom part of screen is still white however while running it on iPhone 8 simulator, it works fine. Not sure if it is simulator issue or code issue. I tried to add Spacer, change VStack, HStack but it did not work.
struct HomePageView: View {
#State var size = UIScreen.main.bounds.width / 1.6
var body: some View {
GeometryReader{geometry in
VStack {
HStack {
ZStack{
NavigationView{
ZStack {
ScrollView(.vertical, showsIndicators: false) {
VStack {
View1()
}.frame( maxWidth: .infinity)
}
.navigationBarItems(leading: Button(action: {
self.size = 10
}, label: {
Image("menu")
.resizable()
.frame(width: 30, height: 30)
}).foregroundColor(.appHeadingColor), trailing:
Button(action: {
print("profile is pressed")
}) {
HStack {
NavigationLink(destination: ProfileView()) {
LinearGradient.lairHorizontalDark
.frame(width: 30, height: 30)
.mask(
Image(systemName: "person.crop.circle")
.resizable()
.scaledToFit()
)
}
}
}
).navigationBarTitle("Home", displayMode: .inline)
}
}
HStack{
menu(size: self.$size)
.cornerRadius(20)
.padding(.leading, -self.size)
.offset(x: -self.size)
Spacer().background(Color.lairBackgroundGray)
}
//Spacer()
}.animation(.spring()).background(Color.lairBackgroundGray)
//Spacer()
}.padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
.padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom)
}.frame(height: geometry.size.height).background(Color.lairBackgroundGray)
}//.background(Color.lairBackgroundGray.edgesIgnoringSafeArea(.all))
}
}
Below is my another view which basically get painted on screen as part of home view. Please forgive me to put so much code here but wanted to make sure if it is not because of View1 -
struct View1: View {
#State var index = 0
var body: some View{
// ScrollView {
GeometryReader { geometry in
VStack{
HStack{
VStack {
ZStack{
Circle()
.trim(from: 0, to: 1)
.stroke(Color.lairDarkGray.opacity(0.09), style: StrokeStyle(lineWidth: 34, lineCap: .round))
.frame(width: 80, height: 80)
Circle()
.trim(from: 0, to: 0.5)
.stroke(LinearGradient(gradient: Gradient(colors: [.buttonGradientStartColor, .buttonGradientEndColor]), startPoint: UnitPoint(x: -0.2, y: 0.5), endPoint: .bottomTrailing), style: StrokeStyle(lineWidth: 34, lineCap: .round))
.frame(width: 80 , height: 80)
.rotationEffect(.init(degrees: -90))
Text("15")
.font(.system(size:30))
.fontWeight(.bold)
}.padding()
Text("Day(s)")
.foregroundColor(Color.black.opacity(0.8))
}.frame(height: 100)
VStack(alignment: .leading, spacing: 12){
HStack {
Image("1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 170, height: 170)
}
.background(Color.lairBackgroundGray)
//.padding(.bottom, 5)
}
.padding(.leading, 20)
Spacer(minLength: 0)
}
.padding(.horizontal, 20)
}//.frame(height: geometry.size.height)
.background(Color.lairBackgroundGray.edgesIgnoringSafeArea(.all))
}
//}
}
}[![enter image description here][1]][1]
You just need to add
.edgesIgnoringSafeArea(.all)
to the view that you want to go fullscreen
After recreating entire view and removing some unnecessary view, i was able to resolve this iissue.

How to make Image Clickable in swiftUI?

import SwiftUI
struct ContentView: View {
#State private var isActive : Bool = false
var body: some View {
VStack {
Image("home-img")
.resizable()
.aspectRatio(contentMode:.fill)
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.bottom)
.overlay(Image("round")
.resizable()
.frame(width: 350, height: 350 , alignment: .center)
.overlay(Image("girl-img")
.resizable()
.frame(width: 150, height: 150, alignment: .center)
)
.overlay(Image("video")
.resizable()
.frame(width: 100, height: 100)
.offset(y: -200)
.padding(.bottom, -70)
).onTapGesture(count: 1) {
NavigationView {
NavigationLink(destination: SelecteImageView(), isActive: self.$isActive) {
Text("")
}
}
}
}
}
}
What I want to do is when I tap on Image("Video") it should redirect me to a new screen using NavigationView. Normally, with button, it redirects to a new screen, but here the problem is that the image is in overlay. Thank you in advance.
You need to put your Image Views inside the NavigationLink label.
The navigationLink acts like Button and it gets the default button style with blue color. So change the default button style to plain using the bellow modifier:
import SwiftUI
struct ContentView: View {
#State private var isActive : Bool = false
var body: some View {
NavigationView {
NavigationLink(destination: SelecteImageView(), isActive: self.$isActive) {
VStack {
Image("home-img") //.renderingMode(.original)
.resizable()
.aspectRatio(contentMode:.fill)
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.bottom)
.clipped() //Here shows your Image only inside the frame
.overlay(Image("round") //.renderingMode(.original)
.resizable()
.frame(width: 350, height: 350 , alignment: .center))
.overlay(Image("girl-img") //.renderingMode(.original)
.resizable()
.frame(width: 150, height: 150, alignment: .center)
)
.overlay(Image("video") //.renderingMode(.original)
.resizable()
.frame(width: 100, height: 100)
.offset(y: -200)
.padding(.bottom, -70)
)
}
}.buttonStyle(PlainButtonStyle())
}
}
}
Or, you can give your Image views .renderingMode(.original) modifier if you are only using Images, and remove .buttonStyle(PlainButtonStyle()) from above code.
Please add tap gesture over here
struct Contentview: View {
#State var isNavigate :Bool = false
var body: some View {
NavigationView{
VStack{
NavigationLink(destination: LoginView()) {
Image("Birthday")
.resizable()
.aspectRatio(contentMode:.fill)
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.bottom)
.frame(width: 200, height: 200 , alignment: .center)
.overlay(Image("round")
.resizable()
.frame(width: 350, height: 350 , alignment: .center)
)
.overlay(Image("girl-img")
.resizable()
.frame(width: 150, height: 150, alignment: .center)
)
}
}
}
}
}

Swift UI VStack align up. Make textfield appear with keyboard when pressing in it

I am having issues placing my "twitter" image higher in my view while using SwiftUI. I want to get the twitter image higher up for all closer to my two blob images, as well as add the spacing between the twitter image and the "Sign into my account" phrase. In addition I am trying to get my UITextfield, I guess now its just TextField to appear with the keyboard when clicked in below my "Sign into your account phrase" but this is now showing up in my view.
Please see image of what is happening attached.
GeometryReader { (deviceSize: GeometryProxy) in
ZStack {
//Define a screen color
LinearGradient (gradient: Gradient(colors:[Color(ColorsSaved.gitLabDark),Color(ColorsSaved.gitLabLight)]),startPoint: .leading,endPoint: .trailing)
//Extend the screen to all edges
.edgesIgnoringSafeArea(.all)
Image("blobVectorLight")
.resizable()
.frame(width: deviceSize.size.height * (220/812) * 0.81, height: deviceSize.size.height * (220/812), alignment: .topTrailing)
.frame(width: deviceSize.size.width, height:deviceSize.size.height , alignment: .topTrailing)
.edgesIgnoringSafeArea(.all)
Image("blobVectorDark")
.resizable()
.frame(width: deviceSize.size.height * (208/812) * 0.74, height: deviceSize.size.height * (208/812), alignment: .topTrailing)
// .overlay(Image("blobVectorLight"))
.frame(width: deviceSize.size.width, height:deviceSize.size.height , alignment: .topTrailing)
.edgesIgnoringSafeArea(.all)
VStack{
Image ("twitter")
.resizable()
.frame(width: deviceSize.size.height*(77/812)*2.078, height: deviceSize.size.height*(77/812))
Text ("Sign into your account")
.foregroundColor(.white)
TextField ("Username")
}
}
}
}
}
To move any element up use:
.offset(y: -200.0)
To increase spacing between elements in a VStack declare it like this:
VStack(spacing: 20.0) { //....
Too use a TextField you need a value to bind it to:
//outside the body declare:
#State private var username: String = ""
//and then inside the body:
TextField("Username", text: $username)
I just sum up all what you are supposed to do here:
VStack(spacing: 50){
Spacer()
Image ("image")
.resizable()
.frame(width: deviceSize.size.height*(77/812)*2.078, height: deviceSize.size.height*(77/812))
Spacer()
Text ("Sign into your account")
.foregroundColor(.white)
TextField.init("Username", text: self.$userName)
Spacer()
}
above the body:
#State var userName: String = ""
var body: some View {
......
Hope you get what you want.

Resources