简体   繁体   中英

How to create spacing between items in a SwiftUI List view?

I can't seem to find a way to create spacing between List items. Maybe I shouldn't put in a list in the first place?

在此处输入图像描述

What do you think?

This the code that generates the view:

struct ContentView: View {
    
    @ObservedObject var ratesVM = RatesViewModel()
    
    init() {
        UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        UITableView.appearance().backgroundColor = UIColor.init(named: "midnight blue")
        UITableViewCell.appearance().backgroundColor = .green
        UITableView.appearance().separatorStyle = .none
    }
    
    var body: some View {
        
        NavigationView {
            List (ratesVM.ratesList, id: \.self) { rate in
                    Image(systemName: "plus")
                    
                    Button(action: {print("pressed")}) {
                        Text(rate.hebrewCurrencyName)
                }
            }
            .navigationBarTitle("המרות מטבע")
            .navigationBarItems(leading:
                Button(action: {
                    print("button pressed")
                    self.ratesVM.callService()
                }) {
                    Image(systemName: "plus")
                        .foregroundColor(Color.orange)})
        }.environment(\.layoutDirection, .rightToLeft)
    }
}

You can define the minimum list row height to be bigger so you'll have more separation between rows.

List (ratesVM.ratesList, id: \.self) { rate in
       Image(systemName: "plus")
       Button(action: {print("pressed")}) {
                    Text(rate.hebrewCurrencyName)
       }
}.environment(\.defaultMinListRowHeight, 50) //minimum row height

Alternatively you can build your row as a HStack and specify a frame height.

List (ratesVM.ratesList, id: \.self) { rate in
    HStack {
       Image(systemName: "plus")
       Button(action: {print("pressed")}) {
          Text(rate.hebrewCurrencyName)
       }
    }.frame(height: 50) //your row height 
}.environment(\.defaultMinListRowHeight, 20) 

Or as a VStack and and use Spacers

List (ratesVM.ratesList, id: \.self) { rate in
    VStack{
        Spacer()
        HStack {
           Image(systemName: "plus")
           Button(action: {print("pressed")}) {
              Text(rate.hebrewCurrencyName)
           }
        }
        Spacer()
    }.frame(height: 50)
}.environment(\.defaultMinListRowHeight, 20) 

SwiftUI lets us set individual padding around views using the padding() modifier. If you use this with no parameters you'll get system-default padding on all sides, like this:

VStack {
    Text("SwiftUI")
        .padding()
    Text("rocks")
}

But you can also customize how much padding to apply and where. So, you might want to apply system padding to only one side:

Text("SwiftUI")
    .padding(.bottom)

Or you might want to control how much padding is applied to all sides:

Text("SwiftUI")
    .padding(100)

Or you can combine the two to add a specific amount of padding to one side of the view:

Text("SwiftUI")
    .padding(.bottom, 100)

so you can do

Text(rate.hebrewCurrencyName)
      .padding(50)

The SwiftUI way

You can achieve it by removing the list row separators .listRowSeparator(.hidden) and setting the list row background to an InsettableShape .listRowBackground() defining top and bottom EdgeInsets padding. Btw, don't forget to set the .listStyle(.plain) to .plain .

You can find a better implementation on this dev post SwiftUI List Card View .

//
//  ContentView.swift
//  My App
//
//  Created by Kolmar Kafran on 25/08/22.
//  https://www.linkedin.com/in/kolmar-kafran/
//

import SwiftUI

struct ContentView: View {
    @State private var someList = [0, 1, 2, 3, 4]
    
    var body: some View {
        List {
            ForEach(someList, id: \.self) { n in
                Text("\(n)")
                    .foregroundColor(.white)
                    .listRowBackground(
                        RoundedRectangle(cornerRadius: 5)
                            .background(.clear)
                            .foregroundColor(.blue)
                            .padding(
                                EdgeInsets(
                                    top: 2,
                                    leading: 10,
                                    bottom: 2,
                                    trailing: 10
                                )
                            )
                    )
                    .listRowSeparator(.hidden)
            }
            .onDelete { idx in
                someList.remove(atOffsets: idx)
            }
        }
        .listStyle(.plain)
    }
}

padding didn't work since it only increased the size of the item/cell and not the spacing between, but .environment(.defaultMinListRowHeight, 20) seemed to work

I also implemented a custom view for the button styling to adjust the frame and "pressable area" of the button relative to the item/cell.

struct MyButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(.black)
            .opacity(configuration.isPressed ? 0.5 : 1.0)
            .frame(width: 350, height: 50, alignment: Alignment.center)
            .background(Color.orange)
    }
}

struct ContentView: View {

    @ObservedObject var ratesVM = RatesViewModel()

    init() {
        UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        UITableView.appearance().backgroundColor = UIColor.init(named: "midnight blue")
        UITableViewCell.appearance().backgroundColor = .clear
        UITableView.appearance().separatorStyle = .none
    }

    var body: some View {

        NavigationView {
            List (ratesVM.ratesList, id: \.self) { rate in
                Button(action: {print("pressed")}) {
                    Text(rate.hebrewCurrencyName)
                }.buttonStyle(MyButtonStyle())
            }
            .navigationBarTitle("המרות מטבע")
            .navigationBarItems(leading:
                Button(action: {
                    print("button pressed")
                    self.ratesVM.callService()
                }) {
                    Image(systemName: "plus")
                        .foregroundColor(Color.orange)})
        }.environment(\.layoutDirection, .rightToLeft)
            .environment(\.defaultMinListRowHeight, 150)
    }
}

在此处输入图片说明

A quick solution here is to just set the corresponding listStyle to SidebarListStyle . For instance:

List {
    Text("First row")
    Text("Second row")
    Text("Third row")
}
.listStyle(SidebarListStyle())

But please note that on macOS and iOS, the sidebar list style also displays disclosure indicators in the section headers that allow the user to collapse and expand sections.

Another quick alternative would be to use theDivider() helper view instead (ie, a visual element that can be used to separate other content):

List {
    Text("First row")
    Divider()
    Text("Second row")
    Divider()
    Text("Third row")
}

Both solutions won't allow direct control of the vertical spacing but at least provides a more spacious layout alternative.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM