【SwiftUI】吹き出しを作りたい

Instagram のこれ。

作ってみようと。

 

🧑🏻‍💻 popover で作る

使えそうなのでやってみました。

👉 popover(isPresented:attachmentAnchor:arrowEdge:content:) | Apple Developer Documentation



struct AnimatedSpeechBubble: View {
  @State private var show = false

  var body: some View {

    HStack {
      Text("お知らせ")
        .popover(isPresented: $show, arrowEdge: .trailing) {
          Text("横に出せないの?")
            .padding(.horizontal)
            .foregroundStyle(.background)
            .presentationBackground(.red)
            .presentationCompactAdaptation(.popover)
        }
      Spacer()
    }
    .frame(width: 250, height: 50)

    Button(show ? "hide" : "show") {
      show.toggle()
    }
    .buttonStyle(.borderedProminent)

  }
}

#Preview("animated") {
  AnimatedSpeechBubble()
    .padding()
    .frame(maxWidth: .infinity)
}

なぜか横 ( .trailing ) 方向に出すことができません。

GIFにしてみたら背景色もなんかあやしい。

あと、ボタンの色も勝手に変わる。

 

🧑🏻‍💻 手作りで

基本の組み合わせで作ります。

まず、吹き出しを作ります。

Path() は使いません。


struct SpeechBubble: View {
  var count: Int

  var body: some View {
    HStack(spacing: 0) {
      Rectangle()
        .fill(.red)
        .rotationEffect(.degrees(45))
        .frame(width: 20, height: 20)
        .offset(x: 14)
        .clipShape(.rect) // *
      HStack {
        Image(systemName: "heart.fill")
        Text("\(count)")
      }
      .foregroundStyle(.background)
      .padding()
      .background(.red, in: .rect(cornerRadius: 8))
    }
  }
}

#Preview("bubble") {
  SpeechBubble(count: 999)
}

アニメーションな部分は scaleopacity のトランジションを使います。


if show {
  SpeechBubble(count: 999)
    .transition(.scale(scale: 0.25).combined(with: .opacity))
}

いい感じです。

 

🧑🏻‍💻 まとめ

手作りでまあいけそうです。

以上のソースコード一式です。