Search code examples
iosswiftswiftuiios-keyboard-extension

iOS 15 Keyboard hides textfield


I am trying to create a messaging page layout but the keyboard hides the textfield and moves everything to the the top. I have looked at many tutorials online and replicated them exactly but none of them seem to work.

Here is all the code I have written:

struct MessagingPage: View {
    var user: OfficialUserModel
    @ObservedObject private var vm = TheUserModel()
    @State var screenWidth = UIScreen.main.bounds.width
    @State var imageSize = UIScreen.main.bounds.width / 12
    @State var text = ""
    @State var show = false
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        NavigationView{
            ZStack{
                VStack{
                    
                    HStack{
                        Spacer()
                        
                        NavigationLink(destination: UserDisplayPage(user: user)) {
                                HStack{
                                    WebImage(url: URL(string: user.imageURL ))
                                        .resizable()
                                        .aspectRatio( contentMode: .fill)
                                        .frame(width: imageSize, height: imageSize
                                        )
                                        .cornerRadius(imageSize/2)
                                    
                                    VStack(alignment: .leading){
                                        Text(user.FullName)
                                            .font(.body)
                                            .fontWeight(.bold)
                                            .foregroundColor(.white)
                                        
                                        Text("\(user.City) , \(user.Country)")
                                            .font(.caption)
                                            .fontWeight(.semibold)
                                            .foregroundColor(.white)
                                    }
                                }
                        }
                        Spacer()
                        
                        HStack{
                            Button{
                                presentationMode.wrappedValue.dismiss()
                            } label: {
                                Image(systemName: "chevron.down")
                                    .font(.title)
                                    .foregroundColor(.myWhite)
                            }
                        }
                        .padding(.trailing)
                        
                    }
                    .padding(.top, 30)
                    .frame(height: 75)
                    .background(Color.mainBlack)
                    
                    ScrollView{
                        Spacer()
                        ForEach(0..<2){ num in
                            HStack{
                                Spacer()
                                HStack{
                                    Text("Hello \(user.firstName)")
                                        .foregroundColor(.orange)
                                }
                                .padding()
                                .background(Color.mainBlack)
                                .cornerRadius(15)
                                .shadow(color: .orange, radius: 2)
                            }
                            .padding(.horizontal)
                            .padding(.top, 8)
                        }
                        HStack{Spacer()}
                        
                        HStack{
                            HStack{
                                Text("\(user.FullName) is unable to recieve your message at this time. Please try again at a later time.")
                                    .foregroundColor(.green)
                            }
                            .padding()
                            .background(Color.mainBlack)
                            .cornerRadius(15)
                            .shadow(color: .green, radius: 2)
                            
                            Spacer()
                        }
                        .padding(.horizontal)
                        .padding(.top, 8)
                    
                    HStack{Spacer()}
                    }
                    .background(Color.mainBlack)
                    
                    ZStack{
                    HStack{
                        HStack{
                        
                        HStack{
                            TextField("Say Something...", text: self.$text)
                                .placeholder(when: text.isEmpty) {
                                    Text("Say Something...").foregroundColor(.myWhite.opacity(0.5))
                                }
                                .frame(width: screenWidth - 200, height: screenWidth/25)
                                .foregroundColor(.myCyan)
                                .accentColor(.myCyan)
                                .background(Color.mainBlack)
                                .textContentType(.emailAddress)
                            
                            if !text.isEmpty{
                                Button{
                                    print(text)
                                    self.text = ""
                                }label: {
                                    Image(systemName: "paperplane")
                                        .foregroundColor(.myCyan)
                                        .font(.system(size: 20))
                                }
                            }
                            else{
                                Button{
                                    print("Show more options")
                                }label: {
                                    Image(systemName: "plus")
                                        .foregroundColor(.myCyan)
                                        .font(.system(size: 20))
                                }
                            }
                           
                        }
                        .frame(width: screenWidth - 150, height: screenWidth/25)
                        .padding()
                        .background(Color.mainBlack)
                        .cornerRadius(30)
                        .shadow(color: .myCyan, radius: 5)
                        .padding(.bottom,5)
                    }
                    
                    }
                    .padding(.bottom, 50)
                    .frame(width: screenWidth)
                    }
                }
            }
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
            .background(Color.mainBlack)
            .navigationBarTitle("")
            .navigationBarHidden(true)
           
        }
        
    }
}

I want the the textfield to move up as well as the messages in the scrollview but the top HStack with the user image and back/dismiss button should remain in place.


