Contextmenu on a Rounded Lineargradient Produces Sharp Edges in Swiftui

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.


Sample Image



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 SwiftUIs 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:

  1. Top row; Left : Small Image in UIImageView
  2. Top row; Right : Small Image in SwiftUI Image
  3. Bottom row; Left : Large Image in UIImageView
  4. Bottom row; Right : Large Image in SwiftUI Image

UIKit's UIImageView has consistent performace while SwiftUI's Image is having trouble.

20x20


60x60


100x100


180x180



Related Topics



Leave a reply



Submit