簡體   English   中英

如何修改SwiftUI中List的背景色?

[英]How do I modify the background color of a List in SwiftUI?

我正在嘗試重新創建我在 SwiftUI 中使用 UIKit 構建的 UI,但我遇到了一些小問題。

我想在這里更改List的顏色,但似乎沒有任何屬性像我預期的那樣工作。 示例代碼如下:

struct ListView: View {
    @EnvironmentObject var listData: ListData

       var body: some View {
        NavigationView {
            List(listData.items) { item in
                ListItemCell(item: item)
            }
            .content.background(Color.yellow) // not sure what content is defined as here
            .background(Image("paper-3")) // this is the entire screen 
        }
    }
}

struct ListItemCell: View {
    let item: ListItem

    var body: some View {

        NavigationButton(destination: Text(item.name)) {
            Text("\(item.name) ........................................................................................................................................................................................................")
                .background(Color.red) // not the area I'm looking for
        }.background(Color.blue) // also not the area I'm looking for
    }
}

我想改變白色區域

好的,我找到了為列表行着色的解決方案:

struct TestRow: View {

    var body: some View {
        Text("This is a row!")
        .listRowBackground(Color.green)
    }
}

然后在正文中:

List {
    TestRow()
    TestRow()
    TestRow()
}

這可以按我的預期工作,但我還沒有弄清楚如何刪除行之間的分隔線......

這會將整個列表的背景設置為綠色:

init() {
   UITableView.appearance().separatorStyle = .none
   UITableViewCell.appearance().backgroundColor = .green
   UITableView.appearance().backgroundColor = .green
}

在此處輸入圖像描述

struct ContentView: View {

    var strings = ["a", "b"]

    var body: some View {

        List {
            ForEach(strings, id: \.self) { string in
                Text(string)
            }.listRowBackground(Color.green)
        }
    }
}

您可以通過更改UITableView的外觀來做到這一點。

UITableView.appearance().backgroundColor = UIColor.clear

只需將此行放在AppdelegatedidFinishLaunchingWithOptions方法中。 代替UIColor.clear設置要在list的背景顏色中添加的任何顏色。

更改背景顏色

正如其他人所提到的,更改 UITableView 背景將影響您應用中的所有其他列表。

但是,如果您想要不同的背景顏色,您可以將默認設置為clear ,並在 swiftui 視圖中設置背景顏色,如下所示:

List {
    Text("Item 1")
    Text("Item 2")
    Text("Item 3")
}
// Ignore safe area to take up whole screen
.background(Color.purple.ignoresSafeArea())
.onAppear {
    // Set the default to clear
    UITableView.appearance().backgroundColor = .clear
}

您可能希望更早地設置 tableview 外觀,例如在SceneDelegate或根視圖中,如下所示:

// SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
      
    
    guard let windowScene = scene as? UIWindowScene else {
        print("Returning because screne does not exist")
        return
            
    }
    
    // Set here    
    UITableView.appearance().backgroundColor = .clear
    let contentView = ContentView()
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: contentView)
    self.window = window
    window.makeKeyAndVisible()
}


// Root App View
@main
struct ListBackgroundApp: App {
    
