Swift UI: Center Text into Circle - swift

I try to put a circle-shaped frame around a text view, but I just can't get it properly aligned and I can't see where the problem is. As you can see in the picture below, the text is sometimes offset to left, while it should be centred. Any ideas on how to fix it?
struct ContentView: View {
let result = getDate();
var body: some View {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top, spacing: 5) {
ForEach(result, id: \.self) {
day in
Text(day.name!)
.frame(width: 35, height: 35, alignment: .center)
.padding()
.overlay(
Circle()
.size(width: 35, height: 35)
.offset(x: 17.5,y: 17.5)
.scale(1.4)
.stroke(Color.orange, lineWidth: 4)
)
}
}
}
Spacer()
}.background(Color.white)
}
}
The circle is offset by half of the size of the frame, so its origin should be in the centre. The Text should be centered as well in .frame(width: 35, height: 35, alignment: .center).
Thanks a lot for helping! :)

.overlay already has size of container with Text an Circle centred in it, so it is just needed to operate with insets of circle not shifting it, like below
Text(day.name!)
.frame(width: 35, height: 35, alignment: .center)
.padding()
.overlay(
Circle()
.stroke(Color.orange, lineWidth: 4)
.padding(6)
)

Related

Format number inside image bubble

I'm having some trouble understanding how to properly align items in top of each other:
So I have the following VStack:
VStack(spacing: 0) {
Text("\(placeC.places.count)")
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
} //: END VStack
Which produces the following output:
What is the best way to have the number inside the circle? Is there a recommended SwiftUI builder that you all use that I can explore?
Typically you would use an .overlay:
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
.overlay(alignment: .top) {
Text("\(placeC.places.count)")
}
or a ZStack:
ZStack(alignment: .top) { // other alignments: .center, .bottom, .leading, .trailing
Image("map-pin-full-cluster-1")
.renderingMode(.template)
.resizable()
.frame(width: 35, height: 35)
.foregroundColor(.brown)
Text("\(placeC.places.count)")
.padding(.top, 4) // adjust this to move the text up/down
}

How to have 2x2 made of squares fit screen in SwiftUI

I'm trying to create a 2x2 grid through either VStacks/HStacks or LazyVGrid to have the squares on each row fit the screen. For example, the first and second squares each take up half the width of the screen and based on that length, that'll determine the height to make it a square. How would I go about doing that in the two ways that I've mentioned or is there a better way to do it? Here's what I have so far.
VStack {
HStack {
Rectangle()
.fill(Color.gray)
.frame(width: 100, height: 100)
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
}
HStack {
Rectangle()
.fill(Color.red)
.frame(width: 100, height: 100)
Rectangle()
.fill(Color.green)
.frame(width: 100, height: 100)
}
}
It feels wrong to hardcode the width and height for the frame property here or is that the way to go about removing the gaps between the squares? Would this way of hardcoding values scale to other phone sizes?
LazyVGrid(columns: layout) {
Rectangle()
.fill(Color.gray)
.frame(width: 210, height: 210)
Rectangle()
.fill(Color.blue)
.frame(width: 210, height: 210)
Rectangle()
.fill(Color.red)
.frame(width: 210, height: 210)
Rectangle()
.fill(Color.green)
.frame(width: 210, height: 210)
}
EDIT: Here's what the new code looks like to get what I wanted.
VStack(spacing: 0) {
HStack(spacing: 0) {
Rectangle()
.fill(Color.gray)
Rectangle()
.fill(Color.blue)
}
HStack(spacing: 0) {
Rectangle()
.fill(Color.red)
Rectangle()
.fill(Color.green)
}
}
.aspectRatio(1.0, contentMode: .fit)
Now to get it working with LazyVGrid.
It feels wrong to hardcode the width and height for frame here or is that the way to go about removing the gaps between the squares?
To remove the gaps between the squares, just modify the HStack / VStack to include spacing:
HStack(alignment: .center, spacing: 0, content: {
Rectangle()
.fill(Color.gray)
.frame(width: 100, height: 100)
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
})
You can use GeometryReader, as seen here.
Example usage:
struct MyView: View {
var body: some View {
GeometryReader { geo in
//You now have access to geo.size.width and geo.size.height
}
}
}
Just apply the aspectRatio (value 1 and fit the screen) modifier, there is no need to specify any frame.
VStack {
HStack {
Rectangle()
.fill(Color.gray)
Rectangle()
.fill(Color.blue)
}
HStack {
Rectangle()
.fill(Color.red)
Rectangle()
.fill(Color.green)
}
}
.aspectRatio(1.0, contentMode: .fit)

