Correct Placeholder Code Fit Width Area and Adjust Height and Placeholder Icon in the. middle - swift

I am not sure what is lacking with regards to adding a placeholder using king fisher. This is the code
NavigationLink {
CustomView()
}
label: {
KFImage.url(URL(string: imageUrl)!)
.placeholder {
Image(systemName: "photo")
}
.fade(duration: 0.25)
.onFailure { error in print("Load image error : \(error) = \(earthquakeDetail.imgUrl)")
}
.resizable()
.aspectRatio(contentMode: .fill)
}
So when the image is successfully downlaoded, it fills the whole width and height is adjusted porportional to the width.
For the placeholder, what happens is that the icon is so small and the width and height area is bigger thant he area occupied when the image is successfully downloaded and displayed.
Please see images highlighted in yellow and green square. I tried adding an HStack wrapping the Image while setting the frame(width: .infinity) but didnt work out the way I wanted to.
What could I be missing here? I also need the image placeholder width with value 80 (using .frame(width: 80) but it also did not work out.

From my understanding, you would like the icon to be bigger than the default size, if that's the case, you will need to either change the size of the image using the font style .font(.system(size: CGFloat(fontSize))) or using the code below:
NavigationLink {
CustomView()
} label: {
KFImage.url(URL(string: imageUrl)!)
.placeholder {
Image(systemName: "photo")
.resizable()
.frame(width: 80)
}
.fade(duration: 0.25)
.onFailure { error in print("Load image error : \(error) = \(earthquakeDetail.imgUrl)")
}
.resizable()
.aspectRatio(contentMode: .fill)
}
A resizeable needs to be added to the placeholder because the second resizable will only work on the image once it has loaded. Hope this helps!

Related

SwiftUI Image from UIImage is still stretched after setting ascpectMode: .fit

I'm struggling to show a SwiftUI Image correctly when creating it from UIImage with the initialiser Image(uiImage: UIImage).
The code I'm using is
private var rightViewImage: Image
public var body: some View {
....
rightViewImage
.resizable()
.renderingMode(.template)
.scaledToFit()
.foregroundColor(.blue)
.frame(width: 20, height: 20)
}
and setting the variable in a method with
if let image = UIImage(systemName: "mic") {
rightViewImage = Image(uiImage: image)
}
I get a stretched version of the image
instead of the correctly scaled one, which is this
It seems like the .scaledToFit() is not working, it renders it like a .fill.
Is this a bug?
UIImage(systemName:) provides a completely different image dimension and resolution from Image(systemName:).
For this case, you should this instead:
Image(systemName: "mic")
.resizable()
.renderingMode(.template)
.scaledToFit()
.foregroundColor(.blue)
.frame(width: 20, height: 20)
This is what rendered by Image():
This is what rendered by UIImage():
The other answer will get the job done.
But what if you can't use an SF Symbol and want to preserve the aspect ratio? In that case, use the .aspectRatio() modifier:
Image("my-custom-image")
.resizable()
.aspectRatio(contentMode: .fit)
That will give an image that is as large as can fit in the parent view without stretching.
It looks like the question might be about some text paired with an image though. The best way to handle that is not to use resizable() at all. SF Symbols have a bunch of variations that match the system font. And Image(systemName:) will give a size and weight based on the current font. So you can do something like this and the image will match the text:
HStack {
Text("Here's a label")
Image(systemName: "mic")
.foregroundColor(.blue)
}
.font(.title.bold())
That's a better bet than resizing by hand because it will match the iOS system design and look 'right.'

GeometryReader's child view overflowing width

I'm currently using GeometryReader and Image to have images in a 3-column grid. In this grid, I want when user taps the image, they will see the bigger version of it.
However, when I implemented this, GeometryReader is not functioning properly. The image within the GeometryReader is overflowing the frame size passed to the GeometryReader.
I have checked that the size of GeometryReader is 1:1 ratio, but when you see the screenshot of view hierarchy, the size of image is different.
Below is the code for my custom Image view.
GeometryReader { geo in
if isZoomable {
Image("Image_gallery_default")
.centerCropped(width: geo.size.width, height: geo.size.height)
.aspectRatio(1.0, contentMode: .fill)
.onTapGesture {
showImage = true
}
} else {
Image("Image_gallery_default")
.centerCropped(width: geo.size.width, height: geo.size.height)
}
}
And centerCropped modifier is just a set of resizable/scaletofill/frame/clipped to make image center cropped.
self
.resizable()
.scaledToFill()
.frame(width: width, height: height)
.clipped()
The image on screen is just fine picture.
But if you tap on the right side of first picture (turlip one), it will instead show the picture on right side.
Why is the Image view overflowing instead of following the width of GeometryReader?
I searched to find out the solution, but nothing similar came up.

Kingfisher image not transitioning with rest of parent view

I just started to use Kingfisher to display web images using SwiftUI. However, I seem to have a problem when the image is inside an animated view.
I have a side menu that slides in from the left with a user's profile picture on my app. When using SiftUI's default Image, the image follows the sidebar when appearing on the screen. However, when using Kingfisher, the picture directly appears at its final destination. It does not slide in with the rest of the view.
Example
Here is the code for my profile picture View
struct ProfilePictureView: View {
let user: User?
let size: CGFloat
var body: some View {
let hasProfilePicture = !(user?.profilePicture?.path?.isEmpty ?? true)
return VStack {
if (hasProfilePicture) {
KFImage.url(URL(string: (user?.profilePicture?.path)!))
.resizable()
.clipShape(Circle())
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)
} else {
Image("paw")
.resizable()
.clipShape(Circle())
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)
}
}
}
}
The side menu itself appears using the withAnimation function.
Would any of you have suggestions or solutions for the problem I'm having?
Just add .loadImmediately() to the images, this will make them animate smoothly like you want.
So for you it should look like this:
KFImage.url(URL(string: (user?.profilePicture?.path)!))
.loadImmediately()
.resizable()
.clipShape(Circle())
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)

