macosswiftuiswiftui-text

Text doesn't wrap to the next line SwiftUI


I am a beginner programmer and doing some SwiftUI. This is a Task Management/todo list app I'm working on for macOS. Each task in the task list relies on a TaskView to display itself, and this TaskView is made up of a HStack with various elements. The text/textfield part does not wrap to the next line, and instead is sort of cut off by dots whenever I drag the window borders in (this is the problem which I want to fix)

The code:

var body: some View {
        HStack {
            Image(systemName: task.isCompleted ? "checkmark.square.fill" : "stop")
                .onTapGesture {
                    task.isCompleted.toggle()
                }

            VStack(alignment: .leading) {
                if isStrikethrough {
                    Text(task.title)
                        .fixedSize(horizontal: false, vertical: true)
                        .strikethrough(task.isCompleted)
                        .onTapGesture {
                            isStrikethrough.toggle()
                        }
                } else {
                    TextField("New Task", text: $task.title)
                        .fixedSize(horizontal: false, vertical: true)
                        .textFieldStyle(.plain)
                        .strikethrough(task.isCompleted)
                }
            }

            Spacer()
            Text("\(dueDateFormatted)")
                .foregroundColor(.gray)
                .font(.caption)

            Button(action: {
                // Action for showing popover for editing due date
                isEditingDueDate.toggle()
            }) {
                Image(systemName: "calendar")
            }
            .popover(isPresented: $isEditingDueDate) {
                CalendarPopover(task: $task, isEditingDueDate: $isEditingDueDate)
                    .frame(width: 250, height: 50) // Set popover size as needed
            }
            .buttonStyle(PlainButtonStyle())
        }
    }

    private var dueDateFormatted: String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .short
        dateFormatter.timeStyle = .short
        return dateFormatter.string(from: task.dueDate)
    }
}

The isStrikethrough conditional checks if isStrikethrough is on to enable a strikethrough effect on tasks that are checked, or have an isCompleted feature set to true. I separated it with the conditional as the strikethrough effect doesn't work on textfields, but I need them for editing, so I made it so that a task is text when not being edited/renamed and a textfield when it is.

The above code already includes some modifications I added in hopes of solving the problem, such as .fixedSize(horizontal: false, vertical: true) and wrapping the text in a VStack as I thought that the HStack could be stopping it from wrapping to the next line.

To clarify, this is what I want to happen when the window borders are dragged in: working wrap to next line, using StaticTaskListView, which doesn't include the elements shown in the above TaskView code

And yet, something like this happens instead: not working, using TaskView which includes other elements in the HStack including the text that displays the current due date of the task and a calendar button for changing this due date.

The first image depicts the correct text wrapping, which happens in a separate view called the StaticTaskListView, where the calendar button and due date text are excluded from the HStack. This StaticTaskListView looks like this:

var body: some View {
        List {
            ForEach(tasks) { task in
                VStack(alignment: .leading) {
                    HStack {
                        Image(systemName: task.isCompleted ? "checkmark.square.fill" : "stop")
                            .onTapGesture {
                                toggleAction(task)
                            }
                        Text(task.title)
                            .strikethrough(task.isCompleted && isStrikethrough)
                    }
                }
            }
            .onDelete { indexSet in
                deleteAction(indexSet)
            }
        }

In conclusion, I want the text to wrap correctly, as it does in the StaticTaskListView provided above and the first image, while maintaining the extra elements of the HStack in the first code I provided, which is part of the TaskView, depicted in the second image.

This is my first ever post, and I am a beginner programmer. I am sorry if this post made anything unclear or is too long and hard to understand, or if I missed out on any StackOverflow etiquette. Any replies would be very helpful and greatly appreciated.


Solution

  • I think it's the TextField that is not wrapping.

    To make it scrollable (multi-line), just add an axis parameter:

    TextField("New Task", text: $task.title, axis: .vertical)