    init() {
        UITableView.appearance().backgroundColor = .clear
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

工作背景顏色變化

SwiftUI中有一個說法:listRowBackground(),但是如果你直接用List來迭代數據集合,是行不通的。

這是我的解決方法:

    List {
        // To make the background transparent, we have we use a ForEach as a wrapper
        ForEach(files) {file in
            Label(
                title: { Text(file.name ?? fileOptionalFiller).lineLimit(listRowTextLineLimit) },
                icon: { AppIcon.doc.foregroundColor(.primary) }
            )
        }
        .listRowBackground(Color.primary.colorInvert())
    }

基本上,如果您在 List 中使用 ForEach,則 listRowBackground() 可以工作。

通過使用 colorMultiply(Color:),我能夠讓整個列表更改顏色。 只需將此修飾符添加到列表視圖的末尾,然后填充會將表格推到設備邊緣。 例如:

List {...}.colorMultiply(Color.green).padding(.top)

https://www.hackingwithswift.com/quick-start/swiftui/how-to-adjust-views-by-tinting-and-desaturating-and-more

我不知道有什么聯系,但如果你用Form包裝列表,它就可以工作。

Form {
     List(viewModel.currencyList, id: \.self) { currency in
        ItemView(item: currency)
     }
      .listRowBackground(Color("Primary"))
      .background(Color("Primary"))
}

2022,MacOS 解決方案

以下代碼使所有List的背景顏色透明:

// Removes background from List in SwiftUI
extension NSTableView {
    open override func viewDidMoveToWindow() {
        super.viewDidMoveToWindow()
        
        backgroundColor = NSColor.clear
        if let esv = enclosingScrollView {
            esv.drawsBackground = false
        }
    }
}

在此處輸入圖像描述

…………

…………

…………

以下代碼使所有TextEditor的背景顏色透明:

extension NSTextView {
    open override var frame: CGRect {
        didSet {
            backgroundColor = .clear
            drawsBackground = true
        }
    }
}
struct Details: View {

    var body: some View {
        Spacer().overlay(
            List {
                Text("Hello World!").font(.title2)
                    .listRowBackground(Color.clear)
                Text("Hello World again").font(.title2)
                    .listRowBackground(Color.clear)
            }.onAppear() {
                UITableView.appearance().backgroundColor = UIColor.green
                UITableViewCell.appearance().backgroundColor = UIColor.green
            }
        )
    }
}

如果嘗試使用.listRowBackground並應用.padding使用 SwiftUI 創建浮動類型單元格,有人可能會發現這很有用

var body: some View {
    NavigationView {
        List {
            ForEach (site) { item in
                HStack {
                    Text(String(item.id))

                    VStack(alignment: .leading) {
                        Text(item.name)
                        Text(item.crop[0])
                    }

                }.listRowBackground(Color.yellow)
                      .padding(.trailing, 5)
                      .padding(.leading, 5)
                      .padding(.top, 2)
                      .padding(.bottom, 2))
            }
        }
            .navigationBarTitle(Text("Locations"))
    }
}

Islom Alimov https://stackoverflow.com/a/59970379/9439097的答案在我看來似乎是迄今為止最好的實現。

唯一的缺點:這也會更改應用程序中所有其他列表視圖的背景顏色,因此您需要手動將它們更改回來,除非您希望到處都使用相同的顏色。

這是一個示例視圖:

import SwiftUI

struct TestView1: View {
    
    init(){
        UITableView.appearance().backgroundColor = UIColor(Color.clear)
    }
    
    @State var data = ["abc", "def"]
    