SwiftUI content gets cut off on smaller iPhone screens

I'm new to SwiftUI, so I'm following a tutorial to get familiar with it. However, my app's content is getting cut off on smaller screens (both vertically and horizontally). How can I prevent this from happening?
Here's my code:
EDIT: I have added borders around my images and resized the images as suggested in your comments and answers, but as you can see, the images don't appear to be taking up any more space than they're supposed to.
struct ContentView: View {
var body: some View {
ZStack {
Image("background").ignoresSafeArea(.all)
VStack {
Spacer()
Image("logo")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
.border(Color.black)
Spacer()
HStack {
Spacer()
Image("card3").border(Color.black, width: 3)
Spacer()
Image("card4").border(Color.black, width: 3)
Spacer()
}
Spacer()
Image("dealbutton")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
.border(Color.black)
Spacer()
HStack {
Spacer()
VStack {
Text("Player").padding(.bottom, 10)
Text("0").font(.largeTitle)
}
Spacer()
VStack {
Text("CPU").padding(.bottom, 10)
Text("0").font(.largeTitle)
}
Spacer()
}
.foregroundColor(.white)
Spacer()
}
}
}
}
And here's what the preview looks like on an iPod touch:
Try making Image("background") resizable or set it as the .background(:) of your ZStack. Currently the background image isn’t resizable and is larger than the screen, so it shows at its native size and stretches its parent ZStack beyond the bounds of the screen. Since your content is in that same ZStack, it also extends beyond the bounds of the screen
Your issue is related to your images that you have present on the view structure itself. Images are rendered at 100% their size, irrespective of their constraints. This will cause other views to be pushed away. The solution for that is to set a set size on the view itself that matches within the confines of your available space. Also you're resizing your ZStack which also resizes the content inside of the ZStack. For example.
Image("logo")
.resizeable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
Handling your image like this will ensure that it is set to the appropriate size when it is rendered. Then you can have the remaining views fall into place in a way that's expected. If you need it scaled on a % for the screen size you can use a GeometryReader to scale the view for different screen sizes.
GeometryReader { reader in
Image("logo")
.resizeable()
.aspectRatio(contentMode: .fit)
.frame(width: reader.size.width * 0.2)
}
Finally, remove your ZStack and set it up like this.
VStack {
//Your Content
}.background(
//Make sure to set the edgesIgnoring.. on this NOT the VStack
Image("background").edgesIgnoringSafeArea(.all)
)
Tip When Working with Stacks
Stacks, wether VStack, HStack, or ZStack's all ALWAYS have their frame set to the content that is held inside of them. If you had an object with a width of 100 and a height of 10,000 then the Stack would also have those dimensions, unless otherwise specified with a Modifier such as .frame(width...) or even, in your case, an Image that is resized.
Suppose your same stack then has a width: 10, height: 10 view added to it, it would still retain the same size as the largest content held within. This is of course handled differently with HStack and VStacks as they actually stack things in a 2D plane, whereas the ZStack works on the 3D plane.

Swiftui how to programatically adjust spacing between images and text?

I'm trying to get an aligned text-image pairs in swiftui programmatically. Is it possible?
I want the word "Visit" to start from the same position in both rows.
This is my code:
HStack{
Image(systemName: item.leftImage) // A system image name
Text(item.text) // A text representing the item
}
I know that I can add spacing to the HStack itself, but it won't fix my issue.
Since every systemimage provided by apple has a different sizing, I guess that I should programmatically somehow determine the spacing that should be instantiated between each the image to the text.
How can I do that?
I would recommend to use explicit width for image frame, this will fit any symbol automatically and make it centred
HStack{
Image(systemName: item.leftImage)
.frame(width: 28)
Text(item.text)
}
Give the Image a constant frame, like below:
HStack {
Image(systemName: item.leftImage)
.frame(width: 32)
Text(item.text) // A text representing the item
}
HStack takes Vertical alignment as argument. Then the text and icon is vertical alignment.
HStack(alignment: .center)
{
Image(systemName: item.leftImage) // A system image name
Text(item.text) // A text representing the item
}
To align the text, give the image a frame width. You need to determine they maximum width a image can take.
VStack(alignment: .leading)
{
HStack(alignment: .center)
{
Image(systemName: "pause") // A system image name
.frame(width: 50)
Text("Test") // A text representing the item
}
HStack(alignment: .center)
{
Image(systemName: "cloud") // A system image name
.frame(width: 50)
Text("Test") // A text representing the item
}
}