SwiftUI: Border is double in size at the rounded edges of button - swift

I get a double border on a button and it looks strange. I tried to create the shape with RoundRectangle overlay, and got the same result. This is the code I use:
ScrollView(.horizontal, showsIndicators: false) {
HStack {
Button(action:{ action()}) {
Label("Name", image: "info")
}
.frame(height: 40)
.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
.foregroundColor(.green)
.background(.clear)
.overlay(
Capsule(style: .continuous)
.stroke(.green, lineWidth: 1)
)}}
And the result is:

The problem isn't that the border is double thickness at the sides, it's that it's half thickness at the top and bottom. The button is being clipped by the ScrollView.
In this case you can fix it by adding a padding to your HStack:
Before:
Adding .padding([.top, .bottom], 1) to HStack:

Related

Having multiline text in a horizontal scroll view in SwiftUI

I want to make a UI that loads an array of strings into a scrollable horizontal stack. The texts however should have a max width of 100, and expand to be multiline to fill the space. This works, however the text is cut off and the horizontal ScrollView is only allowing the height for one line of text.
How do I let the ScrollView expand vertically to whatever the largest text in the stack is?
I want to have a control right above the stack, so setting the height to .infinity isn't a solution, and preferably don't want to have to work with GeometryReader.
My code so far:
VStack {
Capsule()
.foregroundColor(.black.opacity(0.5))
.frame(width: 48, height: 2)
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(chats, id: \.self) { chat in
Text(chat)
}
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: 100)
}
}
}
The result:
Change .frame(maxWidth: 100) to .frame(width: 100). You'll then need to put a maxHeight on your HStack lest it grow too tall.
VStack {
Capsule()
.foregroundColor(.black.opacity(0.5))
.frame(width: 48, height: 2)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top) {
ForEach(chats, id: \.self) { chat in
Text(chat)
.frame(width: 100)
}
}
.frame(maxHeight: 200, alignment: .top)
}
}
Result:

MacOS swiftUI Custom ui TextField field with rounded edge

I'm having trouble customizing a TextField field, I would like to try to have a border equal to that of the first image for both:
Border color
Edge thickness dimension
Type of edge rounding
Can anyone give me advice?
Result I would like to achieve:
Result I get:
HStack(alignment: .center) {
Spacer()
TextField("Git Repository URL", text: $repoUrlStr)
.textFieldStyle(PlainTextFieldStyle())
.lineLimit(1)
.frame(width: 300)
.onAppear {
let url = "https://github.com/name/name"
if isValid(url: url) == true {
print("ok", url)
}
}
Button {
if !repoUrlStr.isEmpty {
self.repoUrlStr = ""
}
} label: {
Image(systemName: "xmark.circle.fill")
.padding(.trailing, 2)
.font(.system(size: 12))
}
.buttonStyle(PlainButtonStyle())
.opacity(repoUrlStr.isEmpty ? 0 : 1)
Spacer()
}
.padding([.top, .bottom], 4)
.border(Color.gray, width: 2)
.cornerRadius(3)
.padding(.bottom, 15)
Try to use rounded rectangle in background (with needed parameters, like corner radius, color, etc) instead of border, like
.background(
RoundedRectangle(cornerRadius: 8)
.stroke(your_color_here)
)

SwiftUI Fixed constraint from bottom of view to top of screen