How to place texts under an image in SwiftUI?

I'm trying to create some tiles in my swiftUI project.
The tiles will need to look like this:
Basically, I need to place the caption on the left and the texts under the image.
I can create the image and I can overlay the texts on the image but I cannot place them under the image and I cannot place the caption to the left.
This is my current code:
Image("flower")
.resizable()
//.aspectRatio(contentMode: .fill)
.frame(width: 160, height: 200)
// Overlay is a very simple way to add content on top of your view ! 😁
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
.shadow(color: Color.black.opacity(0.3), radius: 6, x: 0, y: 3)
VStack(alignment: .trailing, spacing: 6) {
Text("sit amet")
.background(Color.gray.opacity(0.2))
.font(.caption)
}.onTapGesture {
// Handle the action when the card is touched
}
can someone please advice on this?
Put the Image and text both under VStack as follows:
VStack(alignment: .leading, spacing: 6) {
Image("flower")
.resizable()
//.aspectRatio(contentMode: .fill)
.frame(width: 160, height: 200)
// Overlay is a very simple way to add content on top of your view ! 😁
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
.shadow(color: Color.black.opacity(0.3), radius: 6, x: 0, y: 3)
Text("sit amet")
.background(Color.gray.opacity(0.2))
.font(.caption)
}.onTapGesture {
// Handle the action when the card is touched
}
Text("Some Info goes here")
}

Set SwiftUI view to always stay one size

I have a view that I always want to remain the same size, I haven't made it responsive to different screen sizes as eventually it will convert to a PDF. How do I set a specific view to always remain a size, and when I show it in a sheet it will display in the same format, just scaled down?
This is the view I am trying to maintain the size and aspect ratio of:
ScrollView(.vertical){
VStack(spacing: 0){
ForEach(processor.matchEvents){event in
if(event.team.home == true){
HomeArm(team: event.team, event: event) //Same as AwayArm, just changes text
}
else{
AwayArm(team: event.team, event: event)
}
}
}
}
struct AwayArm: View {
#ObservedObject var team: Team
var event: MatchEvent
var body: some View {
let mins: String = String(event.time)
ZStack {
Rectangle()
.frame(width: 5, height: 200)
HStack(spacing: 0){
Spacer()
Text("\(mins)'")
.font(.title)
.frame(width: 60, height: 60, alignment: .center)
.foregroundColor(team.teamTextColor)
.background(team.teamColor)
.clipShape(Circle())
.modifier(RoundedEdge(width: 5, color: .black, cornerRadius: 40))
Rectangle()
.frame(width: 80, height: 5)
VStack{
Text(event.event)
.font(.title)
Text("Event Details")
.font(.title2)
Text("\(event.player.shirtNumber) - \(event.player.playerName)")
.font(.title3)
}.padding()
.foregroundColor(.white)
.frame(width: 250, height: 150)
.background(LinearGradient(gradient: Gradient(colors: [Color(UIColor.lightGray), .gray]), startPoint: .top, endPoint: .bottom))
.cornerRadius(25)
.modifier(RoundedEdge(width: 5, color: .black, cornerRadius: 30))
}
.padding(.top)
.padding(.trailing, 35)
}
}
}
I want this to be displayed inside a sheet, but maintain the correct sizings and aspect ratio:
HStack{
ScrollView(.vertical){
MatchReportView()
}
Text("")
}
Any help on keeping this the same size, all the time, would be appreciated

