34

I want to add text (eg. Hi) in a shape (eg. Square) in SwiftUI and make them act as a single object.

It looks like there's no direct way to add text in shape in SwiftUI.

grg
  • 5,023
  • 3
  • 34
  • 50
AtharvSalokhe
  • 463
  • 1
  • 4
  • 13
  • I started with the solutions below, but ended up going with the view extension in this [SO answer](https://stackoverflow.com/a/58606176/9586164) because it provided a little more flexibility in the corners you want rounded. – Thomas Burke Dec 27 '21 at 20:06

6 Answers6

37

Here is what I consider to be a more comprehensive answer. This will work as of Xcode 11.5:

Text(question)
    .fixedSize(horizontal: false, vertical: true)
    .multilineTextAlignment(.center)
    .padding()
    .frame(width: 300, height: 200)
    .background(Rectangle().fill(Color.white).shadow(radius: 3))

Notes:

  • fixedSize() will let the text wrap (since .lineLimit(nil) no longer is working). You can omit it if you simply want one line of text with ellipsis
  • multilineTextAlignment() allows you to center or align the text in any way
  • padding() gives the text more space to breathe within the Rectangle()
  • frame() sets the width and height of the Text() and hence, the Rectangle(), since it is the background of the Text()
  • background() sets the shape of the Text()'s background. I have added a fill color and a drop shadow here as well

The end result of this example is the text looks to appear within a cue card like shape!

Gene Loparco
  • 2,157
  • 23
  • 23
  • I don't like this solution we shouldn't need to set the frame height/width... it should work with hugging and let the amount o text to stretch the view when needed – João Serra Jun 05 '23 at 17:52
  • The original question stated "I want to add text (eg. Hi) in a shape (eg. Square)". You're not going to get a consistent shape unless you specify what that shape looks like, hence the use of frame() in this case. – Gene Loparco Jun 13 '23 at 16:47
  • Yes, I understand that, but in my opinion, what matters is not the height and width itself but the relation between height and width of 1:1 . This was previously achieved easily with a constraint height = width When working with different sizes/devices simultaneously this may cause some issues. – João Serra Jun 22 '23 at 11:49
  • Well by that logic, if you just specify a relationship between height and width without specifying one of the aspects relative to the screen and pixel density, you will also have issues. If you take what is written as a starting point (which answers the question), you are free to enhance it to your needs. – Gene Loparco Jun 24 '23 at 22:08
25

Here is, IMO, most simple approach:

Generic schema

Text(_any_of_text_)
    .background(_any_of_Shape)

eg:

Text("Hello, World!")
    .background(Rectangle().stroke())

Text("Hello, World!")
    .background(RoundedRectangle(cornerRadius: 4).stroke())
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • To add to this answer, you could also assign a .frame() property to the Text to specify an exact size for the Text/Rectangle – Gene Loparco Jul 14 '20 at 20:00
18

Using Swift built-in shapes such as Capsule(), RoundedRectangle() and etc. Then, you can apply .overlay to the shape. The overlay take in any view such as text.

Example:

var body: some View {
    Capsule()
        .fill(Color.blue)
        .overlay(
            Text("Hello World")
        )
}

Outcome:

enter image description here

Swee Kwang
  • 724
  • 9
  • 15
2
Text("Hi")
 .frame(width: 40, height: 40, alignment: .center)
 .background(Color.black)
 .clipShape(Rectangle())
Christina
  • 21
  • 1
  • This would be a better answer if you explained how the code you provided answers the question. – pppery Jun 23 '20 at 00:25
1

Create a new SwiftUI View and make use of a Z-Stack to create your goal.

struct YourCustomObject: View {

    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.secondary)
                .frame(width: 200, height: 200)

            Text("Your desired text")
                .foregroundColor(.white)
        }
    }
}
Tobias Hesselink
  • 1,487
  • 9
  • 17
  • 2
    This will not necessarily work as intended. If, say, the text is extremely long, it may bleed past the width or height of the rectangle's frame. – Gene Loparco Jul 14 '20 at 19:54
  • So how can we have a background aligned with the text no matter how much it has description in it ? – Mahmoud Zinji Oct 24 '22 at 12:03
0

Using ZStack you can, but the text might spill from the rectangle so you use

.offset()

E.g:

            ZStack {
                RoundedRectangle(cornerRadius: 11)
                    .stroke(Color("color5"), lineWidth: 1)
                    .frame(width: .infinity, height: 60)
               
                VStack(alignment: .leading) {
                    Text("Adewale")
                        .multilineTextAlignment(.leading)
                        .foregroundColor(Color("color5"))
                        .offset(x: -95 )
                }
            }

use the .offset() to tweak the location of the Text view on the RoundedRectangle view.

bravestLimit
  • 33
  • 1
  • 9