admin管理员组文章数量:1356560
There is a similar question here on stackoverflow for how to do it when they are all the same size but not when they are different sizes,I have 4 views in a HStack that I want to evenly space out but since the Picker is larger than the other 3 its impossible to do it using Spacer and since there are now 4 instead of 3 I cannot use alignment anymore either. What is the solution for ensuring they are all evenly spaced out?
import SwiftUI
@EnvironmentObject var captureDelegate: CaptureDelegate
let images = ["person.slash.fill", "person.fill", "person.2.fill", "person.2.fill", "person.2.fill"]
@Binding var timerPress: Bool
private var rotationAngle: Angle {
switch captureDelegate.orientationLast {
case .landscapeRight:
return .degrees(90)
case .landscapeLeft:
return .degrees(-90) // Fixes the upside-down issue
default:
return .degrees(0)
}
}
var body: some View {
HStack() {
Image(systemName: "gearshape")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
if !captureDelegate.cameraPressed {
}
}
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
Picker("Pick a number of people", selection: $captureDelegate.userSelectedNumber) {
ForEach(0...4, id: \.self) { i in
HStack(spacing: 70) {
Image(systemName: self.images[i])
.resizable()
.frame(width: 20, height: 20)
.rotationEffect(rotationAngle)
Text("\(i)")
.font(.system(size: 42))
.rotationEffect(rotationAngle)
}.tag(i)
.rotationEffect(rotationAngle)
}
}
.tint(.white)
.clipped()
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.animation(.easeInOut(duration: 0.5), value: rotationAngle)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.font(.system(size: 24))
.padding([.leading,.trailing], 15)
}
}
I have tried using Spacer but it doesnt work because they are not all the same size, when I had 3 views I had success using alignment leading center and trailing but now that there are 4 views it no longer works.
Here I have attempted to use a ZStack to position them putting the two center views in the same HStack:
ZStack {
HStack {
Image(systemName: "gearshape")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
if !captureDelegate.cameraPressed {
}
}
Picker("Pick a number of people", selection: $captureDelegate.userSelectedNumber) {
ForEach(0...4, id: \.self) { i in
HStack(spacing: 70) {
Image(systemName: self.images[i])
.resizable()
.frame(width: 20, height: 20)
.rotationEffect(rotationAngle)
Text("\(i)")
.font(.system(size: 42))
.rotationEffect(rotationAngle)
}.tag(i)
.rotationEffect(rotationAngle)
}
}
.tint(.white)
.clipped()
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.animation(.easeInOut(duration: 0.5), value: rotationAngle)
.frame(maxWidth: .infinity, alignment: .trailing)
}
HStack {
Text("\(captureDelegate.totalPhotosToTake)")
.font(.system(size: 15))
.foregroundStyle(.white)
.fontWeight(.bold)
.padding(.horizontal, 9)
.padding(.vertical, 5)
.overlay(
RoundedRectangle(cornerRadius: 5).stroke(.white, lineWidth: 2)
)
.frame(maxWidth: .infinity, alignment: .center)
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
}
.font(.system(size: 24))
.padding([.leading,.trailing], 15)
And changing the two center views alignments from center to trialing and leading produces this affect:
There is a similar question here on stackoverflow for how to do it when they are all the same size but not when they are different sizes,I have 4 views in a HStack that I want to evenly space out but since the Picker is larger than the other 3 its impossible to do it using Spacer and since there are now 4 instead of 3 I cannot use alignment anymore either. What is the solution for ensuring they are all evenly spaced out?
import SwiftUI
@EnvironmentObject var captureDelegate: CaptureDelegate
let images = ["person.slash.fill", "person.fill", "person.2.fill", "person.2.fill", "person.2.fill"]
@Binding var timerPress: Bool
private var rotationAngle: Angle {
switch captureDelegate.orientationLast {
case .landscapeRight:
return .degrees(90)
case .landscapeLeft:
return .degrees(-90) // Fixes the upside-down issue
default:
return .degrees(0)
}
}
var body: some View {
HStack() {
Image(systemName: "gearshape")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
if !captureDelegate.cameraPressed {
}
}
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
Picker("Pick a number of people", selection: $captureDelegate.userSelectedNumber) {
ForEach(0...4, id: \.self) { i in
HStack(spacing: 70) {
Image(systemName: self.images[i])
.resizable()
.frame(width: 20, height: 20)
.rotationEffect(rotationAngle)
Text("\(i)")
.font(.system(size: 42))
.rotationEffect(rotationAngle)
}.tag(i)
.rotationEffect(rotationAngle)
}
}
.tint(.white)
.clipped()
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.animation(.easeInOut(duration: 0.5), value: rotationAngle)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.font(.system(size: 24))
.padding([.leading,.trailing], 15)
}
}
I have tried using Spacer but it doesnt work because they are not all the same size, when I had 3 views I had success using alignment leading center and trailing but now that there are 4 views it no longer works.
Here I have attempted to use a ZStack to position them putting the two center views in the same HStack:
ZStack {
HStack {
Image(systemName: "gearshape")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
if !captureDelegate.cameraPressed {
}
}
Picker("Pick a number of people", selection: $captureDelegate.userSelectedNumber) {
ForEach(0...4, id: \.self) { i in
HStack(spacing: 70) {
Image(systemName: self.images[i])
.resizable()
.frame(width: 20, height: 20)
.rotationEffect(rotationAngle)
Text("\(i)")
.font(.system(size: 42))
.rotationEffect(rotationAngle)
}.tag(i)
.rotationEffect(rotationAngle)
}
}
.tint(.white)
.clipped()
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.animation(.easeInOut(duration: 0.5), value: rotationAngle)
.frame(maxWidth: .infinity, alignment: .trailing)
}
HStack {
Text("\(captureDelegate.totalPhotosToTake)")
.font(.system(size: 15))
.foregroundStyle(.white)
.fontWeight(.bold)
.padding(.horizontal, 9)
.padding(.vertical, 5)
.overlay(
RoundedRectangle(cornerRadius: 5).stroke(.white, lineWidth: 2)
)
.frame(maxWidth: .infinity, alignment: .center)
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
}
.font(.system(size: 24))
.padding([.leading,.trailing], 15)
And changing the two center views alignments from center to trialing and leading produces this affect:
Share Improve this question edited Mar 28 at 16:07 john smith asked Mar 28 at 14:12 john smithjohn smith 1516 bronze badges 3 |2 Answers
Reset to default 0Using a ZStack
is certainly one way to lay out the items. I am not sure if your solution using Spacer
is precise (especially since an HStack
adds spacing between the items), but it might still be fit for purpose.
If you want a precise solution then I think the width of the screen needs to be known.
When the width of the screen is known, the width of the middle items can be enlarged to two-thirds of the screen width (with center alignment). Then, these items can be aligned to the leading or trailing edge of the
ZStack
using a frame withmaxWidth: .infinity
(as for the first and last items).Your items are spread across the full width of the screen. So one way of finding the screen width is to use
.containerRelativeFrame
. The container in this case is the screen.Since the alignment of the middle items is based on the full screen width, you should not apply any horizontal padding to the container (now the
ZStack
). To keep the first and last items away from the sides, apply padding to these items individually.
ZStack {
Image(systemName: "gearshape")
.resizable()
.scaledToFit()
.frame(width: 25, height: 25)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.leading, 15)
Image(systemName: "timer")
.resizable()
.scaledToFit()
.frame(width: 25, height: 25)
.containerRelativeFrame(.horizontal) { screenWidth, _ in
2 * screenWidth / 3
}
.frame(maxWidth: .infinity, alignment: .leading)
Image(systemName: "timer")
.resizable()
.scaledToFit()
.frame(width: 25, height: 25)
.containerRelativeFrame(.horizontal) { screenWidth, _ in
2 * screenWidth / 3
}
.frame(maxWidth: .infinity, alignment: .trailing)
Picker("Pick a number of people", selection: $userSelectedNumber) {
ForEach(Array(images.enumerated()), id: \.offset) { i, imageName in
HStack(spacing: 70) {
Image(systemName: imageName)
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
Text("\(i)")
.font(.system(size: 42))
}
.tag(i)
}
}
.tint(.white)
.clipped()
.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.trailing, 15)
}
.foregroundStyle(.white)
.font(.system(size: 24))
Visually, this still doesn't look quite right to me. But you now have more control of the spacing, so the layout can be tweaked, either by changing the fraction of the screen width for the middle items, or by changing the padding. For example:
- change the leading padding on the first item from 15 to 5
- remove the trailing padding from the last item (the
Picker
) - add horizontal padding of 10 to the
ZStack
The ZStack attempt can be made to work with the use of Spacers to achieve the 1/3 and 2/3 positioning
HStack {
Spacer()
Spacer()
Spacer()
Text("\(captureDelegate.totalPhotosToTake)")
.font(.system(size: 15))
.foregroundStyle(.white)
.fontWeight(.bold)
.padding(.horizontal, 9)
.padding(.vertical, 5)
.overlay(
RoundedRectangle(cornerRadius: 5).stroke(.white, lineWidth: 2)
)
// .frame(maxWidth: .infinity, alignment: .center)
Spacer()
Spacer()
Image(systemName: "timer")
.resizable()
.frame(width: 25, height: 25)
.foregroundStyle(captureDelegate.cameraPressed ? Color(white: 0.4) : .white )
.disabled(captureDelegate.cameraPressed)
.rotationEffect(rotationAngle)
.onTapGesture {
if !captureDelegate.cameraPressed {
timerPress.toggle()
}
}
// .frame(maxWidth: .infinity, alignment: .center)
Spacer()
Spacer()
Spacer()
}
本文标签:
版权声明:本文标题:ios - How to make 4 views in HStack align 1st to the left, 2nd at ⅓ horizontal distance, 3rd at ⅔ horizontal distance and 4th at 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744032212a2579120.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
ZStack
might be one way to do it, or wrapping in aGeometryReader
, or a customLayout
. The post How do I center these images in a straight line inside my HStack in SwiftUI might help. – Benzy Neez Commented Mar 28 at 15:53