SwiftUI - 在工作表中有一个不可滚动的固定继续按钮 [英] SwiftUI - in sheet have a fixed continue button that is not scrollable

查看:22
本文介绍了SwiftUI - 在工作表中有一个不可滚动的固定继续按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如您所看到的,即使我试图将工作表拉下,继续按钮也不会向下移动.我怎样才能让我的工作表表现得像那样?在我的应用程序中,继续按钮移出屏幕.这是我的应用程序在工作表被稍微拉下时的外观:

我还在下面附上了我的代码,它在横向和纵向方向上看起来都很美.有没有办法在不破坏 iPhone 7 等较小设备上的横向外观的情况下实现这一点?

导入 SwiftUI结构介绍视图:查看{@State 私有变量 animationAmount:CGFloat = 1@Environment(\.presentationMode) varpresentationMode@Environment(\.verticalSizeClass) var sizeClassvar主体:一些视图{虚拟堆栈{虚拟堆栈{垫片()如果 sizeClass == .compact {堆栈{文本(欢迎使用演示").fontWeight(.heavy)文本(App").foregroundColor(.orange).fontWeight(.heavy)}.padding(.bottom, 10)}别的 {文本(欢迎来到").fontWeight(.heavy)堆栈{文本(演示").fontWeight(.heavy)文本(App").foregroundColor(.orange).fontWeight(.heavy)}.padding(.bottom, 30)}}//介绍VStack关闭.font(.largeTitle).frame(maxWidth: .infinity, maxHeight: 180)VStack(间距:30){HStack(间距:20){图像(系统名称:火花").foregroundColor(.黄色).font(.title2).scaleEffect(animationAmount).onAppear {让 baseAnimation = Animation.easeInOut(duration: 1)让重复 = baseAnimation.repeatForever(autoreverses: true)返回动画(重复){self.animationAmount = 1.5}}VStack(对齐方式:.leading){文本(全新设计").fontWeight(.semibold)Text(在这里轻松查看您的所有必需品.").foregroundColor(.gray)}垫片()}//H栈1.padding([.leading, .trailing], 10)HStack(间距:20){图像(系统名称:引脚").foregroundColor(.red).font(.title2).padding(.trailing, 5).scaleEffect(animationAmount).onAppear {让 baseAnimation = Animation.easeInOut(duration: 1)让重复 = baseAnimation.repeatForever(autoreverses: true)返回动画(重复){self.animationAmount = 1.5}}VStack(对齐方式:.leading){文本(固定收藏夹").fontWeight(.semibold)Text(你可以在所有设备上固定你最喜欢的内容").foregroundColor(.gray)}垫片()}//H栈2.padding([.leading, .trailing], 10).frame(maxWidth: .infinity, maxHeight: 100)HStack(间距:20){图像(系统名称:moon.stars.fill").foregroundColor(.blue).font(.title2).scaleEffect(animationAmount).onAppear {让 baseAnimation = Animation.easeInOut(duration: 1)让重复 = baseAnimation.repeatForever(autoreverses: true)返回动画(重复){self.animationAmount = 1.5}}VStack(对齐方式:.leading){文本(灵活").fontWeight(.semibold)文本(支持暗模式").foregroundColor(.gray)}垫片()}//H栈3.padding([.leading, .trailing], 10)}//VStack 3个条件.padding([.leading, .trailing], 20)垫片()按钮 {presentationMode.wrappedValue.dismiss()UserDefaults.standard.set(true, forKey: "LaunchedBefore")} 标签: {文本(继续").fontWeight(.medium).padding([.top, .bottom], 15).padding([.leading, .trailing], 90).background(Color.blue).foregroundColor(.white).cornerRadius(15)}.frame(maxWidth: .infinity, maxHeight: 100)}//主VStack}}struct IntroView_Previews: PreviewProvider {静态 var 预览:一些视图 {介绍视图()}}

解决方案

这里是可能方法的演示(调整和效果超出范围 - 尽量缩短演示代码).我们的想法是将 UIView 持有者与 above 工作表的按钮一起注入,以便它在工作表向下拖动期间保持不变(因为调查结果显示任何动态偏移都会产生一些丑陋的不希望有的抖动效果).>

使用 Xcode 12/iOS 14 测试

//... 你上面的代码在这里}//VStack 3个条件.padding([.leading, .trailing], 20)垫片()//按钮从这里移动到下面的背景视图中!!}.background(BottomView(presentation:presentationMode){按钮 {presentationMode.wrappedValue.dismiss()UserDefaults.standard.set(true, forKey: "LaunchedBefore")} 标签: {文本(继续").fontWeight(.medium).padding([.top, .bottom], 15).padding([.leading, .trailing], 90).background(Color.blue).foregroundColor(.white).cornerRadius(15)}})//主VStack}}struct BottomView: UIViewRepresentable {@Binding varpresentationMode: PresentationMode私有变量内容:() ->内容init(presentation: Binding, @ViewBuilder _ content: @escaping() -> Content) {_presentationMode = 演示self.content = 内容}func makeUIView(context: Context) ->界面视图{让视图 = UIView()DispatchQueue.main.async {如果让窗口 = view.window {让持有人 = UIView()context.coordinator.holder = 持有人//简单的演示背景使其可见holder.layer.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColorholder.translatesAutoresizingMaskIntoConstraints = falsewindow.addSubview(持有人)holder.heightAnchor.constraint(equalToConstant: 140).isActive = trueholder.bottomAnchor.constraint(equalTo: window.bottomAnchor, constant: 0).isActive = trueholder.leadingAnchor.constraint(equalTo: window.leadingAnchor, constant: 0).isActive = trueholder.trailingAnchor.constraint(equalTo: window.trailingAnchor, 常量: 0).isActive = true如果让 contentView = UIHostingController(rootView: content()).view {contentView.backgroundColor = UIColor.clearcontentView.translatesAutoresizingMaskIntoConstraints = falseholder.addSubview(contentView)contentView.topAnchor.constraint(equalTo: holder.topAnchor, constant: 0).isActive = truecontentView.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0).isActive = truecontentView.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0).isActive = truecontentView.trailingAnchor.constraint(equalTo: holder.trailingAnchor, 常量: 0).isActive = true}}}返回视图}func updateUIView(_ uiView: UIView, context: Context) {如果 !presentationMode.isPresented {context.coordinator.holder.removeFromSuperview()}}func makeCoordinator() ->协调员{协调员()}班级协调员{变量持有者:UIView!去初始化{holder.removeFromSuperview()}}}

As you can see even though I am trying to pull the sheet down, the continue button does not move down. How can I make my sheet to behave like that? In my app the continue button moves offscreen. This is how my app looks when the sheet is pulled down slightly:

I have also attached my code below, it looks aesthetic on both landscape and portrait orientation. Is there a way to pull this off without ruining how it looks on landscape on smaller devices such as the iPhone 7?

import SwiftUI

struct IntroView: View {
    @State private var animationAmount: CGFloat = 1
    @Environment(\.presentationMode) var presentationMode
    @Environment(\.verticalSizeClass) var sizeClass
    
    var body: some View {
        VStack {
            VStack {
                Spacer()
                if sizeClass == .compact {
                    HStack {
                        Text("Welcome to Demo").fontWeight(.heavy)
                        Text("App").foregroundColor(.orange).fontWeight(.heavy)
                    }
                    .padding(.bottom, 10)
                }
                
                else {
                    Text("Welcome to").fontWeight(.heavy)
                    HStack {
                        Text("Demo").fontWeight(.heavy)
                        Text("App").foregroundColor(.orange).fontWeight(.heavy)
                    }
                    .padding(.bottom, 30)
                }
            }//Intro VStack close
            .font(.largeTitle)
            .frame(maxWidth: .infinity, maxHeight: 180)
            
            VStack (spacing: 30) {
                HStack (spacing: 20) {
                    Image(systemName: "sparkle")
                        .foregroundColor(.yellow)
                        .font(.title2)
                        .scaleEffect(animationAmount)
                        .onAppear {
                            let baseAnimation = Animation.easeInOut(duration: 1)
                            let repeated = baseAnimation.repeatForever(autoreverses: true)
                            return withAnimation(repeated) {
                                self.animationAmount = 1.5
                            }
                        }
                    VStack (alignment: .leading) {
                        Text("All new design").fontWeight(.semibold)
                        Text("Easily view all your essentials here.")
                            .foregroundColor(.gray)
                    }
                    Spacer()
                }//HStack 1
                .padding([.leading, .trailing], 10)
                
                HStack (spacing: 20) {
                    Image(systemName: "pin")
                        .foregroundColor(.red)
                        .font(.title2)
                        .padding(.trailing, 5)
                        .scaleEffect(animationAmount)
                        .onAppear {
                            let baseAnimation = Animation.easeInOut(duration: 1)
                            let repeated = baseAnimation.repeatForever(autoreverses: true)
                            return withAnimation(repeated) {
                                self.animationAmount = 1.5
                            }
                        }
                    VStack (alignment: .leading) {
                        Text("Pin favourites").fontWeight(.semibold)
                        Text("You can pin your favourite content on all devices")
                            .foregroundColor(.gray)
                    }
                    Spacer()
                }//HStack 2
                .padding([.leading, .trailing], 10)
                
                .frame(maxWidth: .infinity, maxHeight: 100)
                
                HStack (spacing: 20) {
                    Image(systemName: "moon.stars.fill")
                        .foregroundColor(.blue)
                        .font(.title2)
                        .scaleEffect(animationAmount)
                        .onAppear {
                            let baseAnimation = Animation.easeInOut(duration: 1)
                            let repeated = baseAnimation.repeatForever(autoreverses: true)
                            return withAnimation(repeated) {
                                self.animationAmount = 1.5
                            }
                        }
                    VStack (alignment: .leading) {
                        Text("Flexible").fontWeight(.semibold)
                        Text("Supports dark mode")
                            .foregroundColor(.gray)
                    }
                    Spacer()
                }//HStack 3
                .padding([.leading, .trailing], 10)
                
            }//VStack for 3 criterias
            .padding([.leading, .trailing], 20)
            
                Spacer()
            
            Button {
                presentationMode.wrappedValue.dismiss()
                UserDefaults.standard.set(true, forKey: "LaunchedBefore")
            } label: {
                Text("Continue")
                    .fontWeight(.medium)
                    .padding([.top, .bottom], 15)
                    .padding([.leading, .trailing], 90)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(15)
            }
            .frame(maxWidth: .infinity, maxHeight: 100)

        }//Main VStack
    }
}
struct IntroView_Previews: PreviewProvider {
    static var previews: some View {
        IntroView()
    }
}

解决方案

Here is a demo of possible approach (tuning & effects are out of scope - try to make demo code short). The idea is to inject UIView holder with button above sheet so it persist during sheet drag down (because as findings shown any dynamic offsets gives some ugly undesired shaking effects).

Tested with Xcode 12 / iOS 14

            // ... your above code here

            }//VStack for 3 criterias
            .padding([.leading, .trailing], 20)

                Spacer()

             // button moved from here into below background view !!

        }.background(BottomView(presentation: presentationMode) {
            Button {
                presentationMode.wrappedValue.dismiss()
                UserDefaults.standard.set(true, forKey: "LaunchedBefore")
            } label: {
                Text("Continue")
                    .fontWeight(.medium)
                    .padding([.top, .bottom], 15)
                    .padding([.leading, .trailing], 90)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(15)
            }
        })
        //Main VStack
    }
}

