iosswiftuitrailing

Right align view superimposed on other view using SwiftUI


I have capsule view on which I would like to superimpose a second "sticker" view to the upper right and cannot get it to work. The upper sticker view remains centered.

How can I get the sticker view to align to the right? Thanks for any suggestions.

Code of top "sticker" view:

struct StickerView: View {
    var text: String
    var isSelected: Bool {true}
    var body: some View {
        ZStack{
                Capsule()
                    .fill(Color.red)
                    .frame(height:56)
                    .cornerRadius(12)
                    .frame(maxWidth: .infinity, alignment: .trailing)//no effect
                
                Text(text)
                    .fontWeight(.bold)
                    .foregroundColor(.white)
                    .padding(.horizontal,18)
                    .multilineTextAlignment(.center)
            }.padding(.top,-80)
             .fixedSize()
             .frame(alignment: .trailing)//no effect
        }
}

Code of underlying view:

var body: some View {
        ZStack {
            Capsule(style: .continuous)
                .stroke(isSelected ? Color.red : Color.cyan, lineWidth: 6)
                .background(isSelected ? selectedBackgroundColor: Color.clear)
                .clipped()
                .clipShape(Capsule())
            HStack{
                Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: isSelected ? 24 : 20)
                    .padding(.trailing,8)
                
                VStack(spacing: 0) {
                    Text(subscription.displayName)
                        .frame(maxWidth:.infinity,alignment: .leading)
                    HStack {
                        Text(subscription.description)
                            .frame(maxWidth:.infinity,alignment: .leading)
                    }
                }
                .frame(maxWidth:.infinity,alignment: .leading)
                Spacer()
                VStack{   
                    Text(subscription.displayPrice)
                        .frame(alignment: .trailing)
                        .foregroundColor(.white)
                }
            }
            .padding(4)            
        }
    }

Solution

  • One way to superimpose the sticker over the capsule view is to show it as an overlay.

    Here is how it can be done this way:

    CapsuleView()
        .frame(height: 100)
        .overlay(alignment: .topTrailing) {
            StickerView(text: "purchased")
                .alignmentGuide(.top) { dim in
                    dim[VerticalAlignment.center]
                }
        }
    

    Screenshot


    BTW, you had quite a lot of redundancy in the code, here is how the two views can be simplified:

    // StickerView
    
    var body: some View {
        Text(text)
            .fontWeight(.bold)
            .foregroundStyle(.white)
            .padding(18)
            .background(.red, in: .capsule)
    }
    
    // CapsuleView
    
    var body: some View {
        ZStack {
            Capsule(style: .continuous)
                .fill(isSelected ? selectedBackgroundColor : .clear)
                .strokeBorder(isSelected ? .red : .cyan, lineWidth: 3)
            HStack {
                Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
                    .resizable()
                    .scaledToFit()
                    .frame(width: isSelected ? 24 : 20)
                    .padding(.trailing, 8)
                
                VStack(alignment: .leading, spacing: 0) {
                    Text(subscription.displayName)
                    Text(subscription.description)
                }
                .frame(maxWidth:.infinity,alignment: .leading)
                
                Text(subscription.displayPrice)
                    .foregroundStyle(.white)
            }
            .padding(4)
        }
    }