问题描述
我有一个 SwiftUI 视图,其中包含一个可伸缩的标题、一些选项卡和一个滚动视图。
向上滚动时,无论标题内容大小如何,我都希望标签始终停在导航栏上。标题应与标签一致向上滚动。
我已经能够使用固定值来实现这一点,但这不适用于不同的屏幕尺寸等。
无论屏幕大小如何,我该如何做到这一点?
我附上了一个显示行为的 gif here,正如您在 iPhone 8 上看到的那样,这与导航栏不对齐。
import SwiftUI
struct ContentView: View {
@State private var safeArea: EdgeInsets = EdgeInsets(.zero)
@State private var offset: CGFloat = 0
@State private var tabBarOffset: CGFloat = 0
@State var currentTab = "Tab #1"
@Namespace var animation
var body: some View {
ScrollView {
vstack(spacing: 0) {
makeHeader()
vstack(spacing: 0) {
makeTabs()
makeBody()
}
}
}
}
@viewbuilder func makeHeader() -> some View {
GeometryReader { proxy -> AnyView in
// Header Observer
dispatchQueue.main.async {
offset = proxy.frame(in: .global).minY
safeArea = proxy.safeAreaInsets
}
return AnyView(
ZStack {
// Cover
Color.gray
.frame(maxWidth: .infinity)
.frame(height: offset > 0 ? 180 + offset : 180)
vstack {
Color.white
.clipShape(Circle())
.frame(width: 60,height: 60)
Text("Some Name")
.font(.system(size: 24,weight: .medium,design: .rounded))
HStack {
Text("Some Text #1")
.font(.caption)
Circle()
.frame(width: 3,height: 3)
Text("Some Text #2")
.font(.caption)
}
}
}
.clipped()
// Stretchy Effect
.frame(height: offset > 0 ? 180 + offset : nil)
.offset(y: offset > 0 ? -offset : -offset < 90 ? 0 : -offset - 90)
)
}
.frame(height: 180)
.zIndex(1)
}
@viewbuilder func makeTabs() -> some View {
vstack(spacing: 0) {
HStack(spacing: 0) {
TabButton(title: "Tab #1",currentTab: $currentTab,animation: animation)
.frame(maxWidth: .infinity)
TabButton(title: "Tab #2",animation: animation)
.frame(maxWidth: .infinity)
TabButton(title: "Tab #3",animation: animation)
.frame(maxWidth: .infinity)
}
Text("tabBarOffset: \(tabBarOffset) offset: \(offset)")
.font(.caption)
Divider()
}
.padding(.top,20)
.background(Color.white)
.offset(y: tabBarOffset < 90 ? -tabBarOffset + 90 : 0)
.overlay(
GeometryReader { proxy -> Color in
dispatchQueue.main.async {
tabBarOffset = proxy.frame(in: .global).minY
}
return Color.clear
}
.frame(width: 0,height: 0),alignment: .top
)
.zIndex(1)
}
@viewbuilder func makeBody() -> some View {
vstack {
ForEach((0..<50)) {
Text("Row #\($0)")
Divider()
}
}
.padding(.top)
.zIndex(0)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct TabButton: View {
var title: String
@Binding var currentTab: String
var animation: Namespace.ID
var body: some View {
Button(
action: {
withAnimation { currentTab = title }
},label: {
Lazyvstack(spacing: 12) {
Text(title)
.fontWeight(.semibold)
.foregroundColor(currentTab == title ? .blue : .gray)
.padding(.horizontal)
if currentTab == title {
Capsule()
.fill(Color.blue)
.frame(height: 1.2)
.matchedGeometryEffect(id: "TAB",in: animation)
} else {
Capsule()
.fill(Color.clear)
.frame(height: 1.2)
}
}
}
)
}
}
class SceneDelegate: UIResponder,UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene,willConnectTo session: UIScenesession,options connectionoptions: UIScene.Connectionoptions) {
let contentView = ContentView()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UINavigationController(rootViewController: ViewController(rootView: contentView))
self.window = window
window.makeKeyAndVisible()
}
}
}
class ViewController<Content: View>: UIHostingController<Content> {
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.setBackgroundImage(UIImage(),for: .default)
navigationController?.navigationBar.barTintColor = .clear
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.backgroundColor = .clear
navigationController?.navigationBar.barStyle = .black
}
override public func viewWilldisappear(_ animated: Bool) {
super.viewWilldisappear(animated)
navigationController?.navigationBar.setBackgroundImage(nil,for: .default)
navigationController?.navigationBar.barTintColor = UINavigationBar.appearance().barTintColor
navigationController?.navigationBar.backgroundColor = UINavigationBar.appearance().backgroundColor
navigationController?.navigationBar.barStyle = .default
navigationController?.navigationBar.tintColor = UINavigationBar.appearance().tintColor
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)