I'm trying to have a consistent-width broder with an overlay, and I keep getting the wrong result. My overlay looks like this:
With this code:
VStack {
HStack {
Text("Test")
}
HStack {
Text("test2")
}
}
.padding()
.frame(width: UIScreen.main.bounds.width*0.95)
.frame(minHeight: 50)
.overlay (
RoundedRectangle(cornerRadius: 20)
.stroke(RandomColor(), lineWidth: 3)
)
As you can see the corners are thicker than all other parts of the overlay. How can I fix this?
The thing you are missing is the difference between stroke and strokeBorder, if you changed your code to strokeBorder, it help you.
RoundedRectangle(cornerRadius: 20)
.strokeBorder(RandomColor(), lineWidth: 3)
The lineWidth makes it stretch beyond its bounds slightly. You can balance this with inset(by:) to keep it inside the original frame:
RoundedRectangle(cornerRadius: 20)
.inset(by: 3)
.stroke(RandomColor(), lineWidth: 3)
Note: you may only need to inset by 2 -- haven't done enough experimentation to see what the exact number is
Related
Problem
I am trying to create a view of a card with a symbol in the middle.
I tried to achieve this by creating a ZStack.
However, despite using .center alignment, the symbol always show in the top left.
Code
In the following code, the contentShape shows on the top-left despite alignment setting.
ZStack(alignment: .center) {
let baseShape = RoundedRectangle(cornerRadius: 10)
let contentShape = Rectangle()
.size(width: width, height: height)
.foregroundColor(getContentColor(color: card.color))
baseShape.fill().foregroundColor(.white)
baseShape.strokeBorder(lineWidth: 3, antialiased: true)
contentShape
}
Question
How do I properly align the contentShape at the center of the ZStack?
You need to use frame instead of size, because size is just for path drawing within provided rect, but rect here is entire area, so to fix use
ZStack(alignment: .center) {
let baseShape = RoundedRectangle(cornerRadius: 10)
let contentShape = Rectangle()
.frame(width: width, height: height) // << here !!
.foregroundColor(getContentColor(color: card.color))
baseShape.fill().foregroundColor(.white)
baseShape.strokeBorder(lineWidth: 3, antialiased: true)
contentShape
}
I want to align the heights of two HStack members. The expected outcome would be that the image has the same size as the text. The current outcome is that the image has more height than the text. This is my current setup:
HStack {
Text("Sample")
.font(.largeTitle)
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.red)
)
Spacer()
Image(systemName: "checkmark.seal.fill")
.resizable()
.scaledToFit()
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.red)
)
}
What I've tried:
.fixedSize() -> I tried to tack this modifier onto the Image but the result was that the Image's height got smaller than the text's. Probably because the SFSymbol's intrinsic height is smaller than the .largeTitle intrinsic height.
AlignmentGuide -> I tried to create a custom alignment guide where I initially thought I could say "align bottom of Image and Text and align top of Image and Text" and therefore have the same height. But it seemed like you can only apply a single alignment guide per stack view.
GeometryReader -> I tried to wrap the HStack in a GeometryReader in which I tacked the .frame(height: proxy.frame.height) view modifier on the Text and Image. This also did not help because it somehow just made some white space around the views.
How it is:
How I want it:
Wrap your Image in a Text. Since your image is from SF Symbols, SwiftUI will scale it to match the dynamic type size. (I'm not sure how it will scale other images.)
VStack {
let background = RoundedRectangle(cornerRadius: 10)
.foregroundColor(.red)
ForEach(Font.TextStyle.allCases, id: \.self) { style in
HStack {
Text("\(style)" as String)
.padding()
.background(background)
Spacer()
Text(Image(systemName: "checkmark.seal.fill"))
.padding()
.background(background)
}
.font(.system(style))
}
}
You can get the size of the Image small by adding a .frame() modifier to your HStack. See the code below,
HStack {
// Some Content
}
.frame(height: 60) // Interchangeable with frame(maxHeight: 60)
The Result:
For your exact example, I found 60 to be the sweet spot. But if you wanted a more dynamic solution, I'd make a few changes to your code. See the code below.
HStack {
Text("Sample")
.font(.largeTitle)
.frame(maxHeight: .infinity) // force the text to take whatever height given to the Parent View, which is the HStack
.padding(.horizontal) // Add padding to the Text to the horizontal axis
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.red)
)
Spacer()
Image(systemName: "checkmark.seal.fill")
.resizable()
.scaledToFit()
.padding()
.background(
RoundedRectangle(cornerRadius: 10)
.foregroundColor(.red)
)
}
.background(Color.gray)
.frame(height: 100) // Change this value and the embedded Views will fit dynamically
The output will work as shown in the GIF below,
Here is an upgrade version of rob answer which support Assets Image plus system Image! Almost any Image! Like this:
struct ContentView: View {
var body: some View {
VStack {
ForEach(Font.TextStyle.allCases, id: \.self) { style in
HStack {
Text(String(describing: style))
.padding()
.background(Color.pink.opacity(0.5).cornerRadius(10.0))
Spacer()
}
.font(.system(style))
.background(
Image("swiftPunk")
.resizable()
.scaledToFit()
.padding()
.background(Color.yellow.cornerRadius(10.0))
, alignment: .trailing)
}
}
}
}
Result:
So far I have this circle and image inside it on my view:
and here is the code for it:
Image(chosenImage)
.resizable()
.scaledToFit()
.clipShape(Circle())
.shadow(radius: 20)
.overlay(Circle().stroke(Color.white, lineWidth: 5).shadow(radius: -20))
.frame(width: width, height: width, alignment: .center)
.offset(y: -height * 0.05)
How can I make the image slide slowly to the left within the circle?
The circle should not move, only the image within it should move.
As the image ends another copy of it should be displayed and the action repeated. Or the image could quickly jump back to its previous position and start moving again. Another way to do this is when the image reaches its end it starts slowly moving to the right.
Any ideas on how to do this or is there any libraries that can help me achieve this?
The answer Jeeva Tamil gave is almost correct however it moves the image while staying in the shape of a circle (shown bellow).
Whereas I need it to "show different parts of the image as it moves".
Use .mask before the .overlay modifier to move the image within the circle. Here, I've used Draggesture to demonstrate the behaviour.
#State private var horizontalTranslation: CGFloat = .zero
.
.
.
Image(chosenImage)
.resizable()
.scaledToFit()
.clipShape(Circle())
.offset(x: horizontalTranslation)
.gesture(
DragGesture()
.onChanged({ (value) in
withAnimation {
horizontalTranslation = value.translation.width
print(horizontalTranslation)
}
})
.onEnded({ (value) in
withAnimation {
horizontalTranslation = .zero
}
})
)
.mask(Circle())
.shadow(radius: 20)
.overlay(Circle().stroke(Color.white, lineWidth: 5).shadow(radius: -20))
.frame(width: width, height: width, alignment: .center)
I am working on a SwiftUI project where I need a view to have a border with only some of the corners rounded (for instance, the top left and top right).
I added a RoundedRectangle with a stroke and was able to have all of the corners rounded. However, I need only some of the corners to be rounded and I couldn't figure out a way to do that.
This is the code I had to add a RoundedRectangle:
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.gray, lineWidth: 1)
)
To make only specific corners rounded, I looked at this Stackoverflow post: Round Specific Corners SwiftUI. However, I would have to get rid of the Rounded Rectangle (because it rounds all corners). I would have to use a normal border instead. But, with a normal border, it will cut out a piece of the border when rounding corners and trying any of the answers provided.
This is what I would ideally want it to look like (this is from an example from Bootstrap - we are rebuilding a website as an app):
Thank you!
Here's an alternative / easier way to recreate this. Add a white background to each of the rows and add a single gray background color behind them. Add spacing between the rows to let the gray background color appear like a divider between them. Then just add a rectangle overlay to the entire view, like you already had in your code!
struct CornerView: View {
var body: some View {
VStack(spacing: 1) {
ForEach(0..<5) { index in
Text("Item \(index)")
.frame(maxWidth: .infinity)
.frame(height: 55)
.background(Color.white)
}
}
.background(Color.gray)
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.gray, lineWidth: 1)
)
.padding()
}
}
struct CornerView_Previews: PreviewProvider {
static var previews: some View {
CornerView2()
}
}
I have created two textfields with the following code:
VStack (spacing: geometry.size.width/48) {
TextField("World Name", text: self.$WorldName)
.font(.system(size: geometry.size.width/28))
.textFieldStyle(PlainTextFieldStyle())
.frame(width: geometry.size.width*0.75)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.init(white: 0.28))
)
TextField("World Seed", text: self.$WorldSeed)
.font(.system(size: geometry.size.width/28))
.textFieldStyle(PlainTextFieldStyle())
.frame(width: geometry.size.width*0.75)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.init(white: 0.28))
)
Button (action: {
withAnimation {
self.back.toggle()
}
// Is there a way to "deselect" any textfields here
}){
Text("Back")
}
}
Why is it when I click on one, there is a blue border that does not fade out with the animation, and how can I remove it? This question is specific, and I have provided code, and necessary details, I don't see why it should be too hard to answer.
So in summarized terms, I need to know:
How to get rid of this blue selection border
Or
How to immediately deselect the text field within the button's action,
Get the border to properly line up with the TextField if I apply a padding or round corners.
The only blue in this picture is the border I am referring to
As shown in this screenshot, the textfield is round, but the selection border does not get round corners to reflect the rounded rectangle shape of the entry
The blue border does not fit the padding
I added a padding like this .padding([.leading, .trailing], 6)
You can remove the blue border (which appears on macos even when using PlainTextFieldStyle) by extending NSTextField like so:
extension NSTextField {
open override var focusRingType: NSFocusRingType {
get { .none }
set { }
}
}
See Apple Developer Forum answer here
I don't know which blue border are you referring to, if you are referring to blue border for textfield, there is no blue border beacuse you have given a PlainTextFieldStyle
To deselect the textfield
UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.endEditing(true)
To have a rounded textfield with padding
ZStack {
Rectangle()
.foregroundColor(.clear)
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color("appcolor").opacity(0.5), lineWidth: 1))
TextField("Enter some text", text: $worldName)
.padding([.leading, .trailing], 6)
}.frame(height: 42)
.padding([.leading, .trailing], 10)