7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Google マップのような評価の星をSwiftUIで実装してみる

Last updated at Posted at 2023-09-12

Google マップには、ユーザーがお店や施設を星1から5の5段階で評価し、その平均を表示する機能があります。

S__11517955.jpg

そこでよく目にする左側が黄色で右側がグレーの星。

これをSwiftUIでどのように実装するかを考えました。


まず、黄色い星はSwiftUIでは以下のように実装できます。

Image(systemName: "star.fill")
	.resizable()
    .foregroundColor(.yellow)
    .frame(width: 300, height: 300)

次に左半分が黄色で、右半分がグレーの星を実装してみます。

foregroundColorのModifierで部分的に色をつけられればよいのですが、そのような方法は(おそらく)なさそうなので、発想を変えて、「黄色とグレーの長方形を並べ、星型で切り抜く」方針をとります。

struct HalfStarView: View {
    var body: some View {
        HStack(spacing: 0) {
            Color.yellow
                .frame(width: 150, height: 300)
            Color.gray
                .frame(width: 150, height: 300)
        }
        .mask {
            Image(systemName: "star.fill")
                .resizable()
                .frame(width: 300, height: 300)
        }
    }
}

縦300、横150の黄色とグレーの長方形を用意してHStackを使って水平方向に横並びにし、、.maskModifierを使って縦横300の星でHStackを切り抜いています。


次に、星の黄色い部分の割合が0以上1以下の場合を考えます。

星を明るくする部分の割合をratioのr、星の縦横幅をそれぞれ300とすると、黄色い部分の横幅は300r、グレー部分の横幅は300(1-r)と表せます。

中学校の数学でやりましたね。

これらの横幅をそれぞれColor.yellowColor.grayの横幅に決めて星型で切り抜いて上げると、ratioが変わったときに星の黄色とグレー部分の横幅が変わります。

struct StarView: View {
    let ratio: CGFloat = 0.9
    let starLength: CGFloat = 300
    var body: some View {
        HStack(spacing: 0) {
            Color.yellow
                .frame(width: 300 * ratio, height: 300)
            Color.gray
                .frame(width: 300 * (1 - ratio), height: 300)
        }
        .mask {
            Image(systemName: "star.fill")
                .resizable()
                .frame(width: 300, height: 300)
        }
    }
}

ratioが0.9のとき

ratioが0.3のとき


最後に、星の縦横幅と割合をViewの外部から決められるようにして完成です。

struct StarView: View {
    let ratio: CGFloat
    let starLength: CGFloat

    var body: some View {
        HStack(spacing: 0) {
            Color.yellow
                .frame(width: starLength * ratio, height: starLength)
            Color.gray
                .frame(width: starLength * (1 - ratio), height: starLength)
        }
        .mask {
            Image(systemName: "star.fill")
                .resizable()
                .frame(width: starLength, height: starLength)
        }
    }
}

// 呼び出し側
StarView(ratio: 0.8, starLength: 300)
7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?