当前位置:网站首页>Several methods of opening URL in swiftui view

Several methods of opening URL in swiftui view

2022-07-28 14:39:00 Dongpo Pig Knuckle

Visit my blog www.fatbobman.com[1] You can get a better reading experience

This article will introduce you to SwiftUI Open in view URL Several ways of , Other content includes how to automatically recognize the content in the text and convert it into clickable links , And how to customize the opening URL Before and after behavior, etc .

The example code of this article is in Swift Playgrounds 4.1 ( macOS edition ) Done in , Can be found in Download here [2]. Learn more about Swift Playgrounds The content of , You can refer to Swift Playgrounds 4 Entertainment or productivity [3] One article .

image-20220520182722773

SwiftUI 1.0( iOS 13、Catalina )

In the view , Developers usually need to deal with two different types of opening URL The situation of :

  • Click a button ( Or similar components ) Open the specified URL
  • Turn part of the text into a clickable area , Click to open the specified URL

Unfortunately ,1.0 In the era of SwiftUI Quite young , There is no native way to deal with the above two scenarios .

For the first scenario , The common practice is :

// iOS
Button("Wikipedia"){
    UIApplication.shared.open(URL(string:"https://www.wikipedia.org")!)
}

// macOS
Button("Wikipedia"){
    NSWorkspace.shared.open(URL(string:"https://www.wikipedia.org")!)
}

The second scenario is quite troublesome to implement , Need packing UITextView( or UILabel ) And cooperate with NSAttributedString Let's do it together , here SwiftUI It is only used as a layout tool .

SwiftUI 2.0( iOS 14、Big sur )

SwiftUI 2.0 Provides a fairly perfect native solution for the first scenario , But we still can't deal with the second scenario in a native way .

openURL

openURL yes SwiftUI 2.0 An environment value added in ( EnvironmentValue ), It has two functions :

  • By calling its callFunction Method , Open up URL The action of

At this time in Button in , We can go straight through openURL To complete in SwiftUI 1.0 In the version, by calling other frameworks API The work that can be done .

struct Demo: View {
    @Environment(\.openURL) private var openURL //  Introduce environmental values 

    var body: some View {
        Button {
            if let url = URL(string: "https://www.example.com") {
                openURL(url) { accepted in  //   By setting  completion  Closure , You can check whether it has been completed  URL  On . State by  OpenURLAction  Provide 
                    print(accepted ? "Success" : "Failure")
                }
            }
        } label: {
            Label("Get Help", systemImage: "person.fill.questionmark")
        }
    }
}
  • By providing OpenURLAction , Custom through openURL The act of opening a link ( It will be explained in detail later )

SwiftUI 2.0 Provides a combination of Button and openURL Of Link Control , Help developers further simplify code :

Link(destination: URL(string: "mailto://[email protected]")!, label: {
    Image(systemName: "envelope.fill")
    Text(" email ")
})

SwiftUI 3.0( iOS 15、Monterey )

3.0 Time , With Text Function enhancement and AttributedString Appearance ,SwiftUI Finally made up another short board —— Turn part of the text into a clickable area , Click to open the specified URL.

Text Use cases 1 : Automatic identification LocalizedStringKey Medium URL