    var body: some View {
        VStack {
            List {
                ForEach(data, id: \.self) {element in
                    Text("\(String(describing: element))")
                }
                .background(Color.green)
                .listRowBackground(Color.blue)
                
            }
            .background(Color.yellow)
            Spacer()
            Color.red
        }
    }
}

struct TestView1_Previews: PreviewProvider {
    static var previews: some View {
        TestView1()
    }
}

產生:

我認為listRowPlatterColor修飾符應該這樣做,但不是 Xcode 11 Beta 11M336w

var body: some View {
    List(pokemon) { pokemon in
        PokemonCell(pokemon: pokemon)
            .listRowPlatterColor(.green)
    }
}

對我來說,在 SwiftUI 中更改 List 背景的完美解決方案是:

struct SomeView: View {
    init(){
    UITableView.appearance().backgroundColor = UIColor(named: "backgroundLight")
      }
...

}

列表還不完善。

一個選項是像這樣使用它 -> List { ForEach(elements) { }}而不是List($elements)

就我而言,這是迄今為止效果最好的。 就像@FontFamily 所說,它不應該破壞任何List默認行為,如滑動。

.colorMultiply(...)

作為一個選項,您可以.colorMultiply(Color.yourColor)修飾符。

警告這不會改變顏色! 這只Multiply修改器應用於當前顏色。 請在采取任何行動之前閱讀問題,因為您可能正在尋找:“如何在 SwiftUI 中更改列表的背景顏色”,這對您不起作用。 ❄️

例子:

List (elements, id:\.self ) { element in

     Text(element)

}
.colorMultiply(Color.red) <--------- replace with your color

在此處輸入圖像描述

只需在init()方法中添加UITableView外觀背景顏色並添加列表樣式(.listStyle(SidebarListStyle()) 。不要忘記導入UIKit模塊

struct HomeScreen: View {
init() {
    UITableView.appearance().backgroundColor = .clear
}

let tempData:[TempData] = [TempData( name: "abc"),
                         TempData( name: "abc"),
                         TempData( name: "abc"),
                         TempData( name: "abc")]

var body: some View {
    ZStack {
        Image("loginBackgound")
            .resizable()
            .scaledToFill()
        List{
            ForEach(tempData){ data in
                Text(data.name)
            }
        }
        .listStyle(SidebarListStyle())
        
    }
    .ignoresSafeArea(edges: .all)
}
}

如果要避免全局設置所有表視圖的外觀,可以將UITableView.appearance(whenContainedInInstancesOf:)UIHostingController結合使用。 感謝DanSkeel您在上面留下的評論指出了這一點。 這就是我使用它的方式:

public class ClearTableViewHostingController<Content>: UIHostingController<Content> where Content: View {
    public override func viewDidLoad() {
        UITableView.appearance(whenContainedInInstancesOf: [ClearTableViewHostingController<Content>.self]).backgroundColor = .clear
    }
}

您可以像這樣使用ClearTableViewHostingController

let view = MyListView()
let viewController = ClearTableViewHostingController(coder: coder, rootView: view)

然后在您的視圖中,您可以像這樣設置列表背景顏色:

List {
    Text("Hello World")
}
.background(Color.gray)

使擴展列表如下:

extension List{
@available(iOS 14, *)
func backgroundList(_ color: Color = .clear) -> some View{
    UITableView.appearance().backgroundColor = UIColor(color)
    return self
}

}

使用UITableView.appearance().backgroundColor不是一個好主意,因為它會更改所有表格的背景顏色。 我在您在iOS 14, 15中選擇的確切表格上找到了一個可行的顏色更改解決方案。

我們將使用需要在列表中應用的修飾符來更改顏色

extension View {
    
    func backgroundTableModifier(_ color: UIColor? = nil) -> some View {
        self.modifier(BackgroundTableModifier(color: color))
    }

}

我們的任務是找到 UITableView,然后更改顏色。

private struct BackgroundTableModifier: ViewModifier {
    
    private let color: UIColor?
    @State private var tableView: UITableView?
    
    init(color: UIColor?) {
        self.color = color
    }
    
    public func body(content: Content) -> some View {
        if tableView?.backgroundColor != color {
            content
                .overlay(BackgroundTableViewRepresentable(tableBlock: { tableView in
                    tableView.backgroundColor = color
                    self.tableView = tableView
                }))
        } else {
            content
        }
    }
}

private struct BackgroundTableViewRepresentable: UIViewRepresentable {
    
    var tableBlock: (UITableView) -> ()
    
    func makeUIView(context: Context) -> BackgroundTableView  {
        let view = BackgroundTableView(tableBlock: tableBlock)
        return view
    }
    
    func updateUIView(_ uiView: BackgroundTableView, context: Context) {}
}

class BackgroundTableView: UIView {
    
    var tableBlock: (UITableView) -> ()
    
    init(tableBlock: @escaping (UITableView) -> ()) {
        self.tableBlock = tableBlock
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if let tableView = findTableView(in: self) {
            tableBlock(tableView)
        }
    }
    
    private func findTableView(in view: UIView) -> UITableView? {
        if let tableView = view as? UITableView {
            return tableView
        }
        
        if let superView = view.superview {
            return findTableView(in: superView)
        }
        
        return nil
    }
    
}

為了找到 UITableView,修飾符必須在 List 內。 自然,您需要確保只調用一次修飾符,而不需要將其應用於每一行。 這是一個使用示例

List {
   rows()
     .backgroundTableModifier(.clear)
}

func rows() -> some View {
    ForEach(0..<10, id: \.self) { index in
        Row()
    }
}

我啟發了一些用於配置每頁 NavigationView 導航欄樣式的配置器,並編寫了一些簡單的 UITableView 每頁配置器不使用 UITableView.appearance() 全局方法

   import SwiftUI

    struct TableViewConfigurator: UIViewControllerRepresentable {

        var configure: (UITableView) -> Void = { _ in }

        func makeUIViewController(context: UIViewControllerRepresentableContext<TableViewConfigurator>) -> UIViewController {

            UIViewController()
        }

        func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TableViewConfigurator>) {

            let tableViews = uiViewController.navigationController?.topViewController?.view.subviews(ofType: UITableView.self) ?? [UITableView]()

            for tableView in tableViews {
                self.configure(tableView)
            }
        }
    }

然后需要 UIView 擴展來查找所有 UITableViews

extension UIView {
    func subviews<T:UIView>(ofType WhatType:T.Type) -> [T] {
        var result = self.subviews.compactMap {$0 as? T}
        for sub in self.subviews {
            result.append(contentsOf: sub.subviews(ofType:WhatType))
        }
        return result
    }
}

最后的用法是:

List {

}.background(TableViewConfigurator {
    $0.backgroundColor = .red
})

也許應該改進一件事,即使用 navigationController?.topViewController 使其即使在視圖控制器層次結構中沒有 navigationController 也能工作

如果有人來這里尋找 iPhone X/11 上橫向背景而不是全寬的解決方案,請嘗試:

.listRowBackground(Color("backgroundColour").edgesIgnoringSafeArea(.all))

您可以使用 Github 中的introspect庫為基礎表視圖設置背景顏色,如下所示:

List { ... } .introspectTableView { tableView in
                tableView.backgroundColor = .yellow
            }

由於某種原因顏色更改不起作用,您可以嘗試將 .listStyle 更改為 .plain

代碼:

struct ContentView: View {
var body: some View {
    VStack {
        Text("Test")

        List {
            ForEach(1 ..< 4) { items in
                Text(String(items))
            }
        }
        .listStyle(.plain)
    }
}

iOS 16 提供了一個修改器來自定義 List 背景顏色。

View.scrollContentBackground指定可滾動視圖內容的背景樣式,包括列表。

List {
    Text("One")
    Text("Two")
}
.scrollContentBackground(Color.red)

您可以通過.hiddenColor.clear隱藏背景 - 如果這樣做,列表的背景將可見。

List {
    Text("One")
    Text("Two")
}
.background(Image("MyImage"))
.scrollContentBackground(.hidden)

您可能還想自定義列表行的背景 - 單個單元格 - 和分隔符。 這可以這樣做:

List {
    Section("Header") {
        Text("One")
        Text("Two")
            .listRowBackground(Color.red)
    }
    .listRowBackground(Color.clear)
    .listRowSeparator(.hidden)
}
.scrollContentBackground(.hidden)

在 iOS 16中,我們通過scrollcontentbackground修飾符獲得了一種本地方式來執行此操作。

您可以通過將顏色 ( ShapeStyle ) 設置為scrollcontentbackground更改顏色

List {
    Text("Item 1")
    Text("Item 2")
    Text("Item 3")
}
.scrollContentBackground(Color.pink)

或者您可以隱藏背景.scrollContentBackground(.hidden)並使用.backgroud修飾符設置自定義背景。

List {
    Text("Item 1")
    Text("Item 2")
    Text("Item 3")
}
.background {
    Image("ventura")

}
.scrollContentBackground(.hidden)

由於系統背景,更改背景對我不起作用。 我需要隱藏它。

List(examples) { example in
        ExampleRow(example: example)
    }.background(Color.white.edgesIgnoringSafeArea(.all))
        .scrollContentBackground(.hidden)

Xcode 版本 12.4

Background屬性對我有用,但強制使用Opacity 沒有不透明度是行不通的。

List {
            ForEach(data, id: \.id) { (item) in
                ListRow(item)
                    .environmentObject(self.data)
            }
        }
        .background(Color.black)
        .opacity(0.5)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM