SwiftUI jak animować każdy znak w polu tekstowym?

0

Pytanie

Gdy użytkownik wprowadza znaki w polu tekstowym, chciałbym wyświetlać niektóre animacje dla każdego nowo wprowadzonego znaku (coś jak aplikacja Cash animuje liczby, ale chciałbym zrealizować to i dla znaków alfabetycznych).

enter image description here

Czy można to zrobić w SwiftUI? Moja intuicja podpowiada, że być może będę musiała połączyć się z UIKit dla bardziej szczegółowego dostępu do textfieldelement, ale nie jestem pewien, jak to faktycznie zrealizować.

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

Najlepsza odpowiedź

1

Możesz po prostu utworzyć "fałszerstwo" TextField to pojawia się na teraźniejszości. Następnie pokaż znaki ForEach.

Odbywa się to za pomocą FocusState w 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()
}

Oto przykładowa wersja tego. przyjmuje tylko liczby, takie wzorem kalkulatora

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

Dziękuję. Jak myślicie, aby włączyć funkcję edycji, możemy w jakiś sposób programowo zmienić Z-index pola tekstowego i nałożonego tekstu? Możliwe, użyj ZStack, a nie nakładka. I gdy użytkownik kliknie na tekst, możemy po prostu wyświetlić pole tekstowe na wierzch, aby edytować i aktualizować tablicę znaków dla każdej edycji... To trudno, ale dziękuję ci za rozwiązanie!
PipEvangelist

Możliwe, ale bardzo trudne, prawdopodobnie ulega większej ilości błędów.
lorem ipsum

@PipEvangelist faktycznie, ja wymyśliłem inny sposób, aby to zrobić. to wygląda trochę dziwnie, ale jest to najlepsza wersja. To pozwala na edycję. Kursor po prostu trochę off
lorem ipsum

Dziękuję! To jest genialne
PipEvangelist

W innych językach

Ta strona jest w innych językach

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