SwitUI - VStack - 输入文本时跳转

问题描述

我正在开发一个基本的密码输入屏幕,包括一个显示当前输入的顶部堆栈,然后是一些显示数字的 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 不会占用任何空间,因此垂直高度为 0,当我输入代码时,它会强制整个视图随着视图调整大小而跳跃一点.

我怎么能阻止它

解决方法

老实说,建造起来很有趣! ? 如果它解决了您的问题,请不要忘记将这个答案标记为正确的答案。 ✅

问题

跳跃效果是由于 SwiftUI 会根据根据您的内容(密码数字)计算出的可用空间更新所有视图位置。字体、字体粗细、文字大小等……都会影响其他视图的可用空间。

解决方案

为了避免这种情况,您需要一个预定义的框架,让父视图知道您的数字永远不会占用更多空间。这样做,每次更新都不会影响任何其他视图的位置,因为分配的顶部空间始终是您指定的大小,而不是数字大小(或不存在)。

代码

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: $0) }
            PasscodeLine(numbers: 4...6) { add(number: $0) }
            PasscodeLine(numbers: 7...9) { add(number: $0) }
            PasscodeLine(numbers: 0...0) { add(number: $0) }
            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("\($0)") }
            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()
        }
    }
}

结果

enter image description here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...