如何使用 Swift 在 WebView 中查找和突出显示文本 [英] How to Find and Highlight Text in WebView using Swift

查看:29
本文介绍了如何使用 Swift 在 WebView 中查找和突出显示文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发我的第一个应用程序,它涉及从网站上的大量文本中搜索特定的文本字符串.我希望能够搜索特定字符串并突出显示所有实例,并且随着用户键入更多内容,它会自动更新突出显示的事件.类似于任何浏览器中的查找功能.

我在此处找到了

  1. 右键单击并选择新建文件..."

  1. 选择空"然后点击下一步"

  1. 将您的文件命名为 UIWebViewSearch.js 并单击创建"

  2. 您现在的项目中有一个名为 UIWebViewSearch.js 的空文件,您可以在其中粘贴内容.

使用文件

现在您的项目中有该文件,所以现在您只需要参考它.为此,您可以使用 Bundle 来加载资源您的项目.

如果您查看您提到的答案,您可以在中看到这几行ObjC代码-(NSInteger)highlightAllOccurencesOfString:(NSString*)str

NSString *path = [[NSBundle mainBundle] pathForResource:@UIWebViewSearch";ofType:@js"];NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

翻译成 Swift 看起来像这样:

if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),让 jsString = 试试?字符串(内容文件:路径,编码:.utf8){打印(jsString)}

这应该会给你一个 String 包含你所有的 JS 代码,例如准备添加到 WebView.

希望能给你一些开始.

更新(在您对此帖子添加评论后)

好的,所以你说:

<块引用>

我添加了我的 ViewController 代码以更好地传达我所处的位置.对如何实现您所指的他的代码的第二部分感到困惑.也不确定如何从搜索栏调用搜索.是否有我需要在searchBarSearchButtonClicked()"方法中调用的方法?刚刚在苹果开发者文档中找到了那个方法,不过不知道是否正确.

让我们把它分解成几部分,我将从你的 ViewController 开始,因为你的 viewDidLoad 中存在一些问题:

