0

I have Views embedded in a list, one View per List item but for some reason, the View only takes up a small leading part of the list's row, rather than filling the full line. The embedded View is fully expanded in the preview of the View so I'm unsure why this is happening.

List View

import SwiftUI

struct AnnouncementsView: View{
    @Binding var announcements: [Announcement]
    @State var displayedMessage: String = ""
    @State var isDisplayingMessage: Bool = false
    
    static let sectionDateFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/YYYY"
        return formatter
    }()
    var body: some View{
        //NavigationView{
        VStack{
            List($announcements){$announcement in
                AnnouncementView(announcement: $announcement)
            }
            Spacer()
        }
    }
}

list view preview

List Item View

struct AnnouncementView: View{
    @Binding var announcement: Announcement
    @State private var sheetIsShowing: Bool = false
    static let sectionDateFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/YYYY"
        return formatter
    }()
    var body: some View{
        HStack{
            Button(action: {
                sheetIsShowing = true
            }){
                if (!announcement.read){
                    Image(systemName: "exclamationmark.circle.fill")
                        .foregroundColor(.red)
                }
                Text(announcement.message)
                    .lineLimit(1)
                    .truncationMode(.tail)
                    .foregroundColor(.black)
                Spacer()
                Text("\(announcement.timestamp, formatter: Self.sectionDateFormat)")
                    .disabled(true)
            }
        }
        .padding()
        .sheet(isPresented:$sheetIsShowing){
            NavigationView{
                DetailedAnnouncementView(announcement: $announcement)
                    .navigationTitle(Text("\(announcement.timestamp, formatter: Self.sectionDateFormat)"))
                    .toolbar{
                        ToolbarItem(placement: .navigationBarLeading){
                            Button(action: {
                                announcement.read = true
                                sheetIsShowing = false
                            }){
                                Text("Mark as Read")
                            }
                        }
                        ToolbarItem(placement: .navigationBarTrailing){
                            Button(action: {
                                sheetIsShowing = false
                                announcement.read = false
                            }){
                                Text("Mark as Unread")
                            }
                        }
                    }
            }
        }
    }
}

list item view preview

I'm probably missing something really basic but any help is much appreciated.

Thanks.

Fahim Parkar
  • 30,974
  • 45
  • 160
  • 276
SamuraiMelon
  • 297
  • 3
  • 11
  • Does this answer your question https://stackoverflow.com/a/63986460/12299030? – Asperi May 09 '22 at 09:04
  • @Asperi Unfortunately not, thank you anyway. – SamuraiMelon May 09 '22 at 09:08
  • Consider combining above with https://stackoverflow.com/a/60910124/12299030. – Asperi May 09 '22 at 09:18
  • @Asperi Unfortunately this doesn't fix it either, I'm happy with the list style, that the list box is inset, its just that the View inside the list box refuses to go across the full line, and instead middle aligns to the leading edge over multiple lines. – SamuraiMelon May 09 '22 at 09:23

1 Answers1

2

So it seems that SwiftUI renders Button's content as if it was inside an HStack by default, in case no Stack was provided.

However, when using the Button inside a List, this default behaviour changes to defaulting as if it was a VStack. (Note that it only happens when used inside a List. When used inside LazyVStack, ScrollView, ForEach... the default HStack is maintained).

So, in order to make sure the Button's content is always rendered horizontally, specify it by explicitly nesting its content inside an HStack instead of relying on Button's "default" behaviour (as it does not seem to be consistent right now)

So, change:

Button(action: ...) {
    //content
}

To:

Button(action: ...) {
    HStack {
        //content
    }
}
Sarquella
  • 1,129
  • 9
  • 26