Solution

  • You really have a lot of code in there - and two reasons to clean it up:

    1. To get a good answer, you need to post a minimal, reproducible example, which may also help you debug the code before posting it
    2. Many lines of code are redundant or useless, for example:
    • Why using things like HStack{Spacer()} instead of Spacer(), which by the way is not needed in this context?
    • Why having a stack that has only another stack inside?

    Coming to your issue, the problem is that one of the redundant modifiers is preventing the text file to move up, and this is the line to delete:

    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    

    Why setting a frame that is as high and large as much as the screen? This is forcing the text field to stay at the bottom.

    I tried to do some clean up, I bet some more can be done - see the code below, now the keyboard does not cover the text field anymore:

    struct MessagingPage: View {
    
       // Removed some lines of code to reproduce your issue
        @State var screenWidth = UIScreen.main.bounds.width
        @State var imageSize = UIScreen.main.bounds.width / 12
        @State var text = ""
        @State var show = false
        @Environment(\.presentationMode) var presentationMode
        
        var body: some View {
            NavigationView{
                
                // What is the purpose of this ZStack???
                //            ZStack{
                VStack{
                    
                    HStack{
                        Spacer()
                        
                        NavigationLink(destination: Text("Hello")) {
                            Text("Top bar")
                        }
                        Spacer()
                        
                        HStack{
                            Button{
                                presentationMode.wrappedValue.dismiss()
                            } label: {
                                Image(systemName: "chevron.down")
                                    .font(.title)
                                    .foregroundColor(.white)
                            }
                        }
                        .padding(.trailing)
                        
                    }
                    .padding(.top, 30)
                    .frame(height: 75)
                    .background(Color.black)
                    
                    ScrollView{
                        
                        // All the views inside the Scrollview need to be inside a VStack
                        VStack {
                            
                            // Why this spacer???
                            //                        Spacer()
                            ForEach(0..<2){ num in
                                HStack{
                                    Spacer()
                                    HStack{
                                        Text("Hello username")
                                            .foregroundColor(.orange)
                                    }
                                    .padding()
                                    .background(Color.black)
                                    .cornerRadius(15)
                                    .shadow(color: .orange, radius: 2)
                                }
                                .padding(.horizontal)
                                .padding(.top, 8)
                            }
                            HStack{Spacer()}
                            
                            HStack{
                                HStack{
                                    Text("User is unable to receive your message at this time. Please try again at a later time.")
                                        .foregroundColor(.green)
                                }
                                .padding()
                                .background(Color.black)
                                .cornerRadius(15)
                                .shadow(color: .green, radius: 2)
                                
                                Spacer()
                            }
                            .padding(.horizontal)
                            .padding(.top, 8)
                            
                            // Why a Spacer inside an HStack???
                            // HStack{Spacer()}
                        }
                        .background(Color.black)
                    }
                    
                    
                    // What is the purpose of this ZStack???
                    // ZStack{
                    
                    // Why an HStack that has only an HStack inside??
                    // HStack{
                    
                    // Why an HStack that has only an HStack inside??
                    
                    // HStack{
                    
                    HStack{
                        TextField("Say Something...", text: self.$text)
                            .frame(width: screenWidth - 200, height: screenWidth/25)
                            .foregroundColor(.cyan)
                            .accentColor(.cyan)
                            .background(Color.white)
                            .textContentType(.emailAddress)
                        
                        if !text.isEmpty{
                            Button{
                                print(text)
                                self.text = ""
                            }label: {
                                Image(systemName: "paperplane")
                                    .foregroundColor(.cyan)
                                    .font(.system(size: 20))
                            }
                        }
                        else{
                            Button{
                                print("Show more options")
                            }label: {
                                Image(systemName: "plus")
                                    .foregroundColor(.cyan)
                                    .font(.system(size: 20))
                            }
                        }
                        
                    }
                    
                    // Are you sure you want set the height of this stack based on the width?
                    //                            .frame(width: screenWidth - 150, height: screenWidth/25)
                    .frame(width: screenWidth - 150)
                    .padding()
                    .background(Color.black)
                    .cornerRadius(30)
                    .shadow(color: .black, radius: 5)
                    .padding(.bottom,5)
                    //                        }
                    
                    //                    }
                    .padding(.bottom, 50)
                    .frame(width: screenWidth)
                    //                }
                }
                //            }
                
                // Why setting a frame that is high and large as much as the screen??
                // .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
                .background(Color.black)
                .navigationBarTitle("")
                .navigationBarHidden(true)
                
            }
            
        }
    }
    

    enter image description here