Question: How to set fixed "constraint" from buttom of view to top of the screen?
My problem explanation:
I'm trying to implement such element on screen:
Rounded shape which has stable height in all screens
I use Oval to draw it like
public var body: some View {
VStack {
ZStack(alignment: .bottom) {
Ellipse()
.fill(Color.surfacePrimary)
.frame(width: 546, height: 364)
.offset(x: 0, y: -20)
Text("Text")
.padding(.bottom, 60)
.foregroundColor(.onPrimary)
}
.frame(minWidth: 0, idealWidth: .infinity, maxHeight: 20)
.edgesIgnoringSafeArea(.top)
Text("This text should be right below yellow shape, and it is, but on screens with not rectangle forms, on screens with rectangle form, it pops up on yellow zone")
Spacer()
}
}
Problem: that it works good on iphones 11, 12. But on 8, 8+, SE (where screens have right rectangle form) frame of ZStack move on top but Ellipse left on the same place. And Views which should be below yellow zone move to yellow zone.
UPD: I solved problem with different heights of StatusBar, but now I have another problem which was not observable before.
My new code:
public var body: some View {
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
Text("Text")
.padding(.bottom, 42)
.foregroundColor(.red)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.background(Color.red)
}
This ZStack fills almost all height of the screen. But I expect it should has fixed height. It looks like:
(hmmm ... some problem with uploading image)

Aligning objects in ZStack

The white bar is supposed to be aligned at the left of the darker bar. I've tried using spacers, or changing the alignment of the individual objects but nothing works. This is my code:
VStack {
HStack {
Text("Calories eaten today:")
.foregroundColor(.white)
.fontWeight(.semibold)
Spacer(minLength: 100)
HStack {
ZStack(alignment: .leading) {
Capsule()
.rotation(.degrees(90))
.frame(width: 20, height: CGFloat((calorieGoal/proportion)))
.foregroundColor(.black)
.opacity(0.2)
Capsule()
.rotation(.degrees(90))
.frame(width: 20, height: CGFloat((Swift.min((eatendatabase.dayNutrients[0]/proportion), 180))), alignment: .leading)
}
Spacer(minLength: 20)
Text("\(String(format: "%.0f", eatendatabase.dayNutrients[0]))")
.font(.caption)
.foregroundColor(.white)
.frame(alignment: .trailing)
}
Spacer()
}
}
.padding(.horizontal, 30)
As calorieGoal, proportional, and eatendatabase.dayNutrients were not provided as values, I have used the following constant and variable to keep track of the capsule's widths, which I will denote in the code as the "progress bar":
let MAX_WIDTH: CGFloat = 100.0
let currentProgress: CGFloat = 40.0
With that in mind, first you should consider moving the calorie count label ("832") outside of the HStack containing the progress bar. Second, you nested both the background and foreground capsules forming the progress bars in a ZStack. We can take the foreground capsule and align it to the left by nesting it in an HStack with a Spacer:
HStack {
Capsule()
.rotation(.degrees(90))
.frame(width: 20.0, height: currentProgress /*This is the progress width of the bar, out of 100*/)
Spacer()
}
Of course, we need to set the width of the HStack to the width of the background capsule, so that the foreground capsule aligns properly with the leading edge of the background capsule:
HStack {
...
}.frame(width: MAX_WIDTH)
Overall, here is a possible solution to your issue:
VStack {
HStack {
Text("Calories eaten today:")
.foregroundColor(.white)
.fontWeight(.semibold)
// Made this font smaller for the preview
.font(.footnote)
// Add auto space between the label and the progress bar
Spacer()
// Separate the capsule progress bar from the calorie count
ZStack {
Capsule()
.rotation(.degrees(90))
.frame(width: 20.0, height: MAX_WIDTH /*This is the max width of the bar*/)
.foregroundColor(.black)
.opacity(0.2)
// Nesting the progress Capsule in an HStack so we can align it to the left
HStack {
Capsule()
.rotation(.degrees(90))
.frame(width: 20.0, height: currentProgress /*This is the progress width of the bar, out of 100*/)
// Adding a Spacer will force the Capsule to the left when it is in an HStack
Spacer()
}
// Set the frame width of the HStack to the same width as the background capsule
.frame(width: MAX_WIDTH)
}
// Add auto space between the progress bar and the calorie count
Spacer()
// The calorie count text, nested in an HStack with the label and the progress bar
Text("832")
.font(.caption)
.foregroundColor(.white)
.frame(alignment: .trailing)
}
}
.padding(.horizontal, 30)
// Added a gray background for the preview
.background(Color.gray)
And it would look like this:

Swift UI: Center Text into Circle

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)
)