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()
}
}
Related
With UIKit, it's possible to give a control (e.g. a button) perfectly rounded corners (resulting in a circle on each side) by using this approach:
exampleButton.cornerRadius = exampleButton.frame.size.height/2
How does one achieve the same result with a SwiftUI view?
Because the views are defined more on the fly, I'm not sure how it would be possible to reference that frame size unless it's being set manually (which isn't the desire here).
Button(action: {
// ...
}) {
Text("I'm a Button")
}
.cornerRadius(???)
Another solution to this is to use shapes, in this case the Capsule shape, and use the clipShape modifier
Taking the example already mentioned, it would be like this:
Button(action: {
// ...
}) {
Text("I'm a Button")
.padding(.horizontal, 10)
.background(Color.red)
.clipShape(Capsule())
}
The padding in there can be adjusted so that your view looks how you want it to. The point it that capsule will always have the ends perfectly rounded. In this case I didn't want the text to be too close to the rounded edges, so I applied some padding to the sides.
A note to remember is that in SwiftUI the order the modifiers are applied in is very important.
You need to define it as a square and then put rounding on corners, like this:
Button(action: {
// ...
}) {
Text("I'm a Button")
.frame(width:150, height:150)
.background(Color.red)
.cornerRadius(.infinity)
}
PS. Added some background color for visibility
Working in XCode 12.4
For anyone who found this question trying to find out how to make a button with rounded corners (whether completely round like a capsule or not):
Button(action: {
// Do whatever
}) {
Spacer()
Text("Log In")
.font(.title2)
.padding()
.foregroundColor(.white)
Spacer()
}
.background(Color(UIColor.systemBlue))
.clipShape(RoundedRectangle(cornerRadius: 12))
.padding()
No need to fuss around with overlay shapes.
Another solution is to use geometry reader which will take the height or width of the screen and allow you to divide, multiply subtract or add from it.
Using the example, it would be like this:
GeometryReader { Geometry in
Button(action: {
// ...
}) {
Text("I'm a Button")
}
.cornerRadius(geometry.size.width / 2)
}
It is the most similar to frame.size.height.
How can I change the spacing between a UIButton and its underline? And also try to make the underline bolder. Any help is appreciated.
My UIButton:
enter image description here
The ideal UIButton:
enter image description here
To get such a button, you can split it int 2 elements - the text (not underlined) and a rectangle (as the line).
SwiftUI
In SwiftUI you can achieve your desired design with a Stack within the button with a text and a rectangle in it
Button(action: {
self.anyFancyFunction()
}) {
VStack(){
Text("Button")
Rectangle().frame(height: 5)
}
.foregroundColor(.black)
}
And it would look like:
In this example you can adjust the spacing by adding a (positive or negative) offset. You can add a corner radius to the bar and ich you wanted to have it rounded on the edges, you also can use Capsule() instead of Rectangle()
UPDATE:
UIKit
Regarding UIKit, I think a possible solution could be to create a view with 2 subviews (1. text, 2. bar underneath the text) and then you put a clear button with the same size over it on the same position.
I'll try to add an UIKit example in the afternoon.
Best,
Sebastian
In SwiftUI, there is a View called Rectangle that is perfectly matched for this. You can add it below any view by embedding them into a simple VStack.
Here is the code:
import SwiftUI
struct ContentView: View {
var body: some View {
Button(action: {
}) {
VStack(spacing: 15){
Text("帖子")
.font(.system(size: 30))
Rectangle()
}
.frame(width: 70, height: 60, alignment: .center)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Here is the result:
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
I am trying to change the color of clear(transparent) part inside of a SF Symbol called delete.left.fill. So far I've tried is as follows
Button(action: { return }, label: {
Image(systemName: "delete.left.fill")
.background(Color.black)
//.accentColor(.black)
.font(.system(size: self.fontSize*0.75))
})
.frame(width: self.width, height: self.width)
.foregroundColor(.lightGray)
//.background(Color.black)
When I run the code as above, the result is like
.
At first, the xinside of the symbol was the same color as background. I want it to make black.
I tried to set the backgroundColor of the Button and it made
whole Button black.
I tried to set accentColor of the Image to
black. Nothing changed.
I tried to set backgroundColor of the
Image to black. The result can be seen in the image.
The question is, is there a way to make just that x, inside the symbol, black programmatically?
You could mask the background and apply a custom style:
struct MyButtonStyle: ButtonStyle {
public func makeBody(configuration: MyButtonStyle.Configuration) -> some View {
configuration.label
.compositingGroup()
.opacity(configuration.isPressed ? 0.5 : 1.0)
}
}
Button(action: {}) {
Image(systemName: "delete.left.fill")
.foregroundColor(.green)
.background(
Color.black.mask(Circle())
)
}.buttonStyle(MyButtonStyle())
The circle may not fit to any usage, but for this image it works okay:
As he warned with the circle, #Faruk's solution didn't work for me with the exclamationmark.triangle.fill
I created a ZStack with the fill and unfill versions to create a yellow triangle with a black exclamation point and a black border:
ZStack{
Image(systemName: "exclamationmark.triangle")
.foregroundColor(Color.black)
.scaleEffect(1.1)
Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(Color.yellow)
}
I've only tried on couple of simulators, but it looks nice on iPadPro and iPad Mini
as of iOS 15 you can simply achieve that with .foregroundStyle(.red, .blue)
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)