根据焦点文本字段更改线条的颜色
Change color of lines depending on the focus text field
我正在尝试创建一个 OTP 页面,每个数字的底部都有虚线。我为每个数字使用了一个文本字段,总共使用了 6 个文本字段的 6 个数字。我希望在用户输入整数之前更改下一行的颜色。
线条会改变颜色等,具体取决于哪个是活动文本字段。请注意,活动文本字段不应具有不同的颜色。只有下一个文本字段应该。所以如果我输入第一个数字,第二个数字应该已经是绿色了。
然后当我在第二个文本字段中输入数字时,第三个应该是绿色的。
见截图。
我只使用 Xcode 12.3,无法使用 FocusState API 和 Xcode Beta 中使用的其他 API。
import SwiftUI
class ViewModel: ObservableObject {
@Published var otpField = "" {
didSet {
guard otpField.count <= 6,
otpField.last?.isNumber ?? true else {
otpField = oldValue
return
}
}
}
var otp1: String {
guard otpField.count >= 1 else {
return ""
}
return String(Array(otpField)[0])
}
var otp2: String {
guard otpField.count >= 2 else {
return ""
}
return String(Array(otpField)[1])
}
var otp3: String {
guard otpField.count >= 3 else {
return ""
}
return String(Array(otpField)[2])
}
var otp4: String {
guard otpField.count >= 4 else {
return ""
}
return String(Array(otpField)[3])
}
var otp5: String {
guard otpField.count >= 5 else {
return ""
}
return String(Array(otpField)[4])
}
var otp6: String {
guard otpField.count >= 6 else {
return ""
}
return String(Array(otpField)[5])
}
@Published var borderColor: Color = .black
@Published var isTextFieldDisabled = false
var successCompletionHandler: (()->())?
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
@State var isFocused = false
let textBoxWidth = UIScreen.main.bounds.width / 8
let textBoxHeight = UIScreen.main.bounds.width / 8
let spaceBetweenBoxes: CGFloat = 10
let paddingOfBox: CGFloat = 1
var textFieldOriginalWidth: CGFloat {
(textBoxWidth*6)+(spaceBetweenBoxes*3)+((paddingOfBox*2)*3)
}
var body: some View {
VStack {
ZStack {
HStack (spacing: spaceBetweenBoxes){
otpText(text: viewModel.otp1)
otpText(text: viewModel.otp2)
otpText(text: viewModel.otp3)
otpText(text: viewModel.otp4)
otpText(text: viewModel.otp5)
otpText(text: viewModel.otp6)
}
TextField("", text: $viewModel.otpField)
.frame(width: isFocused ? 0 : textFieldOriginalWidth, height: textBoxHeight)
.disabled(viewModel.isTextFieldDisabled)
.textContentType(.oneTimeCode)
.foregroundColor(.clear)
.accentColor(.clear)
.background(Color.clear)
.keyboardType(.numberPad)
}
}
}
private func otpText(text: String) -> some View {
return Text(text)
.font(.title)
.frame(width: textBoxWidth, height: textBoxHeight)
.background(VStack{
Spacer()
RoundedRectangle(cornerRadius: 1)
.frame(height: 1)
.overlay(Capsule().stroke(Color.green))
})
.padding(paddingOfBox)
}
}
我正在研究答案...
这里我更新了代码。
查看:
struct ContentView: View {
@StateObject var viewModel = ViewModel()
let textBoxWidth = UIScreen.main.bounds.width / 8
let textBoxHeight = UIScreen.main.bounds.width / 8
let spaceBetweenLines: CGFloat = 10
let paddingOfBox: CGFloat = 1
var textFieldOriginalWidth: CGFloat {
(textBoxWidth*6)+(spaceBetweenLines*3)+((paddingOfBox*2)*3)
}
var body: some View {
VStack {
ZStack {
HStack (spacing: spaceBetweenLines){
otpText(text: viewModel.otp1, isNextTyped: $viewModel.isNextTypedArr[0])
otpText(text: viewModel.otp2, isNextTyped: $viewModel.isNextTypedArr[1])
otpText(text: viewModel.otp3, isNextTyped: $viewModel.isNextTypedArr[2])
otpText(text: viewModel.otp4, isNextTyped: $viewModel.isNextTypedArr[3])
otpText(text: viewModel.otp5, isNextTyped: $viewModel.isNextTypedArr[4])
otpText(text: viewModel.otp6, isNextTyped: $viewModel.isNextTypedArr[5])
}
TextField("", text: $viewModel.otpField) { isEditing in
viewModel.isEditing = isEditing
}
.frame(width: viewModel.isEditing ? 0 : textFieldOriginalWidth, height: textBoxHeight)
.textContentType(.oneTimeCode)
.foregroundColor(.clear)
.accentColor(.clear)
.background(Color.clear)
.keyboardType(.numberPad)
}
}
}
private func otpText(text: String, isNextTyped: Binding<Bool>) -> some View {
return Text(text)
.font(.title)
.frame(width: textBoxWidth, height: textBoxHeight)
.background(VStack{
Spacer()
RoundedRectangle(cornerRadius: 1)
.frame(height: 0.5)
.foregroundColor(isNextTyped.wrappedValue ? .green : .black)
})
.padding(paddingOfBox)
}
}
视图模型:
class ViewModel: ObservableObject {
@Published var otpField = "" {
didSet {
isNextTypedArr = Array(repeating: false, count: 6)
guard otpField.count <= 6,
otpField.last?.isNumber ?? true else {
otpField = oldValue
return
}
if otpField.count < 6 {
isNextTypedArr[otpField.count] = true
}
}
}
var otp1: String {
guard otpField.count >= 1 else {
return ""
}
return String(Array(otpField)[0])
}
var otp2: String {
guard otpField.count >= 2 else {
return ""
}
return String(Array(otpField)[1])
}
var otp3: String {
guard otpField.count >= 3 else {
return ""
}
return String(Array(otpField)[2])
}
var otp4: String {
guard otpField.count >= 4 else {
return ""
}
return String(Array(otpField)[3])
}
var otp5: String {
guard otpField.count >= 5 else {
return ""
}
return String(Array(otpField)[4])
}
var otp6: String {
guard otpField.count >= 6 else {
return ""
}
return String(Array(otpField)[5])
}
@Published var isNextTypedArr = Array(repeating: false, count: 6)
@Published var borderColor: Color = .black
@Published var isEditing = false {
didSet {
isNextTypedArr = Array(repeating: false, count: 6)
if isEditing && otpField.count < 6 {
isNextTypedArr[otpField.count] = true
}
}
}
}
我正在尝试创建一个 OTP 页面,每个数字的底部都有虚线。我为每个数字使用了一个文本字段,总共使用了 6 个文本字段的 6 个数字。我希望在用户输入整数之前更改下一行的颜色。
线条会改变颜色等,具体取决于哪个是活动文本字段。请注意,活动文本字段不应具有不同的颜色。只有下一个文本字段应该。所以如果我输入第一个数字,第二个数字应该已经是绿色了。
然后当我在第二个文本字段中输入数字时,第三个应该是绿色的。
见截图。
我只使用 Xcode 12.3,无法使用 FocusState API 和 Xcode Beta 中使用的其他 API。
import SwiftUI
class ViewModel: ObservableObject {
@Published var otpField = "" {
didSet {
guard otpField.count <= 6,
otpField.last?.isNumber ?? true else {
otpField = oldValue
return
}
}
}
var otp1: String {
guard otpField.count >= 1 else {
return ""
}
return String(Array(otpField)[0])
}
var otp2: String {
guard otpField.count >= 2 else {
return ""
}
return String(Array(otpField)[1])
}
var otp3: String {
guard otpField.count >= 3 else {
return ""
}
return String(Array(otpField)[2])
}
var otp4: String {
guard otpField.count >= 4 else {
return ""
}
return String(Array(otpField)[3])
}
var otp5: String {
guard otpField.count >= 5 else {
return ""
}
return String(Array(otpField)[4])
}
var otp6: String {
guard otpField.count >= 6 else {
return ""
}
return String(Array(otpField)[5])
}
@Published var borderColor: Color = .black
@Published var isTextFieldDisabled = false
var successCompletionHandler: (()->())?
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
@State var isFocused = false
let textBoxWidth = UIScreen.main.bounds.width / 8
let textBoxHeight = UIScreen.main.bounds.width / 8
let spaceBetweenBoxes: CGFloat = 10
let paddingOfBox: CGFloat = 1
var textFieldOriginalWidth: CGFloat {
(textBoxWidth*6)+(spaceBetweenBoxes*3)+((paddingOfBox*2)*3)
}
var body: some View {
VStack {
ZStack {
HStack (spacing: spaceBetweenBoxes){
otpText(text: viewModel.otp1)
otpText(text: viewModel.otp2)
otpText(text: viewModel.otp3)
otpText(text: viewModel.otp4)
otpText(text: viewModel.otp5)
otpText(text: viewModel.otp6)
}
TextField("", text: $viewModel.otpField)
.frame(width: isFocused ? 0 : textFieldOriginalWidth, height: textBoxHeight)
.disabled(viewModel.isTextFieldDisabled)
.textContentType(.oneTimeCode)
.foregroundColor(.clear)
.accentColor(.clear)
.background(Color.clear)
.keyboardType(.numberPad)
}
}
}
private func otpText(text: String) -> some View {
return Text(text)
.font(.title)
.frame(width: textBoxWidth, height: textBoxHeight)
.background(VStack{
Spacer()
RoundedRectangle(cornerRadius: 1)
.frame(height: 1)
.overlay(Capsule().stroke(Color.green))
})
.padding(paddingOfBox)
}
}
我正在研究答案...
这里我更新了代码。
查看:
struct ContentView: View {
@StateObject var viewModel = ViewModel()
let textBoxWidth = UIScreen.main.bounds.width / 8
let textBoxHeight = UIScreen.main.bounds.width / 8
let spaceBetweenLines: CGFloat = 10
let paddingOfBox: CGFloat = 1
var textFieldOriginalWidth: CGFloat {
(textBoxWidth*6)+(spaceBetweenLines*3)+((paddingOfBox*2)*3)
}
var body: some View {
VStack {
ZStack {
HStack (spacing: spaceBetweenLines){
otpText(text: viewModel.otp1, isNextTyped: $viewModel.isNextTypedArr[0])
otpText(text: viewModel.otp2, isNextTyped: $viewModel.isNextTypedArr[1])
otpText(text: viewModel.otp3, isNextTyped: $viewModel.isNextTypedArr[2])
otpText(text: viewModel.otp4, isNextTyped: $viewModel.isNextTypedArr[3])
otpText(text: viewModel.otp5, isNextTyped: $viewModel.isNextTypedArr[4])
otpText(text: viewModel.otp6, isNextTyped: $viewModel.isNextTypedArr[5])
}
TextField("", text: $viewModel.otpField) { isEditing in
viewModel.isEditing = isEditing
}
.frame(width: viewModel.isEditing ? 0 : textFieldOriginalWidth, height: textBoxHeight)
.textContentType(.oneTimeCode)
.foregroundColor(.clear)
.accentColor(.clear)
.background(Color.clear)
.keyboardType(.numberPad)
}
}
}
private func otpText(text: String, isNextTyped: Binding<Bool>) -> some View {
return Text(text)
.font(.title)
.frame(width: textBoxWidth, height: textBoxHeight)
.background(VStack{
Spacer()
RoundedRectangle(cornerRadius: 1)
.frame(height: 0.5)
.foregroundColor(isNextTyped.wrappedValue ? .green : .black)
})
.padding(paddingOfBox)
}
}
视图模型:
class ViewModel: ObservableObject {
@Published var otpField = "" {
didSet {
isNextTypedArr = Array(repeating: false, count: 6)
guard otpField.count <= 6,
otpField.last?.isNumber ?? true else {
otpField = oldValue
return
}
if otpField.count < 6 {
isNextTypedArr[otpField.count] = true
}
}
}
var otp1: String {
guard otpField.count >= 1 else {
return ""
}
return String(Array(otpField)[0])
}
var otp2: String {
guard otpField.count >= 2 else {
return ""
}
return String(Array(otpField)[1])
}
var otp3: String {
guard otpField.count >= 3 else {
return ""
}
return String(Array(otpField)[2])
}
var otp4: String {
guard otpField.count >= 4 else {
return ""
}
return String(Array(otpField)[3])
}
var otp5: String {
guard otpField.count >= 5 else {
return ""
}
return String(Array(otpField)[4])
}
var otp6: String {
guard otpField.count >= 6 else {
return ""
}
return String(Array(otpField)[5])
}
@Published var isNextTypedArr = Array(repeating: false, count: 6)
@Published var borderColor: Color = .black
@Published var isEditing = false {
didSet {
isNextTypedArr = Array(repeating: false, count: 6)
if isEditing && otpField.count < 6 {
isNextTypedArr[otpField.count] = true
}
}
}
}