如何在SwiftUI的macOS应用程序中模糊背景?

8

enter image description here

我希望将突出显示的部分设置为透明和模糊,类似于其他macOS应用程序。我在网上找到了关于如何使用NSViewController进行模糊的文章,但我并不完全理解。我是Swift的新手,还不理解如何使用Viewcontrollers。我的代码如下。任何帮助都将不胜感激!


import SwiftUI

struct ContentView: View {

    var body: some View {
        VStack {
            GeometryReader { geometry in
                NavigationView{
                    HStack(spacing: 0) {
                        ZStack{

                            Text("BitMessenger")
                                .font(.title)
                                .fontWeight(.light)
                                .foregroundColor(Color.white)
                        }
                        .frame(width: geometry.size.width/2, height: geometry.size.height+20)
                        .background(Color(red: 0.07, green: 0.07, blue: 0.07, opacity: 1.0))
                        VStack{

                            HStack {
                                Text("Sign Up")
                                    .font(.headline)
                                    .padding(.top, 30.0)
                                Spacer()
                            }




                            HStack {
                                Text("Welcome to BitMessenger")
                                    .font(.subheadline)
                                    .foregroundColor(Color.gray)
                                    .padding(.top, 10.0)
                                Spacer()
                            }

                            Form {
                                VStack{
                                    HStack {
                                        Text("Full Name")
                                            .font(.caption)
                                            .foregroundColor(Color.white)
                                            .padding(.top, 10.0)
                                        Spacer()
                                    }





                                    TextField("ex. John Doe", text: /*@START_MENU_TOKEN@*//*@PLACEHOLDER=Value@*/.constant("")/*@END_MENU_TOKEN@*/)




                                    HStack {
                                        Text("Email Address")
                                            .font(.caption)
                                            .foregroundColor(Color.white)
                                            .padding(.top, 10.0)
                                        Spacer()
                                    }





                                    TextField("doejohn@example.com", text: /*@START_MENU_TOKEN@*//*@PLACEHOLDER=Value@*/.constant("")/*@END_MENU_TOKEN@*/)





                                    HStack {
                                        Text("Password")
                                            .font(.caption)
                                            .foregroundColor(Color.white)
                                            .padding(.top, 10.0)
                                        Spacer()
                                    }



                                    TextField("AIOFHWaowhf", text: /*@START_MENU_TOKEN@*//*@PLACEHOLDER=Value@*/.constant("")/*@END_MENU_TOKEN@*/)

                                    HStack {
                                        Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/) {
                                            Text("Register")
                                                .padding(.horizontal, 10.0)
                                        }
                                        .padding(.all)
                                    }

                                }
                            }
                            .padding(.top)

                            Spacer()

                            NavigationLink(destination: ContentView()) {
                                Text("Already have an Account? Login")
                                .font(.caption)
                                    .foregroundColor(Color.gray)
                                    .background(Color.clear)
                            }
                            .padding(.bottom)
                            .foregroundColor(Color.clear)


                        }
                        .padding(.horizontal, 30.0)
                        .frame(width: geometry.size.width / 2, height: geometry.size.height+20)
                        .background(Color.black.opacity(0.9))
                    }.edgesIgnoringSafeArea(.all)
                }

            }
            .edgesIgnoringSafeArea(.all)
            .frame(width: 750.0, height: 500.0)

        }

    }
}


class MyViewController: NSViewController {

    var visualEffect: NSVisualEffectView!

    override func loadView() {
        super.loadView()

        visualEffect = NSVisualEffectView()
        visualEffect.translatesAutoresizingMaskIntoConstraints = false
        visualEffect.material = .dark
        visualEffect.state = .active
        visualEffect.blendingMode = .behindWindow
        view.addSubview(visualEffect)

        visualEffect.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        visualEffect.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        visualEffect.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        visualEffect.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true


    }
}


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


2个回答

15

你不需要真正地子类化NSViewController。你需要的是来自AppKit的NSVisualEffectView

它为界面中的视图添加半透明和活力效果。

由于NSVisualEffectView在SwiftUI中尚不可用,你可以使用NSViewRepresentable对其进行包装,就像对SwiftUI中不可用的每个AppKit控件一样。

你可以按照以下方式操作-

import SwiftUI

struct VisualEffectView: NSViewRepresentable
{
    let material: NSVisualEffectView.Material
    let blendingMode: NSVisualEffectView.BlendingMode
    
    func makeNSView(context: Context) -> NSVisualEffectView
    {
        let visualEffectView = NSVisualEffectView()
        visualEffectView.material = material
        visualEffectView.blendingMode = blendingMode
        visualEffectView.state = NSVisualEffectView.State.active
        return visualEffectView
    }

    func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context)
    {
        visualEffectView.material = material
        visualEffectView.blendingMode = blendingMode
    }
}

你随后可以将其用作独立的View-

VisualEffectView(material: NSVisualEffectView.Material.contentBackground, blendingMode: NSVisualEffectView.BlendingMode.withinWindow)

或者像这样将其用作突出显示的VStack的背景修饰符 -

.background(VisualEffectView(material: NSVisualEffectView.Material.contentBackground, blendingMode: NSVisualEffectView.BlendingMode.withinWindow))

查看Apple Developer文档,了解有关两种混合模式的更多信息。此外,调整材质属性以获得所需的效果。


1
这个解决方案允许您创建一个semiOpaqueWindow()类型的方法,您可以将其应用于View协议的子级,例如此处的Rectangle形状。
import SwiftUI

extension View {
    public static func semiOpaqueWindow() -> some View {
        VisualEffect().ignoresSafeArea()
    }
}

struct VisualEffect : NSViewRepresentable {
    func makeNSView(context: Context) -> NSView {
        let view = NSVisualEffectView()
        view.state = .active
        return view
    }
    func updateNSView(_ view: NSView, context: Context) { }
}

struct ContentView : View {
    var body: some View {
        ZStack {
            Rectangle.semiOpaqueWindow()
            Text("Semi Transparent MacOS window")
        }
    }
}

接受的解决方案对我没有起作用,但这个方法有效。我确实需要在矩形中添加padding(-1),否则默认背景的一小部分可能会出现。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接