Layout TVOS上SwiftUI的布局问题

Layout TVOS上SwiftUI的布局问题,layout,swiftui,tvos,Layout,Swiftui,Tvos,我在TVOS中使用SwiftUI有一个可行的UI,但我不知道如何使其正确布局 目标: 屏幕为全屏,未插入安全区域 相册图像为方形,保留纵横比,从上到下填充 相册和艺术家文本舒适地布置在相册艺术附近 如果有帮助,以下是相关的帮助程序和数据源方法: DataStore()类具有以下方法: import SwiftUI import Combine class CurrentRoom { var artist: String? var title: String? var a

我在TVOS中使用SwiftUI有一个可行的UI,但我不知道如何使其正确布局

目标:

  • 屏幕为全屏,未插入安全区域
  • 相册图像为方形,保留纵横比,从上到下填充
  • 相册和艺术家文本舒适地布置在相册艺术附近
  • 如果有帮助,以下是相关的帮助程序和数据源方法:

    DataStore()类具有以下方法:

    import SwiftUI
    import Combine
    
    class CurrentRoom {
        var artist: String?
        var title: String?
        var album: String?
        var albumArtURI: String?
        var absoluteAlbumArtURI: String?
        var albumImage: UIImage?
    }
    
    class DataStore: ObservableObject {
        @Published var currentRoom: CurrentRoom = CurrentRoom()
            
        init() {
            getCurrentRoom()
        }
        
        func getCurrentRoom() {
            currentRoom.artist = "Eilen Jewell"
            currentRoom.album = "Sundown over Ghost Town"
            currentRoom.title = "Half-Broke Horse"
            currentRoom.absoluteAlbumArtURI = "https://images-na.ssl-images-amazon.com/images/I/71mkKfTQD0L._SX425_.jpg"
            currentRoom.albumImage = Api().getImageDataFromURI(UrlAsString: currentRoom.absoluteAlbumArtURI)
        }
    }
    
    struct DataStore_Previews: PreviewProvider {
        static var previews: some View {
            /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
        }
    }
    
    最后:

    class Api {
        func getImageDataFromURI(UrlAsString: String?) -> UIImage? {
            if let URI = UrlAsString {
                if URI.starts(with: "http") {
                    if let url = URL(string: URI) {
                        let data = try? Data(contentsOf: url)
    
                        if let imageData = data {
                            return UIImage(data: imageData)
                        }
                    }
                }
            }
            return nil
        }
    }
    

    目标:

    您可以选择Asperis answer,或者,如果ContentMode.Fit对您很重要(因为您不想剪裁图像),只需删除图像上帧修改器的宽度部分,然后在VStack后面添加一个间隔符,这将消耗其余部分:

    struct ContentView: View {
    @ObservedObject var ds = DataStore()
    
    var body: some View {
        HStack(alignment: .top) {
                if (ds.currentRoom.albumImage != nil) {
                    Image(uiImage: ds.currentRoom.albumImage!)
                        .resizable()
                        .aspectRatio(contentMode: ContentMode.fit)
                        .frame(minHeight: 0, maxHeight: .infinity)
                        .background(Color.black)
                    
                }
                VStack(alignment: .leading, spacing: 8) {
                    Text(ds.currentRoom.artist ?? "?")
                        .font(.system(.title, design: .default))
                        .bold()
                        .foregroundColor(Color.gray)
                        .padding(.top, 100)
                    Text(ds.currentRoom.title ?? "?")
                        .font(.system(.headline, design: .default))
                        .foregroundColor(Color.gray)
                        .padding(.bottom, 100)
                    Button(action: { print ("pressed!" )} ) {
                        Image(systemName: "playpause")
                            .font(.system(.title, design: .default))
                            .foregroundColor(Color.gray)
                            .padding(30)
                            .overlay(
                                RoundedRectangle(cornerRadius: 16)
                                    .stroke(Color.green, lineWidth: 4)
                        )
                    }
                }
                .padding(.leading, 10)
            Spacer()
            }
        .padding(20)
        .background(Color.black)
        .edgesIgnoringSafeArea(.all)
        }
    }
    
    这将产生以下图像:

    您肯定需要ContentMode.fill,否则,即使图像的边框会按照您的需要对齐,但由于纵横比不合适,图像本身在“逐帧拟合”中可能会在水平或垂直方向上留下空白。
    struct ContentView: View {
    @ObservedObject var ds = DataStore()
    
    var body: some View {
        HStack(alignment: .top) {
                if (ds.currentRoom.albumImage != nil) {
                    Image(uiImage: ds.currentRoom.albumImage!)
                        .resizable()
                        .aspectRatio(contentMode: ContentMode.fit)
                        .frame(minHeight: 0, maxHeight: .infinity)
                        .background(Color.black)
                    
                }
                VStack(alignment: .leading, spacing: 8) {
                    Text(ds.currentRoom.artist ?? "?")
                        .font(.system(.title, design: .default))
                        .bold()
                        .foregroundColor(Color.gray)
                        .padding(.top, 100)
                    Text(ds.currentRoom.title ?? "?")
                        .font(.system(.headline, design: .default))
                        .foregroundColor(Color.gray)
                        .padding(.bottom, 100)
                    Button(action: { print ("pressed!" )} ) {
                        Image(systemName: "playpause")
                            .font(.system(.title, design: .default))
                            .foregroundColor(Color.gray)
                            .padding(30)
                            .overlay(
                                RoundedRectangle(cornerRadius: 16)
                                    .stroke(Color.green, lineWidth: 4)
                        )
                    }
                }
                .padding(.leading, 10)
            Spacer()
            }
        .padding(20)
        .background(Color.black)
        .edgesIgnoringSafeArea(.all)
        }
    }