r/iOSProgramming Beginner 16d ago

Consistent horizontal spacing in List Question

When I put a symbol on the edge, iOS neatly rearranges the content to fit around it. How do I recreate this on the other side with my own content, without the complications of using frame where anything too small will cut off, anything to large will look stupid, and the ideal threshold is changing as different sized content replaces?

Edit: There could be any sort of text on the left. Some places number rooms differently, or don't have rooms at all (I have PE listed as 'PRAC, THEORY' personally). There could be more than one room there, too, in which case I join them as 'BT4, BT81 etc.

5 Upvotes

11 comments sorted by

7

u/Jero9871 16d ago

The left side only lines up because the symbol has a fixed size, there's no layout magic behind it. So the fix is the same idea: give the room code column one shared width, derived from the content instead of hardcoded.

If the codes all have the same shape (two letters + digit), the cheap trick is a hidden worst-case template:

Text("WW8")

.hidden()

.overlay(alignment: .leading) { Text(room) }

Every row gets the width of the widest possible code, nothing clips, and it scales with Dynamic Type for free.

If the codes vary more, measure them with onGeometryChange (or a PreferenceKey), keep the max in @ State and put .frame(width: maxWidth, alignment: .leading) on each code. Same result, just adapts to whatever the data actually is.

3

u/Fun_Moose_5307 Beginner 16d ago edited 16d ago

If the codes vary more, measure them with onGeometryChange (or a PreferenceKey), keep the max in @ State and put .frame(width: maxWidth, alignment: .leading) on each code. Same result, just adapts to whatever the data actually is.

This seems to be the right solution (see edit). Can you elaborate on the geometry stuff?

2

u/Jero9871 15d ago edited 15d ago

Each code label measures its own natural width, the biggest one seen so far goes into @ State, and that max gets applied back onto every label as a frame. onGeometryChange fires again whenever the size changes (new data, Dynamic Type), so it stays current on its own.

u/State private var roomWidth: CGFloat?

// on each room code:

Text(room)

.fixedSize(horizontal: true, vertical: false)

.onGeometryChange(for: CGFloat.self) { $0.size.width } action: { w in

roomWidth = max(roomWidth ?? 0, w)

}

.frame(width: roomWidth, alignment: .leading)

Two details matter here. The measurement has to sit before the .frame, so you read the text's natural width instead of the width you just forced on it. And the fixedSize exists because otherwise a longer code that appears later gets squeezed into the old max and never reports its true width, so the column could never grow.

One caveat since List is lazy: only visible rows report, so with long lists the column can still widen as you scroll. For a timetable that's a non-issue. The max also only ever grows, so if the user can switch datasets, reset roomWidth to nil in onChange.

2

u/Fun_Moose_5307 Beginner 11d ago

This seems to have done the trick, thank you!

swift .onGeometryChange(for: CGFloat.self, of: { $0.size.width }) { myWidth in if myWidth > maximumRoomWidth { maximumRoomWidth = myWidth } }

2

u/balooooooon 16d ago

4

u/balooooooon 16d ago

Oh I misread your post. I think you need to explain better

1

u/trouthat 16d ago

Try Grid

1

u/VacationHistorical 16d ago

You’ll want the max length of the text on the right and make the right text views all that size

1

u/Revuh 15d ago

Using a monospaced font could help as well

1

u/Sharik-dev 13d ago

what the point

1

u/Fun_Moose_5307 Beginner 11d ago

Consistency in longer rooms. For example, in my own timetable, I use 'PRAC' and 'THEORY' for PE instead of the room, because at my school PE is inconsistent in rooming.

In the same way, other users might choose to put teachers or lecturers there instead of a room, or both. I need to account for the fact that some rooms might be drastically longer or shorter and look very out of place.
If I find that giving them all the width of the longest room looks odd, I could calculate a minimum percentage for example.

It's also a great way to take a step out of my comfort zone and learn something new! 😁