override func viewDidLoad() {super.viewDidLoad()//在加载视图后做任何额外的设置,通常是从笔尖.//将自定义 HTML 放到屏幕上let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")让 requestObj = URLRequest(url: myURL!)webView.loadRequest(requestObj)//提供包含字符串的代码//JS 代码,准备添加到 webview.if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),让 jsString = 试试?字符串(内容文件:路径,编码:.utf8){打印(jsString)}//万一func searchBarSearchButtonClicked() {let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(str)')";self.newsWebView .stringByEvaluatingJavaScript(来自:startSearch)}}

你已经添加了你的 searchBarSearchButtonClicked inside viewDidLoad,但是它应该被自己声明为一个函数(我们会回到以后再说).

此外,正如我在下面的评论中所写:

<块引用>

...在加载视图时运行的一个部分,它从包中加载 JavaScript.

所以让我们修复您的viewDidLoad:

override func viewDidLoad() {super.viewDidLoad()//在加载视图后做任何额外的设置,通常是从笔尖.//将自定义 HTML 放到屏幕上let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")让 requestObj = URLRequest(url: myURL!)webView.loadRequest(requestObj)//提供包含字符串的代码//JS 代码,准备添加到 webview.if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),让 jsString = 试试?字符串(内容文件:路径,编码:.utf8){打印(jsString)//在此处的 Web 视图上使用您的 jsString.newsWebView.stringByEvaluatingJavaScript(来自:jsString)}}

如您所见,searchBarSearchButtonClicked 函数已被删除,我们现在在 newsWebView 上使用了 jsString.

好的,下一部分:

<块引用>

也不知道如何从搜索栏中调用搜索.是否有我需要在searchBarSearchButtonClicked()"方法中调用的方法?刚刚在苹果开发者文档中找到了那个方法,不过不知道是否正确.

您在 Apple Developer 文档中找到了您的 searchBarSearchButtonClicked() 方法,我猜您的意思是 这个

正如您在文档(顶部栏)中所见,此功能来自 UISearchBarDelete 类.

委托许多 Apple 框架中使用的设计模式.它允许您编写一些通用组件,并让其他人"编写一些通用组件.(委托人)决定如何处理来自组件的信息(我知道错误的解释).

以您的 UISearchBar 为例.如果您要实现一个其他开发人员可以用作搜索栏的组件,当用户搜索某些内容时,您将如何处理?我在想,你的客户"应该怎么做?(使用您的组件的开发人员)处理这个?这样做的一种方法可能是开发人员应该子类化 UISearchBar 并覆盖用户确实搜索方法".您还可以使用 NSNotifications 并让开发人员注册这些通知.这两种方法都不漂亮也不聪明.

输入...代表.

UISearchBar 有一个 UISearchBarDelegateUISearchBarDelegate 只是一个协议,如你所见.现在 UISearchBar 可以向其委托询问某些事情,或者通知委托有关重要事件的信息.因此,例如,当用户点击搜索"时,按钮 UISearchBar 可以调用 delegate.searchBarSearchButtonClicked(self) 这意味着嘿委托,用户点击了我的搜索按钮......只是认为你应该知道".然后,代表可以按照其认为合适的方式做出回应.

这意味着任何类都可以符合 UISearchBarDelegate 并处理适合当前情况的各种任务.

好的,长话短说,希望你明白它的要点,我认为你应该多读一点关于委托的内容,因为它是 Apples 框架中到处使用的一种模式:)

所以,在你的情况下,你有一个 UISearchBar,你应该给它一个像这样的委托:

searchBar.delegate = self

并且您需要告诉编译器您打算实现 UISearchBarDelegate 协议.Swift 约定是在 ViewController 之后的 extension 中执行此操作,只是为了将事情分开:

extension ViewController: UISearchBarDelegate {}

然后你还必须实现你有兴趣听的UISearchBarDelegate的方法(注意一些协议需要方法,这意味着你必须实现它们但是我不认为 UISearchBar 有(否则你会在第一次运行时发现应用程序崩溃:)).

所以在您的情况下,您提到了 searchBarSearchButtonPressed.如您所见,它需要一个 UISearchBar 作为参数.所以你的函数最终看起来像这样:

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {守卫让 currentSearchText = searchBar.text else {返回}let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')";newsWebView.stringByEvaluatingJavaScript(来自:startSearch)}

所以...你从搜索栏中获取当前文本,将其作为参数添加到你的 startSearch 字符串中,然后将该 startSearch 字符串传递给你的 newsWebView.

整个扩展看起来像这样.

.... ViewController 类的最后一部分覆盖 func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()//处理任何可以重新创建的资源.}//didReceiveMemoryWarning 结束}//类视图控制器结束扩展视图控制器:UISearchBarDelegate {func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {守卫让 currentSearchText = searchBar.text else {返回}let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')";newsWebView.stringByEvaluatingJavaScript(来自:startSearch)}}

并且您的 viewDidLoad 看起来像这样(您必须将自己添加为搜索栏的委托)

override func viewDidLoad() {super.viewDidLoad()searchBar.delegate = self//委托设置//在加载视图后做任何额外的设置,通常是从笔尖.//将自定义 HTML 放到屏幕上let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")让 requestObj = URLRequest(url: myURL!)webView.loadRequest(requestObj)//提供包含字符串的代码//JS 代码,准备添加到 webview.if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),让 jsString = 试试?字符串(内容文件:路径,编码:.utf8){打印(jsString)//在此处的 Web 视图上使用您的 jsString.newsWebView.stringByEvaluatingJavaScript(来自:jsString)}}

哇...写了很多...希望对你有帮助.

I'm working on my first app, and it involves searching for a specific string of text from a large amount of text on a website. I want to be able to search for a specific string and highlight all instances, and as the user types more, it will automatically update the highlighted occurrences. Similar to a find function in any browser.

I found this question on here where they reference using UIWebViewSearch.js to implement this, but I'm not sure how to add that file to my project, or how to use it.

I've added a search bar to my app so far, but haven't done anything with it. Want to use this function along with the search bar to search for the text.

Here is my ViewController code:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var webView: UIWebView!
@IBOutlet weak var searchBar: UISearchBar!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // Place custom HTML onto the screen
    let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
    let requestObj = URLRequest(url: myURL!)
    webView.loadRequest(requestObj)


    // Code that provides a string containing
    // JS code, ready to add to a webview.
    if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
        let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
        print(jsString)
    } // end if


    func searchBarSearchButtonClicked() {
        let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(str)')"

        self.newsWebView .stringByEvaluatingJavaScript(from: startSearch)
    }


} // end of viewDidLoad


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
} // end of didReceiveMemoryWarning


} // end of class ViewController

解决方案

As @jon-saw says: Welcome to StackOverflow :)

I'll just answer how you can add the JavaScript file to your project...that should get things started right :)

Add a File

You can add a file to Xcode in several ways, but here's one.

  1. In Xcode, in your project, navigate in the left hand Project navigator to where you would like to add your file.

  1. Right click and select "New File..."

  1. Select "Empty" and click "Next"

  1. Name your file UIWebViewSearch.js and click "Create"

  2. You now have an empty file called UIWebViewSearch.js in your project in which you can paste in content.

Use a File

Now you have the file on your project, so now you just need to refer to it. To do so you use Bundle which can load resources in your project for you.

If you look at the answer you referred to, you can see these lines of ObjC code in - (NSInteger)highlightAllOccurencesOfString:(NSString*)str

NSString *path = [[NSBundle mainBundle] pathForResource:@"UIWebViewSearch" ofType:@"js"];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

Translated to Swift that would look like this:

if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
   let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
    print(jsString)
}

And that should give you a String containing all your JS code, ready to add to a WebView for instance.

Hope that gives you something to start with.

Update (after you added a comment to this post)

OK, so you say:

I added my ViewController code to better communicate where I'm at. Kind of confused on how to implement the second part of his code you're referring to. Also not sure how to call the search from the searchBar. Is there a method I need to call within 'searchBarSearchButtonClicked()' method? Just found that method on the apple developer documentation, don't know if it's the correct one, though.

