I am trying to have 3 text views and an image view inside a vstack and have them align differently.
Here is my code:
VStack(alignment: .leading) {
Text("This is the first paragraph").foregroundColor(Color.red)
Spacer().frame(height: 10)
Text("This is a paragraph with ").foregroundColor(Color.blue) + Text("multiple colors.").foregroundColor(Color.green)
Spacer().frame(height: 10)
if #available(iOS 15.0, *) {
AsyncImage(url: URL(string: "https://www.example.org/img/image.png")) { image in
image.resizable()
} placeholder: {
Color.red
}
.frame(width: 128, height: 128)
.clipShape(RoundedRectangle(cornerRadius: 25))
}
Spacer().frame(height: 10)
Text("Final paragraph").foregroundColor(Color.red)
Spacer()
}
Here in the below image I would like the first line and the image to be center aligned:
I tried it like below but then the left aligned text didn't leave a margin like the above image.
struct ContentView: View {
var body: some View {
VStack {
HStack {
Text("This is the first paragraph").foregroundColor(Color.red).frame(alignment: .leading)
}
Spacer().frame(height: 10)
HStack {
Text("This is a paragraph with ").foregroundColor(Color.blue) + Text("multiple colors.").foregroundColor(Color.green)
Spacer()
}
Spacer().frame(height: 10)
HStack {
if #available(iOS 15.0, *) {
AsyncImage(url: URL(string: "https://www.example.org/img/image.png")) { image in
image.resizable()
} placeholder: {
Color.red
}
.frame(width: 128, height: 128)
.clipShape(RoundedRectangle(cornerRadius: 25))
}
}
Spacer().frame(height: 10)
HStack {
Text("Final paragraph").foregroundColor(Color.red)
Spacer()
}
Spacer()
}
}
}
The view:
I can assume that you just need padding in right place to have something like "margins", so a solution can be like
var body: some View {
VStack(alignment: .leading) {
Text("This is the first paragraph")
.foregroundColor(Color.red)
.frame(maxWidth: .infinity) // << default center !!
Spacer().frame(height: 10)
Text("This is a paragraph with ").foregroundColor(Color.blue) + Text("multiple colors.").foregroundColor(Color.green)
Spacer().frame(height: 10)
if #available(iOS 15.0, *) {
AsyncImage(url: URL(string: "https://www.example.org/img/image.png")) { image in
image.resizable()
} placeholder: {
Color.red
}
.frame(width: 128, height: 128)
.clipShape(RoundedRectangle(cornerRadius: 25))
.frame(maxWidth: .infinity) // << for center !!
}
Spacer().frame(height: 10)
Text("Final paragraph").foregroundColor(Color.red)
Spacer()
}
.padding(.horizontal, 24) // << for margins !!
}
Related
I have a simple screen in which content are going on bottom so I use ScrollView on it issue is when I release scroll its going to top again. I need to replace scrollview to something Because I try with with List but that's not working properly with background image so I use Scrollview
struct signupView: View {
#StateObject var signUpViewModel = signupViewModel()
var body: some View {
ZStack{
GeometryReader { geo in
ScrollView {
VStack{
VStack{
Image("Untitled-2")
.resizable()
.frame(width: geo.size.width * 0.45, height: geo.size.width * 0.45)
}
.padding(.top, geo.size.height * 0.03)
HStack(spacing: 0){
VStack{
Text("Student")
.foregroundColor(signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
Rectangle()
.fill(signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
.frame(width: geo.size.width * 0.4, height: 2)
}
.onTapGesture {
signUpViewModel.isStudent = true
}
VStack{
Text("Facilitator")
.foregroundColor(!signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
Rectangle()
.fill(!signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
.frame(width: geo.size.width * 0.4, height: 2)
}
.onTapGesture {
signUpViewModel.isStudent = false
}
}
VStack{
VStack{
Spacer().frame(height: geo.size.height * 0.7)
TextField("", text: $signUpViewModel.nameField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.nameField.isEmpty,
placeholder: "Name"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
TextField("", text: $signUpViewModel.emailField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.emailField.isEmpty,
placeholder: "Email"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
SecureField("", text: $signUpViewModel.passwordField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordField.isEmpty,
placeholder: "Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
SecureField("", text: $signUpViewModel.passwordRepeatField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordRepeatField.isEmpty,
placeholder: "Repeat Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
TextField("", text: $signUpViewModel.countryField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.countryField.isEmpty,
placeholder: "Select Country"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color.black))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
.overlay(
ZStack{if signUpViewModel.hasOptions {
Spacer().frame(height: 70)
VStack(alignment: .center) {
ForEach(signUpViewModel.countryoptions, id: \.self) {d in
Text(d).frame(maxWidth: .infinity).padding(8).onTapGesture {
signUpViewModel.countryField = d
signUpViewModel.hasOptions = false
}
Divider()
}
}.frame(maxWidth: .infinity).background(RoundedRectangle(cornerRadius: 6).foregroundColor(.white).shadow(radius: 4))
}
}.offset(y: 50)
, alignment: .topLeading)
.overlay(
Image("Untitled-42")
.resizable()
.foregroundColor(.white)
.frame(width: 15, height: 10).padding().padding(.bottom,2).onTapGesture {
signUpViewModel.hasOptions = !signUpViewModel.hasOptions
}
, alignment: .trailing).zIndex(1)
SecureField("", text: $signUpViewModel.passwordRepeatField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordRepeatField.isEmpty,
placeholder: "Repeat Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
}.padding([.top, .leading, .trailing], 8).frame(height: 45)
}
}
.padding()
}
}
}.background(Image("Untitled-7").resizable()).edgesIgnoringSafeArea(.all)
}
}
When I release its going back to top. Don't get it why its happening on this. Or I need to use something else
One way of doing it is with introspect package, you can add the package here https://github.com/siteline/SwiftUI-Introspect.git
scrollView.bounces = false
Here's how I would do it with Introspect:
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}.introspectScrollView { scrollView in
scrollView.bounces = false
}
}
}
also don't forget the imports
import Introspect
I don't want the behavior I'm getting with this SwiftUI thing (first time messing with it). I've been putting .background() on everything and there's some kind of padding happening and some sort of dividing line, whether I enable the Button code or not (pic below is with Button code commented out).
What do I need to do to fix it?
var body: some View {
ZStack() {
Color.black
.ignoresSafeArea(.all)
VStack(alignment: .leading, spacing: 0) {
List(eventFields) { eventField in
HStack() {
Spacer(minLength: 10)
if let iconName = eventField.iconName {
Button(action: {
print("edit \(eventField.name)")
}, label: {
Image(uiImage: UIImage(named: iconName)!.colorizeMask(eventField.iconColor!))
.frame(width: 27, height: 27)
self.background(.black)
}).background(.black)
} else {
Text("")
.frame(width: 27)
}
Text(eventField.iconName == nil ? "" : eventField.name)
.font(.system(size: eventField.labelFontSize))
.foregroundColor(eventField.labelFontColor)
.frame(width: 50, alignment: .trailing)
Spacer(minLength: 3)
Text(eventField.stringValue)
.font(.system(size: eventField.fontSize))
.foregroundColor(eventField.fontColor)
.frame(width: 200, alignment: .leading)
Spacer(minLength: 10)
}.background(.black)
}.background(.black)
}
}
}
}
instead of putting .background on the HStack, use
.listRowBackground(Color.black)
and for separator use
.listRowSeparator(.hidden)
Keep in mind, this is on the HStack not the List
Full Code:
var body: some View {
ZStack() {
Color.black
.ignoresSafeArea(.all)
VStack(alignment: .leading, spacing: 0) {
List(eventFields) { eventField in
HStack() {
Spacer(minLength: 10)
if let iconName = eventField.iconName {
Button(action: {
print("edit \(eventField.name)")
}, label: {
Image(uiImage: UIImage(named: iconName)!.colorizeMask(eventField.iconColor!))
.frame(width: 27, height: 27)
self.background(.black)
}).background(.black)
} else {
Text("")
.frame(width: 27)
}
Text(eventField.iconName == nil ? "" : eventField.name)
.font(.system(size: eventField.labelFontSize))
.foregroundColor(eventField.labelFontColor)
.frame(width: 50, alignment: .trailing)
Spacer(minLength: 3)
Text(eventField.stringValue)
.font(.system(size: eventField.fontSize))
.foregroundColor(eventField.fontColor)
.frame(width: 200, alignment: .leading)
Spacer(minLength: 10)
}
.listRowBackground(Color.black)
.listRowSeparator(.hidden)
}
}
}
}
}
I believe the color specification for your hstack and frames is supposed to be "(Color.black)" instead of just "(.black)".
Which type of color you use isn't consistent across all Swift objects. Some objects, such as UITableView use "UI colors" which are in the form ".black", while others, like frames, vstacks, hstacks and other objects, use SwiftUI colors in the form "Color.black".
I recommend this very informative page for a very accessible explanation of using color in a view and a stack.
I'm currently working on trying to implement a custom dropdown menu in SwiftUI that displays a grid of buttons (1-16) and allows you to select one of them. I am using an overlay to display the dropdown below the corresponding button, and it seems to be functioning properly except it's displaying the dropdown below all of the other elements in the view. I found another post here regarding this issue and they used a ZStack to solve it, but I haven't been able to get the same success. Does anyone have any ideas on how to fix this? Here's my code:
struct ContentView: View {
#State var showDropdown = false
#State var selected = 0
var body: some View {
ZStack {
HStack(spacing: 30) {
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
} else {
EmptyView()
}
}, alignment: .topLeading
)
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}
}
}
.padding()
.frame(maxHeight: .infinity)
.buttonStyle(PlainButtonStyle())
}
}
and here are some images of the results:
Before Press
After Press
Thank you in advance!
The .zIndex works for view in same container, so you need something like the following (or make custom flat layout container with all such buttons at same level, then rise clicked button atop).
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { showDropdown.toggle() }) {
Text(selected == 0 ? "Omni" : String(selected))
.frame(width: 80, height: 36)
}
.zIndex(1)
.overlay(
VStack(spacing: 0) {
if self.showDropdown {
Spacer(minLength: 26)
DropdownMenu(selection: self.$selected)
}
}, alignment: .topLeading
)
}.zIndex(showDropdown ? 1 : 0) // << this !!
HStack {
Text("Some Text")
.lineLimit(1)
Spacer()
Button(action: { }) {
Text("Omni")
.frame(width: 80, height: 36)
}
}
}.zIndex(showDropdown ? 1 : 0) // << and this !!
I am illustrating the problem I have with a simple example below. It all boils down to properly aligning VStacks with text to a Circle. This is the image of what I am trying to get at. Is there any way to align things properly without using hardcoded paddings?
This is the code producing the left image
struct MyAlignedView: View {
var body: some View {
HStack {
VStack(alignment: .center, spacing: 10) {
Circle()
.frame(width: 20, height: 20)
Text("|")
Circle()
.frame(width: 20, height: 20)
Text("|")
Circle()
.frame(width: 20, height: 20)
}
VStack {
VStack{
Text("stack 1")
}
VStack{
Text("stack 2")
Text("text2")
Text("more text")
}
VStack{
Text("stack 3")
Text("text3")
}
}
}
}
}
Here's one way to do it. I put the Circle and the corresponding text into an HStack to keep them aligned. I let every other Circle manage the lines. That keeps them vertically aligned with the Circles.
If you were to continue this, the next Circle would have two lines, or a line and a space if it is the last one.
struct ContentView: View {
var body: some View {
HStack {
VStack(alignment: .center, spacing: 0) {
HStack {
Circle()
.frame(width: 20, height: 20)
Text("stack 1")
.frame(width: 80, height: 40)
}
HStack {
VStack {
Text("|")
Circle()
.frame(width: 20, height: 20)
Text("|")
}
VStack {
Text("stack 2")
Text("text2")
Text("more text")
}
.frame(width: 80, height: 40)
}
HStack {
Circle()
.frame(width: 20, height: 20)
VStack {
Text("stack 3")
Text("text3")
}
.frame(width: 80, height: 40)
}
}
}
}
}
There is a lot of redundancy that needs to be managed. This can be put into a loop that can automatically figure out which lines to add and/or hide:
struct TextLines {
let lines: [String]
}
struct BulletPoints: View {
let textLines: [TextLines]
var body: some View {
HStack {
VStack(alignment: .center, spacing: 0) {
ForEach(0 ..< textLines.count) { idx in
HStack {
VStack {
if !idx.isMultiple(of: 2) {
Text("|")
}
Circle()
.frame(width: 20, height: 20)
if !idx.isMultiple(of: 2) {
Text("|").opacity(idx == self.textLines.count - 1 ? 0 : 1)
}
}
VStack {
ForEach(self.textLines[idx].lines, id: \.self) { line in
Text(line)
}
}
.frame(width: 80, height: 40)
}
}
}
}
}
}
struct ContentView: View {
var body: some View {
BulletPoints(textLines: [
.init(lines: ["stack1"]),
.init(lines: ["stack 2", "text2", "more text"]),
.init(lines: ["stack 3", "text3"]),
.init(lines: ["stack 4"])
])
}
}
I have a SwiftUI view that is a circular view which when tapped opens up and is supposed to extend over the UI to its right. How can I make sure that it will appear atop the other ui? The other UI elements were created using a ForEach loop. I tried zindex but it doesn't do the trick. What am I missing?
ZStack {
VStack(alignment: .leading) {
Text("ALL WORKSTATIONS")
ZStack {
ChartBackground()
HStack(alignment: .bottom, spacing: 15.0) {
ForEach(Array(zip(1..., dataPoints)), id: \.1.id) { number, point in
VStack(alignment: .center, spacing: 5) {
DataCircle().zIndex(10)
ChartBar(percentage: point.percentage).zIndex(-1)
Text(point.month)
.font(.caption)
}
.frame(width: 25.0, height: 200.0, alignment: .bottom)
.animation(.default)
}
}
.offset(x: 30, y: 20)
}
.frame(width: 500, height: 300, alignment: .center)
}
}
}
}
.zIndex have effect for views within one container. So to solve your case, as I assume expanded DataCircle on click, you need to increase zIndex of entire bar VStack per that click by introducing some kind of handling selection.
Here is simplified replicated demo to show the effect
struct TestBarZIndex: View {
#State private var selection: Int? = nil
var body: some View {
ZStack {
VStack(alignment: .leading) {
Text("ALL WORKSTATIONS")
ZStack {
Rectangle().fill(Color.yellow)//ChartBackground()
HStack(alignment: .bottom, spacing: 15.0) {
ForEach(1...10) { number in
VStack(spacing: 5) {
Spacer()
ZStack() { // DataCircle()
Circle().fill(Color.pink).frame(width: 20, height: 20)
.onTapGesture { self.selection = number }
if number == self.selection {
Text("Top Description").fixedSize()
}
}
Rectangle().fill(Color.green) // ChartBar()
.frame(width: 20, height: CGFloat(Int.random(in: 40...150)))
Text("Jun")
.font(.caption)
}.zIndex(number == self.selection ? 1 : 0) // << here !!
.frame(width: 25.0, height: 200.0, alignment: .bottom)
.animation(.default)
}
}
}
.frame(height: 300)
}
}
}
}