SwiftUI comment animer chaque personnage dans textfield?

0

La question

En tant qu'utilisateur des types de caractères dans un champ de texte, je voudrais afficher un peu d'animation sur chaque nouveau caractère tapé (un peu comme la façon de Trésorerie App anime de chiffres, mais j'aimerais le mettre en œuvre pour les caractères alphabétiques ainsi).

enter image description here

Est-il possible de le faire dans SwiftUI? Mon intuition est que je pourrais avoir à pont de UIKit pour plus nuancée de l'accès à un textfields 'élément mais vous ne savez pas comment mettre cela en œuvre.

swift swiftui
2021-11-23 14:54:17
1

La meilleure réponse

1

Il vous suffit de créer un "Faux" TextField qui s'affiche sur le réel. Et puis montrer les personnages dans un ForEach.

Il est fait avec FocusState dans 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()
}

Voici un exemple de version. ne prend que des nombres tels que la calculatrice de l'échantillon

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
        }
    }
}
2021-11-24 02:45:46

Je vous remercie. Pensez-vous que pour permettre le montage, nous pouvons en quelque sorte modifier par programmation le Z-index de l'objet textfield et la superposition de texte? Peut-être utiliser une ZStack plutôt que de superposition. Et lorsque l'utilisateur clique sur le texte, nous pouvons juste faire le Textfield à l'avant pour l'édition et la mise à jour de la char-tableau pour modifier... C'est complexe, mais merci pour la solution!
PipEvangelist

Possible, mais très complexe probablement sujettes à plus de bugs.
lorem ipsum

@PipEvangelist en Fait, j'ai pensé à une autre façon de faire. il ressemble un petit peu, mais une meilleure version. Il permet l'édition. Le curseur est juste un peu hors de
lorem ipsum

Merci!!!! C'est génial
PipEvangelist

Dans d'autres langues

Cette page est dans d'autres langues

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................