jeff-ridgeway
jeff-ridgeway

Reputation: 171

SwiftUI Keyboard pops up once for Input and keeps appearing and disappearing

I am a novice when it comes to Swift programming and am trying to learn how to build my own chat app via some YouTube tutorials. I've gotten pretty far but hit a snag. I don't understand why when I try to type in a TextField, it works fine the first time but if I click in there any other subsequent time, the keyboard pops up and then immediately goes away.

The line of code that is .clipShape(Rectangle()) was originally .clipShape(RoundedShape()) but that was cutting off the messages, so I defaulted to Rectangle(). I think it has something to do with either my TextField or Rectangle(). Check out the screenshot below with the keyboard (the first try):

iOS simulator with keyboard

Here is my code below:

import SwiftUI

struct ChatUIView: View {
    
    @State var message = ""
    //StateObject is the owner of the object...
    @StateObject var allMessages = Messages()
    
    var body: some View {
        VStack{
            
            ZStack{
                
                /*
                HStack{
                    Spacer()
                }*/
                
                VStack(spacing:5){
                    Text("Chat")
                        .fontWeight(.bold)
                }
                .foregroundColor(.white)
            }
            .padding(.all)
            
            //Spacer()
            VStack{
                
                //Spacer()
                //Displaying Message...
                
                ScrollView(.vertical, showsIndicators: false, content: {
                    
                    ScrollViewReader{reader in
                        
                        VStack(spacing: 20){
                            
                            ForEach(allMessages.messages){msg in
                                
                                //Chat Bubbles...
                                
                                ChatBubble(msg: msg)
                            
                                
                            }
                            //whenever new data is inserted, scroll to bottom...
                            .onChange(of: allMessages.messages) {(value) in
                                
                                //scrolling only user message...
                                
                                if value.last!.myMsg{
                                    reader.scrollTo(value.last?.id)
                                }
                                
                            }
                        }
                        .padding([.horizontal, .bottom])
                        .padding(.top, 25)
                    }
                })
                
                HStack(spacing:15){
                    
                    HStack(spacing: 15){
                        TextField("Message", text: self.$message)
                    }
                    .padding(.vertical, 12)
                    .padding(.horizontal)
                    .background(Color.black.opacity(0.06))
                    .clipShape(Capsule())
                    
                    
                    //send button
                    //hiding view...
                    if message != ""{
                        Button(action: {
                            
                            //appending message...
                            
                            //adding animation...
                            withAnimation(.easeIn){
                                allMessages.messages.append(Message(id: Date(), message: message, myMsg: true))
                            }
                            message = ""
                            
                        }, label: {
                            
                            Image("send")
                                .resizable()
                                .frame(width: 25, height: 25)
                                .rotationEffect(.init(degrees: 45))
                                .padding()
                                //.aspectRatio(contentMode: .fit)
                                //.font(.system(size: 0.5))
                                //.padding(.all)
                                .background(Color.black.opacity(0.07))
                                .clipShape(Circle())
                        })
                    }
                }
                .padding(.horizontal)
                .animation(.easeOut)
            }
            .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom)
            .background(Color.white)
            //.clipShape(RoundedShape())
            .clipShape(Rectangle())
            .keyboardType(.default)
        }
        //.edgesIgnoringSafeArea(.bottom)
        .background(Color.blue.edgesIgnoringSafeArea(.top))
    }
}

//Chat Bubbles...

struct ChatBubble : View {
    
    var msg : Message
    var body: some View{
        
        //Automatics scroll to bottom...
        //First assigning id to each row
        
        HStack(alignment: .top, spacing: 10){
            
            if msg.myMsg{
                
                //pushing msg to the left...
                
                //minimum space ...
                Spacer(minLength: 25)
                
                Text(msg.message)
                    .padding(.all)
                    .background(Color.black.opacity(0.06))
                    //.cornerRadius(15)
                    .clipShape(BubbleArrow(myMsg: msg.myMsg))
            } else {
                
                //pushing msg to the right...
                
                Text(msg.message)
                    .fixedSize(horizontal: false, vertical: true)
                    .lineLimit(nil)
                    .foregroundColor(.white)
                    .padding(.all)
                    //.background(Color.black.opacity(0.06))
                    .background(Color.blue)
                    .clipShape(BubbleArrow(myMsg: msg.myMsg))
                
                Spacer(minLength: 25)
            }
        }
        .id(msg.id)
        //.padding(msg.myMsg ? .leading : .trailing, 55)
        //.padding(.vertical,10)
    }
}

// Bubble Arrow...

struct BubbleArrow : Shape {
    
    var myMsg : Bool
    
    
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: myMsg ? [.topLeft, .bottomLeft, .bottomRight] : [.topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10, height: 10))
        
        return Path(path.cgPath)
    }
}


// Custom Rounded Shape...

struct RoundedShape : Shape {
    
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize())
        
        return Path(path.cgPath)
    }
}

// Model Data For Message...

struct Message : Identifiable, Equatable {
    
    var id: Date
    var message: String
    var myMsg: Bool
    //var profilePic: String
    //var photo: Data?
    
}

class Messages: ObservableObject {
    
    @Published var messages : [Message] = []
    
    //sample data...
    init() {
        let strings = ["Hi!", "hello!", "How are you doing?!", "Fine, I just want to talk about life", "ok, I may be able to help with that", "This is awesome, thanks", "So what do you want to talk about?", "movies sound like a good topic. Let's start there!", "Ok, so tell me: What's you favorite movie? LKASJLDJGLSJGOJOSGJDOJGOSDJNOGNSDOGNISNO", "Definitely, interstellar for sure."]
        
        for i in 0..<strings.count{
            
            //simple logic for two sided message View...
            
            messages.append(Message(id: Date(), message: strings[i], myMsg: i % 2 == 0 ? false : true))
        }
    }
    
    func writeMessage(id: Date, msg: String, photo: Data?, myMsg: Bool){
        
        messages.append((Message(id: id, message: msg, myMsg: myMsg)))
        
        
    }
}

Again, I'm not sure what the issue is per se with my SwiftUI code. All of my other TextFields are fine. Any help would be appreciated! Thanks.

Upvotes: 1

Views: 1284

Answers (1)

nicksarno
nicksarno

Reputation: 4245

I'm not sure the exact reason this is happening, but you can just shape the background layer instead of the actual TextField and you'll have the same UI result.

.background(
    Color.black
        .opacity(0.06)
        .clipShape(Capsule())
)
//.clipShape(Capsule())

Upvotes: 2

Related Questions