Search code examples
swiftswiftuitextfield

Is there a way to make the textfield appear in different color without affecting the semi-transparent background?


I was wondering if it's possible to change the color of the textfield inside the blue border itself, without changing the surrounding area that is semi-transparent. Here is a screenshot of what I have: textfield

Here is a screenshot of what I wish to have: enter image description here

Here is my code:

import SwiftUI

struct ContentView: View {
    @State private var textFieldContent = ""
    
    var body: some View {
        ZStack {
            VisualEffectView()
            GeometryReader { geometry in
                VStack {
                    Rectangle()
                        .foregroundColor(Color(red: 0.1, green: 0.1, blue: 0.1))
                        .frame(height: geometry.size.height / 1.16)
                    Rectangle()
                        .foregroundColor(.clear)
                        .frame(height: geometry.size.height * 2 / 3)
                }
                HStack {
                    TextField("Send a message", text: $textFieldContent)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                        .background(Color.clear)
                        .cornerRadius(25)
                        .focusable(false)
                        .padding(.leading, 20)
                    Spacer()
                    Button(action: {
                        
                    }) {
                        Text("Send")
                            .foregroundColor(.blue)
                    }
                    .buttonStyle(PlainButtonStyle())
                    .padding(.trailing, 20)
                }
                .padding(1)
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
                VStack {
                    HStack {
                        Spacer()
                        Button(action: {
                            
                        }) {
                            Image(systemName: "gearshape")
                                .foregroundColor(.blue)
                                .padding()
                        }
                        .buttonStyle(PlainButtonStyle())
                        .padding(.trailing, 0)
                        .padding(.top, 0)
                    }
                    Spacer()
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
                .padding(.trailing, 0)
                .padding(.top, 20)
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct VisualEffectView: NSViewRepresentable {
    func makeNSView(context: Context) -> NSVisualEffectView {
        let view = NSVisualEffectView()
        view.blendingMode = .behindWindow
        view.state = .active
        view.material = .underWindowBackground
        return view
    }
    func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
    }
}

Also, as a bonus, is it even possible to have the textfield surrounding the area/box more transparent or clear with some blur? As shown in the second screenshot.

I tried changing the textfield using .background(Color.blue) for example, but the whole thing looks different then. See below: enter image description here


Solution

  • Here's how you could do it:

    use .textFieldStyle(.plain) to erase styling and build the textbox yourself.

    HStack {
        TextField("Send a message", text: $textFieldContent)
            .textFieldStyle(.plain) // 👈🏻
            .padding(6)
            .padding(.horizontal, 6)
            .background(Color.black.cornerRadius(6))
        
            .padding()
            .background(Color.clear)
            .focusable(false)
        Button(action: {
            
        }) {
            Text("Send")
                .foregroundColor(.blue)
        }
        .buttonStyle(.plain)
    }
    .padding(.horizontal, 20)
    .padding(1)
    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
    

    enter image description here

    With this solution, you have no focus ring, but in your target example it's also not visible.


    It was not your question, but I think it makes the code more readable to use .padding(.horizontal, 20) rather than the two padding for .leading and .trailing in different places.