Concatenating two Text Views within an HStack container? - swiftui

I wonder if someone might be able to point me in the right direction with regards to getting two Text items to sit next to each other without leaving the white gap (see image below). There are lots of spacings, borders and alignments, but after playing around for 30mins I don't seem to be any closer.
The code I am using is as follows:
struct TestView: View {
var body: some View {
VStack {
HStack() {
Text("SHOT").background(Color.red)
Text("GUN").background(Color.blue)
}
Text("SHOTGUN").background(Color.green)
}
}
}

try
struct ContentView: View {
var body: some View {
VStack {
HStack(spacing: 0) {
Text("SHOT").background(Color.red)
Text("GUN").background(Color.blue)
}
Text("SHOTGUN").background(Color.green)
}
}
}

Related

SwiftUI ScrollView horizontal scroll lag on macOS

Faced with a very strange ScrollView behavior on macOS. The content freezes under the mouse during horizontal scrolling. But it is worth taking the mouse away from the window and the content scrolls normally.
This happens when I try to use a vertical scroll inside a horizontal one:
struct ScrollTestView: View {
var body: some View {
ScrollView(.horizontal) {
ScrollView(.vertical) {
VStack {
ForEach(0..<20, id: \.self) { row in
HStack {
ForEach(0..<20, id: \.self) { item in
Text("\(item)")
.font(.title)
.padding()
.background {
Color.gray
}
}
}
}
}
}
}
}
}
Yes, I know that I can use the same ScrollView for both axes simultaneously, but I need solution with two ScrollViews because of desired UX.
This solution is perfectly works on iOS, but I have this strange behavior on macOS.
Also if you swap a horizontal and a vertical ScrollView in the exact same code, everything works just fine:
struct ScrollTestView: View {
var body: some View {
ScrollView(.vertical) {
ScrollView(.horizontal) {
// ...
}
}
}
}
Looks like this is a SwiftUI bug, but I am not sure, maybe I am missing something?
Any ideas?

Does a LazyVStack remain "lazy" if it's inside a VStack?

Let's consider a list of 100 posts. According to Apple, if I layout them inside a LazyVStack:
the stack view doesn’t create items until it needs to render them
onscreen.
What if I embed that LazyVStack inside a VStack? Does it still load the views "as needed"?
struct MyView: View {
init() {
print("init...")
}
var body: some View {
Text("test")
}
}
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
LazyVStack {
ForEach.init(0..<100) { int in
MyView()
}
}
}
}
}
}
Running the above code, as we scroll we can see more MyViews are init'd (by viewing the print statements in the console), so it seems like a LazyVStack in a VStack does indeed create it's content lazily. We can see the same is true when removing the VStack as well.

Poor on-screen / scrolling performance using LazyVStack and LazyHStack with ScrollView in SwiftUI

I'm trying to draw a large scrolling SwiftUI View consisting of Rectangles that will be colour-coded. Step one is just testing 1,000s of rectangles on screen within a ScrollView, however, performance is awful. This code draws 16,000 rectangles, but the scrolling performance is really jittery and sometimes pauses a few seconds.
Any ideas on what is going on and how to fix appreciated.
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach (0..<32) { byte in
MemoryBlockView()
}
}
}
}
}
struct MemoryBlockView: View {
var body: some View {
LazyVStack(spacing: 2) {
ForEach (0..<8) { byte in
MemoryBlockRowView()
}
}
.padding(0)
}
}
struct MemoryBlockRowView: View {
var body: some View {
LazyHStack(spacing: 2) {
ForEach (0..<64) { byte in
Rectangle()
.fill(Color.blue)
.cornerRadius(2)
.padding(1)
}
}
}
}

How to allow Text to grow enough to display entire contents without truncation?

I am trying to create a SwiftUI view that represents a chat conversation in a series of vertically arranged bubbles, like in Messages.
I'm having trouble figuring out how to display very long messages. I would like to display such messages simply as very large bubbles that display all of the text. For example, like Messages does this:
The problem I run into is that the Text view, on which my bubbles are based, pretty much does its own thing. This can lead to the entire text being displayed correctly for small messages, long messages being broken into several lines but still displayed in full, other long messages being reduced to a single line with an ellipse.
Consider the following code to create a sequence of messages:
import SwiftUI
struct MessageView: View {
var body: some View {
Text("This is a very long message. Can you imagine it will ever be displayed in full on the screen? Because I can‘t. I can tell you, the one other time I wrote a message this long was when we went to the picnic and uncle Bob whipped out his cigars and I had to vent on the family WhatsApp group.")
}
}
struct ContentView: View {
var body: some View {
VStack {
ForEach(0..<100, id: \.self) { i in
MessageView()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
It results in this undesirable layout:
I have experimented with fixedSize and frame after reading several SwiftUI guides; this makes it possible to make bubbles large, but then they have a fixed size and/or won't grow when the text to display is even longer than expected.
How can I tell the MessageViews – or rather the Text views inside them – that they're free to take up as much space as they need vertically to render their text contents in full?
I found one interesting decision, using List and removing dividers:
struct ContentView: View {
init() {
UITableView.appearance().tableFooterView = UIView()
UITableView.appearance().separatorStyle = .none
}
var body: some View {
List {
ForEach(0..<50, id: \.self) { i in
VStack(alignment: .trailing, spacing: 20) {
if i%2 == 0 {
MessageView().lineLimit(nil)
} else {
MessageViewLeft()
}
}
}
}
}
}
and I made 2 structs, for demonstration:
struct MessageView: View {
var body: some View {
HStack {
Text("This is a very long message. Can you imagine it will ever be displayed in full on the screen? Because I can‘t. I can tell you, the one other time I wrote a message this long was when we went to the picnic and uncle Bob whipped out his cigars and I had to vent on the family WhatsApp group.")
Spacer(minLength: 20)
}
}
}
struct MessageViewLeft: View {
var body: some View {
HStack {
Spacer(minLength: 20)
Text("This is a very long message. Can you imagine it will ever be displayed in full on the screen? Because I can‘t. I can tell you, the one other time I wrote a message this long was when we went to the picnic and uncle Bob whipped out his cigars and I had to vent on the family WhatsApp group.")
}
}
}
the result is:
P.S. the answer should be .lineLimit(nil), but there is some bug with this in TextField. Maybe with Text this bug continues too
P.P.S. I wad hastened with the answer =(. You can set your VStack List into ScrollView:
var body: some View {
VStack {
ScrollView {
ForEach(0..<50, id: \.self) { i in
VStack(alignment: .trailing, spacing: 20) {
MessageView().padding()
}
}
}
}
}
and the result is:
Try to set your MessageView in a ScrollView.

Multiple NavigationLink in SwiftUI

Can you have multiple NavigationLinks in SwiftUI? The following only displays the first Link:
struct Test : View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("First")) {
Text("Visible")
}
NavigationLink(destination: Text("Second")) {
Text("Invisible")
}
//EDIT: Also Invisible
Text("Not rendered")
}
}
}
EDIT: Turns out everything under the first NavigationLink is not displayed
Put your views inside a VStack:
struct Test : View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("First")) {
Text("Visible")
}
NavigationLink(destination: Text("Second")) {
Text("Invisible")
}
//EDIT: Also Invisible
Text("Not rendered")
}
}
}
}
Look you can definitely have multiple NavigationLinks but here you are doing one things wrong.
The body property returns a single View but here you are trying to return more than one views, which causes the error.
To Solve this issue we put them inside another View like a VStack or a HStack, like shown above in the answer given by kontiki.