By supporting LocalizedStringKey Created by the construction method of Text , It will automatically recognize the... In the text website ( Developers don't have to make any settings ), Click to open the corresponding URL .

Text("www.wikipedia.org 13900000000 [email protected]") //  The default parameter type is  LocalizedStringKey  Constructor 

image-20220520141225595

This method can only identify the network address ( Web address 、 Email address, etc ), Therefore, the telephone number in the code cannot be automatically recognized .

Please note that , The following code uses the parameter type String Constructor , therefore Text Will not automatically recognize... In content URL :

let text = "www.wikipedia.org 13900000000 [email protected]" //  The type is  String
Text(text) //  Parameter type is  String  The constructor of does not support automatic recognition 

Text Use cases 2 : distinguish Markdown The grammatical URL Mark

SwiftUI 3.0 Of Text , When the content type is LocalizedStringKey when ,Text It's possible to do some of the Markdown Parsing syntax tags :

Text("[Wikipedia](https://www.wikipedia.org "Wikipedia") ~~Hi~~ [13900000000](tel://13900000000 "13900000000")")

In this way , We can use any kind of URI ( Not limited to the network ), For example, make a call in the code .

image-20220522085352243

stay WWDC 2021 On , Apple launched NSAttributedString Value type version of AttributedString, And can be used directly in Text in . By means of AttributedString Set different properties for text in different positions in , So as to realize Text Open in URL The function of .

let attributedString:AttributedString = {
    var fatbobman = AttributedString(" Elbow  Swift  Notepad ")
    fatbobman.link = URL(string: "https://www.fatbobman.com")!
    fatbobman.font = .title
    fatbobman.foregroundColor = .green // link  Not for  nil  Of  Run, Custom foreground colors and underscores are automatically masked 
    var tel = AttributedString(" Phone number ")
    tel.link = URL(string:"tel://13900000000")
    tel.backgroundColor = .yellow
    var and = AttributedString(" and ")
    and.foregroundColor = .red
    return fatbobman + and + tel
}()

Text(attributedString)

image-20220520144103395

More information about AttributedString The content of , see also AttributedString—— Not only make the words more beautiful [4]

Text Use cases 4 : Identify... In a string URL Information , Translates into AttributedString

Above 3 In two use cases , except Use cases 1 It can automatically identify the network address in the text , The other two use cases need to be explicitly added by the developer in some way URL Information .

Developers can use NSDataDetector + AttributedString The combination of , So as to realize similar system information 、 mail 、 WeChat app like that , Automatic recognition of different types of content in text , And set the corresponding URL.

NSDataDetector[5] yes NSRegularExpression Subclasses of , It can detect semi-structured information in natural language text , Such as date 、 Address 、 link 、 Phone number 、 Traffic information, etc , It is widely used in various system applications provided by Apple .

let text = "https://www.wikipedia.org 13900000000 [email protected]"
//  Set the type to be recognized 
let types = NSTextCheckingResult.CheckingType.link.rawValue | NSTextCheckingResult.CheckingType.phoneNumber.rawValue
//  Create recognizer 
let detector = try! NSDataDetector(types: types)
//  Get recognition results 
let matches = detector.matches(in: text, options: [], range: NSRange(location: 0, length: text.count))
//  Process the inspection results one by one 
for match in matches {
    if match.resultType == .date {
        ...
    }
}

You can take NSDataDetector Think of it as a regular expression encapsulation suite with extremely high complexity .

The complete code is as follows :

extension String {
    func toDetectedAttributedString() -> AttributedString {

        var attributedString = AttributedString(self)

        let types = NSTextCheckingResult.CheckingType.link.rawValue | NSTextCheckingResult.CheckingType.phoneNumber.rawValue

        guard let detector = try? NSDataDetector(types: types) else {
            return attributedString
        }

        let matches = detector.matches(in: self, options: [], range: NSRange(location: 0, length: count))

        for match in matches {
            let range = match.range
            let startIndex = attributedString.index(attributedString.startIndex, offsetByCharacters: range.lowerBound)
            let endIndex = attributedString.index(startIndex, offsetByCharacters: range.length)
            //  by  link  Set up  url
            if match.resultType == .link, let url = match.url {
                attributedString[startIndex..<endIndex].link = url
                //  If it's email , Set background color 
                if url.scheme == "mailto" {
                attributedString[startIndex..<endIndex].backgroundColor = .red.opacity(0.3)
                }
            }
            //  by   Phone number   Set up  url
            if match.resultType == .phoneNumber, let phoneNumber = match.phoneNumber {
                let url = URL(string: "tel:\(phoneNumber)")
                attributedString[startIndex..<endIndex].link = url
            }
        }
        return attributedString
    }
}

Text("https://www.wikipedia.org 13900000000 [email protected]".toDetectedAttributedString())

image-20220520150754052

Customize Text The color of the link in

Unfortunately , Even if we've been for AttributedString Set the foreground color , But when a paragraph of text link Properties of nil when ,Text Its foreground color and underline settings are automatically ignored , Use the system default link Render settings to display .

At present, you can change... By setting shading Text All of them link Color :

Text("www.wikipedia.org 13900000000 [email protected]")
    .tint(.green)

Link("Wikipedia", destination: URL(string: "https://www.wikipedia.org")!)
    .tint(.pink)

image-20220520151737202

Comparison Text Fixed style of links in , It can be used Button or Link Create a link button that can customize the appearance freely :

Button(action: {
    openURL(URL(string: "https://www.wikipedia.org")!)
}, label: {
    Circle().fill(.angularGradient(.init(colors: [.red,.orange,.pink]), center: .center, startAngle: .degrees(0), endAngle: .degrees(360)))
})

image-20220520164125700

Customize openURL act

stay Button in , We can add logic code to the closure , Custom open URL Before and after .

Button(" Open the web page ") {
            if let url = URL(string: "https://www.example.com") {
                //  Turn on  URL  Previous behavior 
                print(url)
                openURL(url) { accepted in  //   By setting  completion  Closure , Define click  URL  Post action 
                    print(accepted ? "Open success" : "Open failure")
                }
            }
}

But in Link and Text in , We need to set the environment value openURL Provide OpenURLAction Handle the code to customize the behavior of opening links .

Text("Visit [Example Company](https://www.example.com "Example Company") for details.")
    .environment(\.openURL, OpenURLAction { url in
        handleURL(url)
        return .handled
    })

OpenURLAction The structure is as follows :

public struct OpenURLAction {
    @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
    public init(handler: @escaping (URL) -> OpenURLAction.Result)

    public struct Result {
        public static let handled: OpenURLAction.Result  //  The current code has processed the  URL , The invocation behavior is no longer passed down 
        public static let discarded: OpenURLAction.Result  //  The current processing code will discard the  URL , The invocation behavior is no longer passed down 
        public static let systemAction: OpenURLAction.Result  //  The current code does not handle , The calling behavior is passed down (  If the outer layer is not customized by the user  OpenURLAction , The default implementation of the system is used )
        public static func systemAction(_ url: URL) -> OpenURLAction.Result  //  The current code does not handle , New  URL  Pass down (  If the outer layer is not customized by the user  OpenURLAction , The default implementation of the system is used )
    }
}

such as :

Text("www.fatbobman.com [email protected] 13900000000".toDetectedAttributedString()) //  Create three links  https mailto tel
    .environment(\.openURL, OpenURLAction { url in
        switch url.scheme {
        case "mailto":
            return .discarded //  The mail will be discarded directly , Don't deal with 
        default:
            return .systemAction //  Other types  URI  To the next level ( Outer layer )
        }
    })
    .environment(\.openURL, OpenURLAction { url in
        switch url.scheme {
        case "tel":
            print("call number \(url.absoluteString)") //  Print phone number 
            return .handled  //  Inform that it has been handled , Will not continue to the next level 
        default:
            return .systemAction //  Other types  URI  The current code does not handle , Directly to the next layer 
        }
    })
    .environment(\.openURL, OpenURLAction { _ in
        .systemAction(URL(string: "https://www.apple.com")!) //  Since we did not continue to set after this layer  OpenURLAction ,  Therefore, it will eventually call the implementation of the system to open the apple official website 
    })

This processing method of setting the environment value layer by layer , It gives developers a lot of freedom . stay SwiftUI in , Similar logic is also used onSubmit , of onSubmit Information about , see also SwiftUI TextField Advanced —— event 、 The focus of 、 keyboard [6].

handler Return result of handled and discarded Will stop url Continue to pass down , The only difference between them is when you explicitly call openURL Will show when .

// callAsFunction  The definition of 
public struct OpenURLAction {
  public func callAsFunction(_ url: URL, completion: @escaping (_ accepted: Bool) -> Void)
}

// handled  when   accepted  by  true , discarded  when  accepted  by  false
openURL(url) { accepted in
      print(accepted ? "Success" : "Failure")
}

Combined with the above introduction , The following code will implement : After clicking the link , Users can choose whether to open the link or copy the link on the pasteboard :

struct ContentView: View {
    @Environment(\.openURL) var openURL
    @State var url:URL?
    var show:Binding<Bool>{
        Binding<Bool>(get: { url != nil }, set: {_ in url = nil})
    }

    let attributedString:AttributedString = {
        var fatbobman = AttributedString(" Elbow  Swift  Notepad ")
        fatbobman.link = URL(string: "https://www.fatbobman.com")!
        fatbobman.font = .title
        var tel = AttributedString(" Phone number ")
        tel.link = URL(string:"tel://13900000000")
        tel.backgroundColor = .yellow
        var and = AttributedString(" and ")
        and.foregroundColor = .red
        return fatbobman + and + tel
    }()

    var body: some View {
        Form {
            Section("NSDataDetector + AttributedString"){
                //  Use  NSDataDetector  convert 
                Text("https://www.fatbobman.com 13900000000 [email protected]".toDetectedAttributedString())
            }
        }
        .environment(\.openURL, .init(handler: { url in
            switch url.scheme {
            case "tel","http","https","mailto":
                self.url = url
                return .handled
            default:
                return .systemAction
            }
        }))
        .confirmationDialog("", isPresented: show){
            if let url = url {
                Button(" Copy to clipboard "){
                    let str:String
                    switch url.scheme {
                    case "tel":
                        str = url.absoluteString.replacingOccurrences(of: "tel://", with: "")
                    default:
                        str = url.absoluteString
                    }
                    UIPasteboard.general.string = str
                }
                Button(" open  URL"){openURL(url)}
            }
        }
        .tint(.cyan)
    }
}

openURL_Demo_Recording_iPhone_13_mini_2022-05-20_18.00.15.2022-05-20 18_03_18

summary

Although the main purpose of this article is to introduce SwiftUI Open in view URL Several ways to , But readers should also feel SwiftUI Three years of continuous progress , I believe that in the near future WWDC 2022 It will bring more surprises to developers .

I hope this article can help you .

Reference material

[1] www.fatbobman.com: https://www.fatbobman.com

[2] Download here : https://github.com/fatbobman/BlogCodes/tree/main/openURLinSwiftUI

[3] Swift Playgrounds 4 Entertainment or productivity : https://www.fatbobman.com/posts/swiftPlaygrounds4/

[4] AttributedString—— Not only make the words more beautiful : https://www.fatbobman.com/posts/attributedString/

[5] NSDataDetector: https://developer.apple.com/documentation/foundation/nsdatadetector

[6] SwiftUI TextField Advanced —— event 、 The focus of 、 keyboard : https://fatbobman.com/posts/textfield-event-focus-keyboard/

原网站

版权声明
本文为[Dongpo Pig Knuckle]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/209/202207281344349124.html