Lets break it down into pieces, I'll start with your ViewController, as there are some problems in your viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // Place custom HTML onto the screen
    let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
    let requestObj = URLRequest(url: myURL!)
    webView.loadRequest(requestObj)
    // Code that provides a string containing
    // JS code, ready to add to a webview.
    if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
        let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
        print(jsString)
    } // end if


    func searchBarSearchButtonClicked() {
        let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(str)')"

        self.newsWebView .stringByEvaluatingJavaScript(from: startSearch)
    }
}

You've added your searchBarSearchButtonClicked inside viewDidLoad, but it should be declared as a function by itself (we'll get back to it later).

Furthermore, as I wrote in the comments below:

...One part that is run when the view is loaded and which loads the JavaScript from the bundle.

So lets fix your viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // Place custom HTML onto the screen
    let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
    let requestObj = URLRequest(url: myURL!)
    webView.loadRequest(requestObj)
    // Code that provides a string containing
    // JS code, ready to add to a webview.
    if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
        let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
        print(jsString)
        //Use your jsString on the web view here.
        newsWebView.stringByEvaluatingJavaScript(from: jsString) 
    }
}

As you can see, the searchBarSearchButtonClicked function has been removed and we now use out jsString on the newsWebView.

OK, next part:

Also not sure how to call the search from the searchBar. Is there a method I need to call within 'searchBarSearchButtonClicked()' method? Just found that method on the apple developer documentation, don't know if it's the correct one, though.

You have your searchBarSearchButtonClicked() method which you have found in the Apple Developer documentation, I'm guessing you're meaning this one

As you can see in the documentation (top bar), this function is from the UISearchBarDelete class.

Delegation is a design pattern used in many of Apples frameworks. It allows you to write some generic components and let "someone else" (the delegate) decide what to do with the information from the component (bad explanation I know).

Think of your UISearchBar for instance. If you were to implement a component that other developers could use as a search bar, how would you handle when the user searches for something? I'm thinking, how should your "customers" (the developers using your components) handle this? One way of doing this could be that the developers should subclass UISearchBar and override a "user did search method". You could also use NSNotifications and have the developer register for these notifications. Both of these methods are not pretty or clever.

Enter...the delegate.

UISearchBar has a UISearchBarDelegate and UISearchBarDelegate is just a protocol as you can see. Now the UISearchBar can ask its delegate for certain things, or inform the delegate about important events. So for instance, when the user taps the "Search" button UISearchBar can call delegate.searchBarSearchButtonClicked(self) which means "hey delegate, the user has clicked the search button on me...just thought you should know". And the delegate can then respond as it sees fit.

This means that any class can conform to UISearchBarDelegate and handle the various tasks as it suits in their current situation.

OK, long story, hope you get the gist of it and I think you should read a bit more on delegation as it is a pattern used all over in Apples frameworks :)

So, in your case, you have a UISearchBar, you should give that a delegate like so:

searchBar.delegate = self

And you need to tell the compiler that you intend to implement the UISearchBarDelegate protocol. The Swift convention is to do this in an extension after your ViewController, just to keep things separated:

extension ViewController: UISearchBarDelegate {

}

And then you must also implement the methods of UISearchBarDelegate that you are interested in listening to (note that some protocols have required methods, meaning that you MUST implement them but I don't think UISearchBar has (otherwise you'll find out when the app crashes the first time you run it :)).

So in your case, you mentioned searchBarSearchButtonPressed. As you can see it needs a UISearchBar as a parameter. So your function ends out looking like this:

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    guard let currentSearchText = searchBar.text else {
        return
    }
    let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')"

    newsWebView.stringByEvaluatingJavaScript(from: startSearch)
}

So... you fetch the current text from your searchBar, add it as a parameter to your startSearch string and hand that startSearch string to your newsWebView.

The entire extensions ends out looking like this.

.... last part of your ViewController class
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    } // end of didReceiveMemoryWarning
} // end of class ViewController

extension ViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        guard let currentSearchText = searchBar.text else {
            return
        }
        let startSearch = "uiWebview_HighlightAllOccurencesOfString('\(currentSearchText)')"

        newsWebView.stringByEvaluatingJavaScript(from: startSearch)
    }
}

And your viewDidLoad ends out looking like this (you must add yourself as a delegate to the searchBar)

override func viewDidLoad() {
    super.viewDidLoad()
    searchBar.delegate = self //delegate set up
    // Do any additional setup after loading the view, typically from a nib.

    // Place custom HTML onto the screen
    let myURL = Bundle.main.url(forResource: "myHTML", withExtension: "html")
    let requestObj = URLRequest(url: myURL!)
    webView.loadRequest(requestObj)
    // Code that provides a string containing
    // JS code, ready to add to a webview.
    if let path = Bundle.main.path(forResource: "UIWebViewSearch", ofType: "js"),
        let jsString = try? String(contentsOfFile: path, encoding: .utf8) {
        print(jsString)
        //Use your jsString on the web view here.
        newsWebView.stringByEvaluatingJavaScript(from: jsString) 
    }
} 

Wow...that was a lot of writing...hope it helps you.

这篇关于如何使用 Swift 在 WebView 中查找和突出显示文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