struct BottomView<Content: View>: UIViewRepresentable {
    @Binding var presentationMode: PresentationMode
    private var content: () -> Content

    init(presentation: Binding<PresentationMode>, @ViewBuilder _ content: @escaping () -> Content) {
        _presentationMode = presentation
        self.content = content
    }

    func makeUIView(context: Context) -> UIView {
        let view = UIView()

        DispatchQueue.main.async {
            if let window = view.window {
                let holder = UIView()
                context.coordinator.holder = holder

                // simple demo background to make it visible
                holder.layer.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColor

                holder.translatesAutoresizingMaskIntoConstraints = false

                window.addSubview(holder)
                holder.heightAnchor.constraint(equalToConstant: 140).isActive = true
                holder.bottomAnchor.constraint(equalTo: window.bottomAnchor, constant: 0).isActive = true
                holder.leadingAnchor.constraint(equalTo: window.leadingAnchor, constant: 0).isActive = true
                holder.trailingAnchor.constraint(equalTo: window.trailingAnchor, constant: 0).isActive = true

                if let contentView = UIHostingController(rootView: content()).view {
                    contentView.backgroundColor = UIColor.clear
                    contentView.translatesAutoresizingMaskIntoConstraints = false
                    holder.addSubview(contentView)

                    contentView.topAnchor.constraint(equalTo: holder.topAnchor, constant: 0).isActive = true
                    contentView.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0).isActive = true
                    contentView.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0).isActive = true
                    contentView.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: 0).isActive = true
                }
            }
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        if !presentationMode.isPresented {
            context.coordinator.holder.removeFromSuperview()
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator {
        var holder: UIView!

        deinit {
            holder.removeFromSuperview()
        }
    }
}

这篇关于SwiftUI - 在工作表中有一个不可滚动的固定继续按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