英文:
SwiftUI glitch / bug - status bar not showing when using AVPlayer inside LazyVStack and ScrollView
问题
我正在尝试弄清楚为什么在使用AVPlayer在LazyVStack和ScrollView内部时,状态栏不显示很长时间,所以我制作了一个最小的示例,只需要复制并粘贴:
import SwiftUI
import AVKit
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
struct ContentView: View {
@State var toolbarHeight: CGFloat = 64
@State var freeScreenHeight: CGFloat = 0
@State var toolbarOffset: CGFloat = 0
@State var lastScrollOffset: CGFloat = 0
@State var startChecking: Bool = false
@State var player = AVPlayer()
var videoUrl: String = "someExternal1:1ratioVideo"
init() {
UIScrollView.appearance().bounces = false
}
var body: some View {
ZStack(alignment: .leading){
VStack{
HStack(spacing: 10){
Text("toolbar")
Spacer()
}
.padding(.horizontal, 12.0)
.frame(height: toolbarHeight)
.background(Color.green)
.padding(.bottom, toolbarOffset)
.offset(y: toolbarOffset)
.zIndex(2)
Spacer()
}
.clipped()
.zIndex(2)
ScrollView(.vertical, showsIndicators: false){
LazyVStack(spacing: 0){
VStack{
}
.frame(width: round(UIScreen.main.bounds.width / 1.5), height: toolbarHeight + 8)
ForEach(1..<5) { index in
VideoPlayer(player: player)
.onAppear{
startChecking = true
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width)
.padding(.bottom, 10)
}
}
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self,
value: -$0.frame(in: .named("scroll")).origin.y)
})
.onPreferenceChange(ViewOffsetKey.self) {
if(startChecking){
if($0 > lastScrollOffset){
let howMuch = $0 - lastScrollOffset
if((toolbarOffset - howMuch) < -toolbarHeight){
toolbarOffset = -toolbarHeight
}else{
toolbarOffset -= howMuch
}
}else{
let howMuch = lastScrollOffset - $0
if((toolbarOffset + howMuch) > 0){
toolbarOffset = 0
}else{
toolbarOffset += howMuch
}
}
}
lastScrollOffset = $0
}
}
.frame(height: freeScreenHeight)
}
.onAppear() {
player = AVPlayer(url: URL(string: videoUrl)!)
}
.preferredColorScheme(.dark)
.background(
GeometryReader { proxy in
Color.clear
.onAppear {
freeScreenHeight = UIScreen.main.bounds.height - proxy.safeAreaInsets.top - proxy.safeAreaInsets.bottom
}
}
)
.clipped()
}
}
这个 bug 的可能原因是什么?
英文:
I'm trying to figure out why the status bar doesn't show when using AVPlayer inside LazyVStack and ScrollView for many hours now so I made a minimal example that just needs to be copied and pasted:
import SwiftUI
import AVKit
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
struct ContentView: View {
@State var toolbarHeight: CGFloat = 64
@State var freeScreenHeight: CGFloat = 0
@State var toolbarOffset: CGFloat = 0
@State var lastScrollOffset: CGFloat = 0
@State var startChecking: Bool = false
@State var player = AVPlayer()
var videoUrl: String = "someExternal1:1ratioVideo"
init() {
UIScrollView.appearance().bounces = false
}
var body: some View {
ZStack(alignment: .leading){
VStack{
HStack(spacing: 10){
Text("toolbar")
Spacer()
}
.padding(.horizontal, 12.0)
.frame(height: toolbarHeight)
.background(Color.green)
.padding(.bottom, toolbarOffset)
.offset(y: toolbarOffset)
.zIndex(2)
Spacer()
}
.clipped()
.zIndex(2)
ScrollView(.vertical, showsIndicators: false){
LazyVStack(spacing: 0){
VStack{
}
.frame(width: round(UIScreen.main.bounds.width / 1.5), height: toolbarHeight + 8)
ForEach(1..<5) { index in
VideoPlayer(player: player)
.onAppear{
startChecking = true
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width)
.padding(.bottom, 10)
}
}
.background(GeometryReader {
Color.clear.preference(key: ViewOffsetKey.self,
value: -$0.frame(in: .named("scroll")).origin.y)
})
.onPreferenceChange(ViewOffsetKey.self) {
if(startChecking){
if($0 > lastScrollOffset){
let howMuch = $0 - lastScrollOffset
if((toolbarOffset - howMuch) < -toolbarHeight){
toolbarOffset = -toolbarHeight
}else{
toolbarOffset -= howMuch
}
}else{
let howMuch = lastScrollOffset - $0
if((toolbarOffset + howMuch) > 0){
toolbarOffset = 0
}else{
toolbarOffset += howMuch
}
}
}
lastScrollOffset = $0
}
}
.frame(height: freeScreenHeight)
}
.onAppear() {
player = AVPlayer(url: URL(string: videoUrl)!)
}
.preferredColorScheme(.dark)
.background(
GeometryReader { proxy in
Color.clear
.onAppear {
freeScreenHeight = UIScreen.main.bounds.height - proxy.safeAreaInsets.top - proxy.safeAreaInsets.bottom
}
}
)
.clipped()
}
}
What could be the reason for this bug?
答案1
得分: 1
如果您需要快速修复,可以使用.statusBar(hidden:)
修饰符来显示状态栏。
在您的ZStack
底部添加以下代码行:
} // ZStack 结束位置
.statusBar(hidden: false) // <---- 这里 *****
.onAppear() {
player = AVPlayer(url: URL(string: videoUrl)!)
}
.preferredColorScheme(.dark)
.background(
GeometryReader { proxy in ........
英文:
If you need a quick fix, you can use the .statusBar(hidden:)
modifier to get the status bar to display.
At the bottom of your ZStack
add the following line of code:
} // ZStack ends here
.statusBar(hidden: false) // <---- here *****
.onAppear() {
player = AVPlayer(url: URL(string: videoUrl)!)
}
.preferredColorScheme(.dark)
.background(
GeometryReader { proxy in ........
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论