SwiftUI - VStack - 输入文本时跳转
SwitUI - VStack - Jumping when text entered
我正在开发一个基本的密码输入屏幕,包括一个显示当前输入的顶部堆栈,然后是一些显示数字的 HStack
VStack(){
HStack(spacing: 20){
ForEach(codes,id: \.self){i in
Text("*")
}
}
HStack(){
<Number 1 - 3>
}
HStack(){
<Number 4 - 6>
}
HStack(){
<Number 7 - 9>
}
HStack(){
<Number 0>
}
}
我面临的这个问题是当没有输入密码时,顶部 HStack 不会用完任何 space,因此垂直高度为 0,当我输入密码时,它会强制整个视图跳转随着视图调整大小。
我怎样才能阻止它
老实说,建造过程非常有趣!如果它解决了您的问题,请不要忘记将此答案标记为正确答案。 ✅
问题
跳跃效果是由于 SwiftUI 根据根据您的内容(密码数字)计算的可用 space 更新所有视图位置。字体、字体粗细、文本大小等...都会影响留给其他视图的可用 space。
解决方案
为避免这种情况,您需要一个预定义的框架,让父视图知道您的数字永远不会占用更多 space。这样做,每次更新都不会影响任何其他视图的位置,因为分配的顶部 space 将始终是您指定的大小,而不是数字大小(或缺失)。
代码
import SwiftUI
import Combine
// Using Combine to manage digits and future network calls…
class PasscodeManager: ObservableObject {
let codesQuantity = 4
@Published var codes = [Int]()
}
struct PasscodeView: View {
@StateObject private var manager = PasscodeManager()
var body: some View {
VStack {
Spacer()
// Dots placeholders and passcode digits
selectedCodes
Spacer()
// Numberpad
PasscodeLine(numbers: 1...3) { add(number: [=10=]) }
PasscodeLine(numbers: 4...6) { add(number: [=10=]) }
PasscodeLine(numbers: 7...9) { add(number: [=10=]) }
PasscodeLine(numbers: 0...0) { add(number: [=10=]) }
Spacer()
}
.padding()
}
var selectedCodes: some View {
let minDots = manager.codes.count == manager.codesQuantity ? 0:1
let maxDots = manager.codesQuantity - manager.codes.count
return HStack(spacing: 32) {
ForEach(manager.codes, id: \.self) { Text("\([=10=])") }
if maxDots != 0 {
ForEach(minDots...maxDots, id: \.self) { _ in
Circle().frame(width: 12)
}
}
}
.font(.title.bold())
// Setting a default height should fix your problem.
.frame(height: 70)
}
func add(number: Int) {
guard manager.codes.count < manager.codesQuantity else { return }
manager.codes.append(number)
}
}
struct PasscodeLine: View {
let numbers: ClosedRange<Int>
var select: (Int) -> Void
var body: some View {
HStack {
ForEach(numbers, id: \.self) { number in
Spacer()
Button(action: { select(number) },
label: {
Text("\(number)")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color(.label))
.padding(32)
.background(Color(.quaternarySystemFill))
.clipShape(Circle())
})
}
Spacer()
}
}
}
结果
我正在开发一个基本的密码输入屏幕,包括一个显示当前输入的顶部堆栈,然后是一些显示数字的 HStack
VStack(){
HStack(spacing: 20){
ForEach(codes,id: \.self){i in
Text("*")
}
}
HStack(){
<Number 1 - 3>
}
HStack(){
<Number 4 - 6>
}
HStack(){
<Number 7 - 9>
}
HStack(){
<Number 0>
}
}
我面临的这个问题是当没有输入密码时,顶部 HStack 不会用完任何 space,因此垂直高度为 0,当我输入密码时,它会强制整个视图跳转随着视图调整大小。
我怎样才能阻止它
老实说,建造过程非常有趣!如果它解决了您的问题,请不要忘记将此答案标记为正确答案。 ✅
问题
跳跃效果是由于 SwiftUI 根据根据您的内容(密码数字)计算的可用 space 更新所有视图位置。字体、字体粗细、文本大小等...都会影响留给其他视图的可用 space。
解决方案
为避免这种情况,您需要一个预定义的框架,让父视图知道您的数字永远不会占用更多 space。这样做,每次更新都不会影响任何其他视图的位置,因为分配的顶部 space 将始终是您指定的大小,而不是数字大小(或缺失)。
代码
import SwiftUI
import Combine
// Using Combine to manage digits and future network calls…
class PasscodeManager: ObservableObject {
let codesQuantity = 4
@Published var codes = [Int]()
}
struct PasscodeView: View {
@StateObject private var manager = PasscodeManager()
var body: some View {
VStack {
Spacer()
// Dots placeholders and passcode digits
selectedCodes
Spacer()
// Numberpad
PasscodeLine(numbers: 1...3) { add(number: [=10=]) }
PasscodeLine(numbers: 4...6) { add(number: [=10=]) }
PasscodeLine(numbers: 7...9) { add(number: [=10=]) }
PasscodeLine(numbers: 0...0) { add(number: [=10=]) }
Spacer()
}
.padding()
}
var selectedCodes: some View {
let minDots = manager.codes.count == manager.codesQuantity ? 0:1
let maxDots = manager.codesQuantity - manager.codes.count
return HStack(spacing: 32) {
ForEach(manager.codes, id: \.self) { Text("\([=10=])") }
if maxDots != 0 {
ForEach(minDots...maxDots, id: \.self) { _ in
Circle().frame(width: 12)
}
}
}
.font(.title.bold())
// Setting a default height should fix your problem.
.frame(height: 70)
}
func add(number: Int) {
guard manager.codes.count < manager.codesQuantity else { return }
manager.codes.append(number)
}
}
struct PasscodeLine: View {
let numbers: ClosedRange<Int>
var select: (Int) -> Void
var body: some View {
HStack {
ForEach(numbers, id: \.self) { number in
Spacer()
Button(action: { select(number) },
label: {
Text("\(number)")
.font(.title)
.fontWeight(.medium)
.foregroundColor(Color(.label))
.padding(32)
.background(Color(.quaternarySystemFill))
.clipShape(Circle())
})
}
Spacer()
}
}
}