Můžete vytvořit "Falešný" TextField
to se zdá více než reálné. Pak se ukáže, že postavy v ForEach
.
To je děláno s FocusState
v iOS 15
@available(iOS 15.0, *)
struct AnimatedInputView: View {
@FocusState private var isFocused: Int?
@State var text: String = ""
//If all the fonts match the cursor is better aligned
@State var font: Font = .system(size: 48, weight: .bold, design: .default)
@State var color: Color = .gray
var body: some View {
HStack(alignment: .center, spacing: 0){
//To maintain size in between the 2 views
Text(text)
.font(font)
.opacity(0)
.overlay(
//This textField will be invisible
TextField("", text: $text)
.font(font)
.foregroundColor(.clear)
.focused($isFocused, equals: 1)
)
.background(
ZStack{
HStack(alignment: .center, spacing: 0, content: {
//You need an array of unique/identifiable characters
let uniqueArray = text.uniqueCharacters()
ForEach(uniqueArray, id: \.id, content: { char in
CharView(char: char.char, isLast: char == uniqueArray.last, font: font)
})
})
}.opacity(1)
.minimumScaleFactor(0.1)
)
.onAppear(perform: {
//Bring focus to the hidden TextField
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
isFocused = 1
})
})
}
.padding()
.border(color)
.font(.title)
//Bring focus to the hidden textfield
.onTapGesture {
isFocused = 1
}
}
}
struct CharView: View{
var char: Character
var isLast: Bool
var font: Font
@State var scale: CGFloat = 0.75
var body: some View{
Text(char.description)
.font(font)
.minimumScaleFactor(0.1)
.scaleEffect(scale)
.onAppear(perform: {
//Animate only if last character
if isLast{
withAnimation(.linear(duration: 0.5)){
scale = 1
}
}else{
scale = 1
}
})
}
}
@available(iOS 15.0, *)
struct AnimatedInputView_Previews: PreviewProvider {
static var previews: some View {
AnimatedInputView()
}
}
//Convert String to Unique characers
extension String{
func uniqueCharacters() -> [UniqueCharacter]{
let array: [Character] = Array(self)
return array.uniqueCharacters()
}
func numberOnly() -> String {
self.trimmingCharacters(in: CharacterSet(charactersIn: "-0123456789.").inverted)
}
}
extension Array where Element == Character {
func uniqueCharacters() -> [UniqueCharacter]{
var array: [UniqueCharacter] = []
for char in self{
array.append(UniqueCharacter(char: char))
}
return array
}
}
//String/Characters can be repeating so yu have to make them a unique value
struct UniqueCharacter: Identifiable, Equatable{
var char: Character
var id: UUID = UUID()
}
Zde je ukázka verze. trvá jen čísla jako kalkulačka vzorku
import SwiftUI
@available(iOS 15.0, *)
struct AnimatedInputView: View {
@FocusState private var isFocused: Int?
@State var text: String = ""
//If all the fonts match the cursor is better aligned
@State var font: Font = .system(size: 48, weight: .bold, design: .default)
@State var color: Color = .gray
var body: some View {
HStack(alignment: .center, spacing: 0){
Text("$").font(font)
//To maintain size in between the 2 views
Text(text)
.font(font)
.opacity(0)
.overlay(
//This textField will be invisible
TextField("", text: $text)
.font(font)
.foregroundColor(.clear)
.focused($isFocused, equals: 1)
.onChange(of: text, perform: { value in
if Double(text) == nil{
//Leaves the negative and decimal period
text = text.numberOnly()
}
//This condition can be improved.
//Checks for 2 occurences of the decimal period
//Possible solution
while text.components(separatedBy: ".").count > 2{
color = .red
text.removeLast()
}
//This condition can be improved.
//Checks for 2 occurences of the negative
//Possible solution
while text.components(separatedBy: "-").count > 2{
color = .red
text.removeLast()
}
color = .gray
})
)
.background(
ZStack{
HStack(alignment: .center, spacing: 0, content: {
//You need an array of unique/identifiable characters
let uniqueArray = text.uniqueCharacters()
ForEach(uniqueArray, id: \.id, content: { char in
CharView(char: char.char, isLast: char == uniqueArray.last, font: font)
})
})
}.opacity(1)
.minimumScaleFactor(0.1)
)
.onAppear(perform: {
//Bring focus to the hidden TextField
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
isFocused = 1
})
})
}
.padding()
.border(color)
.font(.title)
//Bring focus to the hidden textfield
.onTapGesture {
isFocused = 1
}
}
}