テキストの先頭にアイコンがあり、2行目のテキストの先頭をアイコンの下に潜り込ませるデザインを、あなたはどのように実装しますか?
SwiftUIのTextを使うと、テキストに画像をインラインで埋め込むことができるので、以下のように簡単に実装できます。
Text(Image(systemName: "star")) + Text("寿限無寿限無五劫のすり切れ海砂利水魚の水行末")
では、SF Symbolにない独自のアイコン画像を使いたい場合はどうでしょうか?
同じように、Textを使って実装してみます。
Text(Image("forward10")) + Text("寿限無寿限無五劫のすり切れ海砂利水魚の水行末")
なんかアイコンの位置がおかしい。。
ちょっと上になってる。。
そうなんです、思った通り配置してくれないんです。
他のModifier当ててみたり色々試してみたんですがうまくいかずでした。
そこで、UIKitで要件を実現するビューを作ってみることにしました。
色々試行錯誤してたどり着いた実装がこれです。
struct IconLabel: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let attachment = NSTextAttachment() attachment.image = UIImage(named: "forward10")! attachment.bounds = CGRect(x: 0, y: -6, width: 24, height: 24) let imageString = NSAttributedString(attachment: attachment) let mutableAttributedString = NSMutableAttributedString() mutableAttributedString.append(imageString) mutableAttributedString.append(NSAttributedString(string: "寿限無寿限無五劫のすり切れ海砂利水魚の水行末")) mutableAttributedString.addAttributes( [.font: UIFont.systemFont(ofSize: 18)], range: .init(location: 0, length: mutableAttributedString.length) ) let label = UILabel() label.attributedText = mutableAttributedString label.numberOfLines = 2 label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) return label } func updateUIView(_ uiView: UIViewType, context: Context) { } }
いい感じに配置されています!
ところが、、
以下はプレビューのCanvasの図なんですが、UIViewRepresentableで実装したビューはコンテンツの上下に余白が入ってしまいます。
理想は下図のようにフレームがコンテンツサイズと一致することなんですが、いろいろ試してもここがうまくいきませんでした。
上下に不要な余白が入ってしまうことで、他のビューと組み合わせたときにマージンを調整するのに非常に苦労します。
高さを固定値にしないと使えなかったりと、なかなか自由度の低いビューになってしまいます。
ということで、今のところ要件を実現するビューが実装できていない状況です。
もし良い感じのやり方ご存じの方いたら、コメントで教えていただけると嬉しいです。