One aspect of my Swift app project is to build a feed with "posts" as I have sketched here.
I have every aspect of this finished except for the date display in the top left corner. How do I build this kind of hexagon shape in Swift UI?
Note that the "date" texts need to dynamic and parametizable. They can't be hard-coded into the shape.
You can use Shape for this project, but since we have SF symbol for what you need, it is easier to use SF symbol. Here one way of doing, you can scale it or change the Date as you like.
struct ContentView: View {
var body: some View {
CustomDateView(month: "April", day: "01", time: "00:00 AM", scaleEffect: 0.8)
CustomDateView(month: "July", day: "15", time: "2:00 PM", backgroundColor: .blue)
CustomDateView(month: "May", day: "26", time: "8:00 AM", scaleEffect: 0.5, backgroundColor: .green)
}
}
struct CustomDateView: View {
let month: String
let day: String
let time: String
let scaleEffect: CGFloat
let backgroundColor: Color
internal init(month: String, day: String, time: String, scaleEffect: CGFloat = 1.0, backgroundColor: Color = .clear) {
self.month = month
self.day = day
self.time = time
self.scaleEffect = scaleEffect
self.backgroundColor = backgroundColor
}
var body: some View {
VStack(spacing: 0.0) {
Text(month)
.font(.system(size: 25, design: .monospaced)).minimumScaleFactor(0.1)
Image(systemName: "hexagon")
.font(Font.system(size: 150, weight: Font.Weight.light))
.rotationEffect(Angle(degrees: 90.0))
.overlay(Text(day).font(.system(size: 70, design: .monospaced)).minimumScaleFactor(0.1))
Text(time)
.font(.system(size: 25, design: .monospaced)).minimumScaleFactor(0.1)
}
.padding((backgroundColor != Color.clear) ? 16.0 : 0.0)
.background((backgroundColor != Color.clear) ? backgroundColor.opacity(0.5).cornerRadius(20.0) : nil)
.scaleEffect(scaleEffect)
.shadow(radius: 10.0)
}
}
It seems using .scaleEffect()
modifier does NOT modify the frame of View and it keeps and carry the original size! It may be an issue in replacing the view with other views and it cause issue about taking more space than it needs to fit! therefor I updated the codes in way that modify the frame as well to solve that issue! more on in code, the new update does not break old API, it fix the issue:
struct CustomDateView: View {
let month: String
let day: String
let time: String
let scaleEffect: CGFloat
let backgroundColor: Color
internal init(month: String, day: String, time: String, scaleEffect: CGFloat = 1.0, backgroundColor: Color = .clear) {
self.month = month
self.day = day
self.time = time
self.scaleEffect = ((scaleEffect > 0.0) && (scaleEffect <= 1.0)) ? scaleEffect : 1.0
self.backgroundColor = backgroundColor
}
var body: some View {
VStack(spacing: 0.0) {
Text(month)
.font(Font.system(size: 25.0*scaleEffect, design: Font.Design.monospaced))
Image(systemName: "hexagon")
.font(Font.system(size: 150.0*scaleEffect, weight: Font.Weight.light))
.rotationEffect(Angle(degrees: 90.0))
.overlay(Text(day).font(Font.system(size: 70.0*scaleEffect, design: Font.Design.monospaced)))
Text(time)
.font(Font.system(size: 25.0*scaleEffect, design: Font.Design.monospaced))
}
.padding((backgroundColor != Color.clear) ? 16.0*scaleEffect : 0.0)
.background((backgroundColor != Color.clear) ? backgroundColor.opacity(0.5).cornerRadius(20.0*scaleEffect) : nil)
.shadow(radius: 10.0)
}
}