SwiftUI different children alignment and GeometryReader

I want to transform a web app into an iOS app and I am struggling with alignments and the GeometryReader().
This a a screenshot from my original web app template:
This is my current version in SwiftUI:
With the related code:
struct PileRow: View {
var body: some View {
HStack() {
VStack(alignment: .leading, spacing: 3) {
Text("Adobe".uppercased())
Bar(backgroundColor: Color.gray, width: 200)
Bar(backgroundColor: Color.black, width: 200)
HStack(alignment: .top, spacing: 3) {
Text("EUR 1,00")
.fontWeight(.light)
Text(" / ")
.fontWeight(.light)
.foregroundColor(Color.gray)
Text("35,69")
.fontWeight(.light)
.foregroundColor(Color.gray)
}
Image("dots")
.resizable()
.scaledToFit()
.frame(width: 20)
}
.font(.system(size: 14))
.padding()
}
.background(Color.white)
.cornerRadius(15)
.shadow(radius: 6, x: 5, y: 5)
}
}
struct Bar: View {
var backgroundColor: Color
var width: CGFloat
var body: some View {
Rectangle()
.fill(backgroundColor)
.frame(width: width, height: 3)
.cornerRadius(1.5)
}
}
I want:
the dots image to be centered in the parent VStack (like margin: 0 auto; in CSS)
the outer HStack to be 100% width with a left and right margin of 10px (like width: 100%; margin: auto 10px; in CSS)
The special challenge I want to realize is, to give the second Bar() view a percentage with (or some equivalent) to have a with of 1.00/35.69*100%.
In the apple documentation of Swift UI I found:
GeometryReader
A container view that defines its content as a function of its own size and coordinate space. 3
With a change from:
Bar(backgroundColor: Color.gray, width: 200)
Bar(backgroundColor: Color.black, width: 200)
to
GeometryReader { g in
Bar(backgroundColor: Color.gray, width: g.size.width)
}
.frame(height: 3)
GeometryReader { g in
Bar(backgroundColor: Color.black, width: g.size.width*(1/35.69))
}
.frame(height: 3)
it is going close to what I look for:
I don't understand what is happening here. My purpose was to give the Bar views a size relationship to the parent. But the parent itself gets a different width and hight that I need to fix with a frame with a height of 3 and the parent HStack fills the entire screen.
When I try this:
GeometryReader { g in
Bar(backgroundColor: Color.gray, width: g.size.width)
Bar(backgroundColor: Color.black, width: g.size.width*(1/35.69))
}
I am completely out, because the bars get somehow vstacked:
I think this is what you want:
import SwiftUI
struct ContentView: View {
var body: some View {
GeometryReader { g in
HStack {
VStack(alignment: .leading, spacing: 3) {
Text("Adobe".uppercased())
Bar(backgroundColor: Color.gray, width: g.size.width)
Bar(backgroundColor: Color.black, width: g.size.width*(1/35.69))
HStack(alignment: .top, spacing: 3) {
Text("EUR 1,00")
.fontWeight(.light)
Text(" / ")
.fontWeight(.light)
.foregroundColor(Color.gray)
Text("35,69")
.fontWeight(.light)
.foregroundColor(Color.gray)
}
HStack {
Spacer()
Image(systemName: "dots")
.resizable()
.scaledToFit()
.frame(width: 20)
Spacer()
}
}
.font(.system(size: 14))
.padding()
}
.background(Color.white)
.cornerRadius(15)
.shadow(radius: 6, x: 5, y: 5)
}
.padding()
}
}
struct Bar: View {
var backgroundColor: Color
var width: CGFloat
var body: some View {
Rectangle()
.fill(backgroundColor)
.frame(width: width, height: 3)
.cornerRadius(1.5)
}
}