SwiftUI edges visible after using overlay - ios

I'm trying to create rounded edges in one of my views using overlay.
.background(Color.gray.opacity(0.2))
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
)
The issue is that i still can see the edges on the background and also the stroke. How to crop the edges?

Your view will not be tappable through overlay, even with transparency, so the solution is to use clip shape and background as shown below
struct DemoRoundRectView: View {
var body: some View {
Text("DEMO")
.frame(width: 100, height: 50)
.background(Color.gray.opacity(0.2))
.clipShape(RoundedRectangle(cornerRadius: 10)) // clip corners
.background(
RoundedRectangle(cornerRadius: 10) // stroke border
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
)
}
}

struct ContentView: View {
var body: some View {
Rectangle()
.fill(Color.orange)
.frame(width: 200, height: 200, alignment: .center)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.red, lineWidth: 1)
)
} }
try this.

It seems that right now your modifiers are something like:
.cornerRadius(10)
.background(Color.gray.opacity(0.2))
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
)
Instead, you need to change the order of the view modifiers, as order matters! You are rounding the corners then applying a background, whereas you should be applying the background so that the corner radius can then clip that.
Try this instead:
.background(Color.gray.opacity(0.2))
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
)

Related

How do I create a leading border for a view with cornerRadius in SwiftUI?

So I've got a view
VStack(alignment: .leading) {
Text("Top text").font(.title2).bold()
Spacer()
Text("Bottom text")
}
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
and want to setup a left colored (e.g., in red) border that should match its rounded contour.
I tried adding:
.overlay(RoundedRectangle(cornerRadius: 20)
.frame(width: 2, height: nil, alignment: .leading), alignment: .leading)
that does draw a left border but it doesn't match a rounded contour:
and I'd like to get something like this instead:
Here is a demo of possible approach - using mask in overlay (also shown how to make button clickable if there will be some in card)
Tested with Xcode 12.1 / iOS 14.1
struct DemoView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Top text").font(.title2).bold()
Spacer()
Button("Bottom text") {}
}
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
.overlay(
RoundedRectangle(cornerRadius: 10).fill(Color.red).mask( // << here !!
HStack {
Rectangle().frame(width: 10)
Spacer()
}
).allowsHitTesting(false)) // << make click-through
.frame(height: 200)
}
}

How to clip subviews using ZStack with SwiftUI?

I need to clip the view behind a Text by using its Rectangle. When I add a Text over this 1-pixel height rectangle, I need it to "clip" the subview below, so the text can be readable.
Of course, if I use a solid background color, it's easy to do, as I just set it and it will clip the subview.
Here is a POC to test it:
struct test: View {
let gradient = Gradient(colors: [Color.blue, Color.purple])
var body: some View {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
.frame(width: 200, height: 200)
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: 100, height: 1, alignment: .center)
Text("XXXX")
.background(Color.green)
}
}
}
}
Any ideas? I don't think I can handle it using a mask.
Sometimes a solution might be not-to-do instead of to-do-but.
Here is a possible implementation of above principle to solve your issue.
var body: some View {
ZStack {
Rectangle()
.fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
.frame(width: 200, height: 200)
HStack(spacing: 0) {
Rectangle()
.fill(Color.white)
.frame(width: 30, height: 1, alignment: .center)
Text("XXXX")
Rectangle()
.fill(Color.white)
.frame(width: 30, height: 1, alignment: .center)
}
}

How to disable SwiftUI ScrollView clipping

See the following sample code:
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(0 ..< 12) { index in
Rectangle()
.foregroundColor(.white)
.frame(width: 100, height: 100, alignment: .center)
.shadow(radius: 20)
}
}
}
This sample code will result in a horizontal ScrollView
with Rectangle as elements.
However, as it seems the ScrollView actually clips it's content
so any shadow on the top and bottom will be clipped.
Is there any way to disable automatic clipping by the scrollview
or another way to achieve this?
Shadow won't affect the frame of the Rectangle. So, try to add padding to the Rectangle, so the Shadow will be still visible, by increasing the frame size of the Rectangle including shadow..
ForEach(0 ..< 12) { index in
Rectangle()
.foregroundColor(.white)
.frame(width: 100, height: 100, alignment: .center)
.shadow(radius: 20)
.padding(20) //<< Padding here for the radius
}

Swiftui - only show a percentage of a view

