ContextMenu on a rounded LinearGradient produces sharp edges in SwiftUI
Add the following code after .frame(...)
:
.contentShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
How to soften edges of a Rectangle SwiftUI
Since you are working on Shape because you used RoundedRectangle
, the right and correct way of coloring is fill
, your issue is not connected to View to make an extension but it is about Shape.
extension Shape {
public func gradientForeground(colors: [Color]) -> some View {
self.fill(LinearGradient(gradient: .init(colors: colors), startPoint: .topLeading, endPoint: .bottomTrailing))
}
}
Use case:
struct ContentView: View {
var body: some View {
RoundedRectangle(cornerRadius: 50)
.gradientForeground(colors: [Color.red, Color.yellow])
.frame(width: 300, height: 300, alignment: Alignment.center)
}
}
SwiftUI: Drag & Drop and Corner Radius
I found a solution there: ContextMenu on a rounded LinearGradient produces sharp edges in SwiftUI
So, when I used contentShape
with onDrag
it works.
Why do PDFs resized in SwiftUI getting sharp edges?
I did a side by side comparison for both vector images using the ones you provided:
- http://simensolbakken.com/public/stackoverflow/icon.pdf
- http://simensolbakken.com/public/stackoverflow/icon_small.pdf
At first, I used SwiftUI
's inbuilt Image
and as mentioned, both performed badly at their extreme ends:
- Large image got sharp edges when it scaled down
- Small image got blurred as it scaled up
At first I thought it might be your pdf vectors so I used ones that I know have worked well in my previous projects, but I got the same issues.
Thinking it to be a UIImage
issue, I used SwiftUI
s Image(uiImage:)
but same problem.
Last guess was the image container, and knowing that UIImageView
has handled vector images well, getting UIViewRepresentable
to wrap the UIImageView
seems to solve this issue. And for now it looks like a possible workaround.
Workaround Solution:
struct MyImageView: UIViewRepresentable {
var name: String
var contentMode: UIView.ContentMode = .scaleAspectFit
var tintColor: UIColor = .black
func makeUIView(context: Context) -> UIImageView {
let imageView = UIImageView()
imageView.setContentCompressionResistancePriority(.fittingSizeLevel,
for: .vertical)
return imageView
}
func updateUIView(_ uiView: UIImageView, context: Context) {
uiView.contentMode = contentMode
uiView.tintColor = tintColor
if let image = UIImage(named: name) {
uiView.image = image
}
}
}
This loses some SwiftUI
Image
modifiers (you still have normal View
modifiers) but you can always pass in some parameters such as contentMode
and tintColor
as shown above. Add more if needed and handle accordingly.
Usage Example:
struct ContentView: View {
var body: some View {
VStack {
MyImageView(name: "icon", //REQUIRED
contentMode: .scaleAspectFit, //OPTIONAL
tintColor: .black /*OPTIONAL*/)
.frame(width: 27, height: 27)
MyImageView(name: "icon_small", //REQUIRED
contentMode: .scaleAspectFit, //OPTIONAL
tintColor: .black /*OPTIONAL*/)
.frame(width: 27, height: 27)
}
}
}
Now this is all speculation but it looks as though SwiftUI
treats vector images as a PNG
.
The following example is a simple side by side comparison of the small and large vector images rendered in UIKit
's UIImageView
and SwiftUI
's Image
.
Comparison:
struct ContentView: View {
let (largeImage, smallImage) = ("icon", "icon_small")
let range = stride(from: 20, to: 320, by: 40).map { CGFloat($0) }
var body: some View {
List(range, id: \.self) { (side) in
ScrollView(.horizontal) {
VStack(alignment: .leading) {
Text(String(format: "%gx%g", side, side))
HStack {
VStack {
Text("UIKit")
MyImageView(name: self.smallImage)
.frame(width: side, height: side)
MyImageView(name: self.largeImage)
.frame(width: side, height: side)
}
VStack {
Text("SwiftUI")
Image(self.smallImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: side)
Image(self.largeImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: side)
}
}
}
}
}
}
}
Results:
- Top row; Left : Small Image in
UIImageView
- Top row; Right : Small Image in
SwiftUI
Image
- Bottom row; Left : Large Image in
UIImageView
- Bottom row; Right : Large Image in
SwiftUI
Image
UIKit
's UIImageView
has consistent performace while SwiftUI
's Image
is having trouble.
Related Topics
How to Check If Core Data Is Empty
Why It Is Called the Memberwise Initialiser
Realitykit - How to Edit or Add a Lighting
Swift Protocol for String Interpolation
Building for Arm64E on Apple Silicon
How to Make Embedded View Controller Part of the Responder Chain
Different Portrait/Landscape Views in Storyboard and Swift
Cannot Preview in This File -- Message Send Failure
Metal Ray Tracing - Scenekit or Realitykit
Avspeechsynthesizer Errors in iOS 10
Swift: Hashable Struct with Dictionary Property
Get Color of Point in a Skscene Swift
Swift: Copy Information Selected by User in Abpersonviewcontroller to Dictionary
Spritekit Particle Emitter Multi Image
What Does a "Do Statement" Without Catch Block Mean
Passing and Storing Closures/Callbacks in Swift
Getting a Segmentation Fault: 11 with Swift 5.2 When Using Filemanager.Default.Currentdirectorypath
How to Use a Completion Handler to Put an Image in a Swiftui View