0

I would like to overlay text on top of an image, and allow that text to properly scale with the parent image as it decreases or increases in size. However, I do not want to force the text to fit inside the view. Below, is a simple code I have been using to test this:

struct BooksView: View {
    let gridItems = [GridItem(.adaptive(minimum: 200, maximum: 300))]
    let books = [
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4),
        BookView(bookTitle: "Illustrated Manual of Abdominal Massage", bookAuthor: "Shinsai Ota", bookRating: 4)
    ]


    var body: some View {

        ScrollView {
            LazyVGrid(columns: gridItems, spacing: 5) {
                ForEach(books.indices, id: \.self) { i in
                    books[i]
                }
            }
        }
    }
}

and my "BookView" looks like this:

import SwiftUI
import URLImage

struct BookView: View {
    let bookTitle: String
    let bookAuthor: String
    let bookRating: Int
    
    var body: some View {
        
        ZStack {
            VStack {
                URLImage(URL(string: "https://upload.wikimedia.org/wikipedia/commons/e/e8/AnpukuZukaiCover.jpg")!) { // placeholder url
                    EmptyView()
                } inProgress: { progress in
                    ProgressView()
                } failure: { error, retry in
                    VStack {
                            Text(error.localizedDescription)
                            Button("Retry", action: retry)
                    }
                } content: { image in
                    image
                        .scaleFit(radius: 2)
                        .shadow(radius: 5)
                }
            }
            
            
            VStack(alignment: .leading) {
                Spacer()

                Text(bookTitle)
                    .font(.title)
                    .fontWeight(.bold)
                    .lineLimit(3)
                    .foregroundColor(.primary)
                    
                

                Text("by \(bookAuthor)")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }
            .scaledToFit()
        }
        .frame(minWidth: 200, minHeight: 300)
    }
}

as well, I made a "scaleFit" function for my image. It looks like this:

    func scaleFit(radius: CGFloat) -> some View {
        self
            .resizable()
            .scaledToFit()
            .mask(
                self
                    .resizable()
                    .scaledToFit()
                    .clipped()
            )
            .clipShape(RoundedRectangle(cornerRadius: radius))
            .contentShape(Rectangle())
    }

This BooksView is inside the detail of a NavigationSplitView, and I was hoping of figuring out a way that allows the text to scale with the image as the column changes size.

I have tried using:

.minimumScaleFactor(0.01) and .font(.system(size: 300)) to try and scale my text, but I am not sure if this is what I want, as it has only been useful for fitting rather than dynamic scaling. I have looked at using .scaleEffect, but I am not too sure if that is what I want either. I was thinking of somehow turning the text into a bitmap, so it behaves differently and I could possible scale it better, but I feel there must be a better solution to this.

I also have looked at this page but everything seemed to refer to fitting rather than scaling with the parent.

  • I haven’t used it before but you could potentially use the SwiftUI `ImageRenderer` type to turn the text into an image. And then the image could be scaled like you want it to. – Fogmeister Apr 06 '23 at 13:04
  • This has some examples https://www.hackingwithswift.com/quick-start/swiftui/how-to-convert-a-swiftui-view-to-an-image – Fogmeister Apr 06 '23 at 13:05

0 Answers0