P_n
P_n

Reputation: 992

How to split app window UI into 2 different colors

I am currently facing an issue where I need to split a window into two sections, with transparent areas surrounding a text field. Although I have managed to implement a workaround, I believe it is not the ideal solution and I am seeking guidance on how to improve it.

The main problem with my current approach is that when I manually resize the window, the colors used to split the window also resize, which is not the desired behavior. Essentially, I want the transparency around the text field area to remain consistent regardless of window resizing.

Here are the key points:

  1. I want to split the window into two sections.
  2. The split should have transparent areas around a text field.
  3. When manually resizing the window, the colors used for splitting should not resize.
  4. I have already implemented a workaround, but I believe it is not the best solution.

Any suggestions, tips, or alternative approaches on how to achieve this desired behavior would be greatly appreciated. Thank you in advance for your assistance!

This is how it looks normal This is how it looks normal

And here is how I don't want it to look like And here is how I don't want it to look like

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))  // darker gray color
                        .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) // Add padding to adjust the text field position
                    Spacer()  // pushes the button to the side
                    Button(action: {
                        // Your action here
                    }) {
                        Text("Send")
                            .foregroundColor(.blue)  // text color of the button
                    }
                    .buttonStyle(PlainButtonStyle()) // Removing button's default styling
                    .padding(.trailing, 20)  // adds some padding to the right of the button
                }
                .padding(1)
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
                VStack {
                    HStack {
                        Spacer()
                        Button(action: {
                            // Your action here
                        }) {
                            Image(systemName: "gearshape")
                                .foregroundColor(.blue)
                                .padding()
                        }
                        .buttonStyle(PlainButtonStyle())
                        .padding(.trailing, 0) // Adjust the trailing padding to move the gear button to the right
                        .padding(.top, 0) // Adjust the top padding to move the gear button down
                    }
                    Spacer()
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
                .padding(.trailing, 0) // Adjust the trailing padding of the gear button container
                .padding(.top, 20) // Adjust the top padding of the gear button container
            }
        }
        .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) {
        // No update code needed here for this example.
    }
}

I tried using geometryReader in hope that would do the trick, but I realize this is not the right way of doing it. I was expecting that the color would be in the same position all the time, even after rescaling the size of the window.

GeometryReader { geometry in
                VStack {
                    Rectangle()
                        .foregroundColor(Color(red: 0.1, green: 0.1, blue: 0.1))  // darker gray color
                        .frame(height: geometry.size.height / 1.16)
                    Rectangle()
                        .foregroundColor(.clear)
                        .frame(height: geometry.size.height * 2 / 3)
                }

Upvotes: 1

Views: 196

Answers (1)

jnpdx
jnpdx

Reputation: 52347

The main issue right now is that you're trying to rely on GeometryReader to make relative size Views, but it seems that you really want a static size height for the TextField and its background.

There are a number of ways to achieve the layout you're looking for. I generally lean towards using frames rather than Spacers, but that's just a matter of preference.

struct ContentView: View {
    @State private var textFieldContent = ""
    
    var body: some View {
        ZStack {
            VisualEffectView()
            
            VStack {
                VStack {
                    // Main content
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
                .background(
                    Color(red: 0.1, green: 0.1, blue: 0.1)
                )
                .overlay(
                    Button(action: {
                        // Your action here
                    }) {
                        Image(systemName: "gearshape")
                            .foregroundColor(.blue)
                            .padding()
                    }
                    .buttonStyle(PlainButtonStyle()) // Removing button's default styling
                    .padding(.trailing, 20)  // adds some padding to the right of the button
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
                )
                
                HStack {
                    TextField("Send a message", text: $textFieldContent)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                        .background(Color.clear)
                        .cornerRadius(25)
                        .focusable(false)
                        .padding(.leading, 20) // Add padding to adjust the text field position
                    Button(action: {
                        // Your action here
                    }) {
                        Text("Send")
                            .foregroundColor(.blue)  // text color of the button
                    }
                    .buttonStyle(PlainButtonStyle()) // Removing button's default styling
                    .padding(.trailing, 20)  // adds some padding to the right of the button
                }
                .padding(1)
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

Note that you could also get rid of the ZStack and just add .background(VisualEffectView()) to the outer VStack -- also just a matter of preference.

Upvotes: 0

Related Questions