I have a RoundedRectangle, and my objective is to lay another RoundedRectangle over it such that the overlay shows a "percentage complete". I can't seem to find the proper incantation to do so, though.
I think that ideally, the overlay should somehow only show a percentage of itself. Resizing itself to match the percentage skews the shape of the overlay.
import PlaygroundSupport
struct ContentView: View {
#State private var value: Double = 0
var body: some View {
GeometryReader { geom in
VStack {
Slider(value: self.$value, in: 0...1, step: 0.01)
ZStack {
ZStack(alignment: .leading) {
// The main rectangle
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: geom.size.width,
height: 200)
// The progress indicator...
RoundedRectangle(cornerRadius: 10)
.fill(Color.red)
.opacity(0.5)
.frame(width: CGFloat(self.value) * geom.size.width,
height: 200)
}
Text("\(Int(self.value * 100)) %")
}
}
}
.padding()
}
}
PlaygroundPage.current.setLiveView(ContentView())
In the above playground, if you look at 1, 2, or even 3 %, you can see that the red overlay is out of the blue background rectangle bounds in the upper and lower left. See image below.
I feel like this is not the proper solution, but I also couldn't find the right mix of things (trying scaleEffect, a bunch of offset and position math) to really nail it.
To me, like I said above, it feels like the overlay should be able to say "only make my left-most 40% visible" when the value is 0.4.
That was long-winded, I apologize for that. If you've read this far, and have any advice to impart, I'd be incredibly appreciative.
Thanks!
If I correctly understood your concern, here is a solution. Tested with Xcode 11.4 / iOS 13.4.
ZStack {
ZStack(alignment: .leading) {
// The main rectangle
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.frame(width: geom.size.width,
height: 200)
// The progress indicator...
RoundedRectangle(cornerRadius: 10)
.fill(Color.red)
.opacity(0.5)
.frame(width: CGFloat(self.value) * geom.size.width,
height: 200)
}
.clipShape(RoundedRectangle(cornerRadius: 10)) // << here !!
This how I approach it so I don't have to manage more than one cornerRadius.
VStack {
ZStack(alignment: .leading) {
// The main rectangle
Rectangle()
.fill(Color.blue)
.frame(width: geom.size.width,
height: 200)
// The progress indicator...
Rectangle()
.fill(Color.red)
.opacity(0.5)
.frame(width: CGFloat(self.value) * geom.size.width,
height: 200)
}
.cornerRadius(10)

SwiftUI Mask a rectangle inside a rounded rectangle

Hello there. I am wondering, in SwiftUI, how do you mask the contents of a rounded rectangle so that a child rectangle clips the corners.
In my example I have a white rounded rectangle and a pink rectangle on a zstack, I've tried to apply clipping, but the pink rectangle does not conform to the corners.
I've tried applying .mask to the white rectangle, but it gives different results to expectations (sometimes it doesn't show the pink rectangle).
I did find an example where you can set your own cornerRadius
Round Specific Corners SwiftUI
But I was wondering if perhaps there was a way to mask the internals/body of the pink rectangle so that it conforms to the parent's rounded rectangle?
My code follows;
var body: some View {
GeometryReader { geometry in
Color.gray
.edgesIgnoringSafeArea(.top)
.overlay(
ZStack (alignment: .topLeading) {
RoundedRectangle(cornerRadius: 16,
style: .continuous)
.foregroundColor(.white)
.shadow(radius: 10)
// Tried using .mask here
Rectangle()
.fill(Color.pink)
.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 150, alignment: .top)
.clipped()
}
.frame(width: 300, height: 450, alignment: .center)
)
}
.edgesIgnoringSafeArea(.all)
}
Edit: To clarify:
The pink rectangle should remain as a rectangle, but clip the top left and right to match the parent white rounded rectangle.
If I correctly understood your goal, here is a solution - the only needed clip in right place is after internal content (two rectangles in this case) is constructed. So clipping with RoundedRectangle gives rounded corners around entire card. (As well as shadow most probably is needed to entire card, so placed at the end).
UPDATE: re-tested with Xcode 13.3 / iOS 15.4
ZStack (alignment: .topLeading) {
Rectangle()
.foregroundColor(.white)
Rectangle()
.fill(Color.pink)
.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 150, alignment: .top)
}
.clipShape(RoundedRectangle(cornerRadius: 16)) // << here !!
.frame(width: 300, height: 450, alignment: .center)
.shadow(radius: 10)
#Asperi already posted a great answer, I have done this aswell with using mask modifier in SwiftUI. Furthermore you only have to set cornerRadius once.
VStack(spacing: 0)
{
ZStack(alignment: .center)
{
Rectangle()
.fill(Color.red)
.frame(width: 66, height: 20)
}
ZStack(alignment: .center)
{
Rectangle()
.fill(Color.white)
.frame(width: 66, height: 46)
}
}
.mask(Rectangle()
.cornerRadius(3.0)
.frame(width: 66, height: 66)
)
check this out
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
Color.gray
.edgesIgnoringSafeArea(.top)
.overlay(
ZStack (alignment: .topLeading) {
RoundedRectangle(cornerRadius: 16,
style: .continuous)
.foregroundColor(.white)
.shadow(radius: 10)
// Tried using .mask here
Rectangle()
.fill(Color.pink)
.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 150, alignment: .top)
.clipShape(RoundedRectangle(cornerRadius: 16)) // <<<<<<
}
.frame(width: 300, height: 450, alignment: .center)
)
}
.edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I think the easier way is to apply cornerradius to ZStack
ZStack (alignment: .topLeading) {
RoundedRectangle(cornerRadius: 16,
style: .continuous)
.foregroundColor(.white)
.shadow(radius: 10)
// Tried using .mask here
Rectangle()
.fill(Color.pink)
.frame(minWidth: 0, maxWidth: .infinity, maxHeight: 150, alignment: .top)
//.clipped() //<<= here
}
.frame(width: 300, height: 450, alignment: .center)
.cornerRadius(20) //<<= here

Resources