skip to Main Content

I’m trying to create a chat bubble like this:
Actual Bubble
Actual Bubble 2.0
This is what I have been able to achieve so far.
My attempt
My attempt

This is my code so far:

import SwiftUI

struct TestingView: View {
    
    var body: some View {
        ZStack {
            /// header
            VStack(alignment: .trailing) {
                HStack {
                    HStack() {
                        Text("abcd")
    
                    }
                    HStack {
                        Text("~abcd")
                    }
                }.padding([.trailing, .leading], 15)
                    .fixedSize(horizontal: false, vertical: true)
                
                /// text
                HStack {
                    Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!")
                    
                }.padding([.leading, .trailing], 15)
                
                /// timestamp
                HStack(alignment: .center) {
                    Text("12:00 PM")
                }.padding(.trailing,15)
                
            }.background(Color.gray)
                .padding(.leading, 15)
                .frame(maxWidth: 250, alignment: .leading)
            
        }
        
    }
}

struct TestingView_Previews: PreviewProvider {
    static var previews: some View {
        TestingView()
    }
}

The main goal is that I want the two labels on top to be distant relative to the size of the message content. I am not able to separate the two labels far apart i.e one should be on the leading edge of the bubble and the other one on the trailing edge.

Already tried spacer, it pushes them to the very edge, we need to apart them relative to the content size of the message as shown in attached images.

3

Answers


  1. Here is a simplified code.

    Regarding Spacer: To achieve your desired result you put both Text views inside of a HStack, and put a Spacer between them. So the Spacer pushes them apart to the leading and trailing edge.

    Also I recommend to only use one padding on the surrounding stack.

    enter image description here

            VStack(alignment: .leading) {
                // header
                HStack {
                    Text("+123456")
                        .bold()
                    Spacer() // Spacer here!
                    Text("~abcd")
                }
                .foregroundStyle(.secondary)
                
                // text
                Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!")
                    .padding(.vertical, 5)
                
                // timestamp
                Text("12:00 PM")
                    .frame(maxWidth: .infinity, alignment: .trailing)
                
            }
            .padding()
            .background(Color.gray.opacity(0.5))
            .cornerRadius(16)
            .frame(maxWidth: 250, alignment: .leading)
            
        }
    
    Login or Signup to reply.
  2. We can put that header into overlay of main text, so it will be always aligned by size of related view, and then it is safe to add spacer, `cause it do not push label wider than main text.

    Tested with Xcode 13.4 / iOS 15.5

    demo1demo2

    var body: some View {
        let padding: CGFloat = 15
        ZStack {
            /// header
            VStack(alignment: .trailing) {
                /// text
                HStack {
                    //Text("Hello Everyone")   // short test
                    Text("Hello Everyone, bdhjewbdwebdjewbfguywegfuwyefuyewvfyeuwfvwbcvuwe!") // long test
                }
                .padding(.top, padding * 2)
                .overlay(
                    HStack {            // << here !!
                        HStack() {
                            Text("abcd")
    
                        }
                        Spacer()
                        HStack {
                            Text("~abcd")
                        }
                    }
                , alignment: .top)
                .padding([.trailing, .leading], padding)
    
                /// timestamp
                HStack(alignment: .center) {
                    Text("12:00 PM")
                }.padding(.trailing, padding)
    
            }.background(Color.gray)
                .padding(.leading, padding)
                .frame(maxWidth: 250, alignment: .leading)
        }
    }
    
    Login or Signup to reply.
  3. To separate two components with fairly space in the middle, use HStack{} with Spacer().

    This is a sample approach for this case. Code is below the image:
    enter image description here

    VStack {
      HStack {
        Text("+92 301 8226")
            .foregroundColor(.red)
        Spacer()
        Text("~Usman")
            .foregroundColor(.gray)
      }
      .padding(.bottom, 5)
      .padding(.horizontal, 5)
      Text("Testing testingtesting testing testing testingtesting testing testing testing testing testing testing testing testing testing.")
        .padding(.horizontal, 5)
      HStack {
        Spacer()
        Text("2:57 AM")
            .foregroundColor(.gray)
            .font(.subheadline)
      }
      .padding(.trailing, 5)
    }
    .frame(width: 300, height: 160)
    .background(.white)
    .cornerRadius(15)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search