skip to Main Content

Here is the piece of code, half is commented,
in the first part, text elements from array are in VStack, and each one appears in new line. but on clicking it gives details about the clicked array element.
But in 2nd part, text Is concatenated and visible in the paragraph. But on click it is unable to show the details for the clicked element.
I just need the paragraphic representation of the text and each element clickable.
here is the code

//import SwiftUI
//
//struct ContentView: View {
//    let dummyStrings = [
//        "Lorem ipsum dolor sit amet*",
//        "consectetur adipiscing elit*",
//        "sed do eiusmod tempor incididunt*",
//        "ut labore et dolore magna aliqua*",
//        "Ut enim ad minim veniam*",
//        "quis nostrud exercitation ullamco*",
//        "laboris nisi ut aliquip ex ea commodo consequat*",
//        "Duis aute irure dolor in reprehenderit*",
//        "in voluptate velit esse cillum dolore*",
//        "eu fugiat nulla pariatur*"
//    ]
//    
//    var body: some View {
//        ScrollView {
//            VStack(alignment: .leading, spacing: 10) {
//                // Concatenate all strings into a single continuous text
//                Text(dummyStrings.joined(separator: " "))
//                    .font(.body)
//                    .foregroundColor(.blue)
//                    .modifier(ClickableText(lines: dummyStrings) { string in
//                        print("Clicked:", string)
//                    })
//            }
//            .padding()
//        }
//    }
//}
//
//// View modifier to make each line of text individually tappable
//struct ClickableText: ViewModifier {
//    let lines: [String]
//    let action: (String) -> Void
//    
//    func body(content: Content) -> some View {
//        // Use GeometryReader to determine the size of each line of text
//        GeometryReader { proxy in
//            VStack(spacing: 0) {
//                ForEach(lines, id: .self) { line in
//                    Text(line)
//                        .onTapGesture {
//                            action(line)
//                        }
//                        .frame(width: proxy.size.width, alignment: .leading)
//                        .contentShape(Rectangle()) // Make whole Text area tappable
//                }
//            }
//        }
//    }
//}
//
//struct ContentView_Previews: PreviewProvider {
//    static var previews: some View {
//        ContentView()
//    }
//}
//

//------------------For Testing use -------------------

import SwiftUI

struct ContentView: View {
    let dummyStrings = [
        "1Lorem ipsum dolor sit amet",
        "2consectetur adipiscing elit",
        "3sed do eiusmod tempor incididunt",
        "4ut labore et dolore magna aliqua",
        "5Ut enim ad minim veniam",
        "6quis nostrud exercitation ullamco",
        "7laboris nisi ut aliquip ex ea commodo consequat",
        "8Duis aute irure dolor in reprehenderit",
        "9in voluptate velit esse cillum dolore",
        "10 eu fugiat nulla pariatur"
    ]
    
    var body: some View {
        let concatenatedText = dummyStrings.joined(separator: " ")
        
        return ScrollView {
            Text(concatenatedText)
                .font(.body)
                .foregroundColor(.blue)
                .lineSpacing(5)
                .onTapGesture {
                    // Handle tap gesture here (e.g., print tapped portion)
                    print("Text tapped")
                }
                .padding()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

 

2

Answers


  1. One way is to join all the strings into a AttributedString, where each string has a link associated with it. The link would be a URL with whatever information you want encoded in it. Then, you can intercept the openURL action and run whatever code you want.

    For example, if you want to encode the string itself as the path of the URL

    func encodeIntoAttributedString(_ str: String) -> AttributedString {
        var attrStr = AttributedString(str)
        attrStr.link = URL(filePath: str)
        return attrStr
    }
    

    Use something like this to join everything together:

    extension Array where Element == AttributedString {
        func joined(separator: AttributedString = "") -> AttributedString {
            guard let first else { return "" }
            var result = first
            for elem in self[1...] {
                result += separator
                result += elem
            }
            return result
        }
    }
    

    Usage:

    let text = [
        "1Lorem ipsum dolor sit amet",
        "2consectetur adipiscing elit",
        "3sed do eiusmod tempor incididunt",
        "4ut labore et dolore magna aliqua",
        "5Ut enim ad minim veniam",
        "6quis nostrud exercitation ullamco",
        "7laboris nisi ut aliquip ex ea commodo consequat",
        "8Duis aute irure dolor in reprehenderit",
        "9in voluptate velit esse cillum dolore",
        "10 eu fugiat nulla pariatur"
    ].map(encodeIntoAttributedString).joined(separator: " ")
    
    var body: some View {
        ScrollView {
            Text(text)
                // these modifiers could also be replaced by adding the corresponding attributes in encodeIntoAttributedString
                .font(.body)
                .foregroundColor(.blue)
                .lineSpacing(5)
                .padding()
                .environment(.openURL, OpenURLAction { x in
                    // here I am printing the string itself, which is encoded in the path
                    print(x.path(percentEncoded: false))
                    return .handled
                })
        }
    }
    
    Login or Signup to reply.
  2.   var body: some View {
        ScrollView {
            HStack(alignment: .top, spacing: 0) {
                ForEach(dummyStrings.indices, id: .self) { index in
                    Text(dummyStrings[index])
                        .foregroundColor(.blue)
                        .onTapGesture {
                            print("Tapped on: (dummyStrings[index])")
                        }
                        + Text(index < dummyStrings.count - 1 ? " " : "")
                }
            }
            .font(.body)
            .lineSpacing(5)
            .padding()
        }
    }
    

    Try this

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search