如何使用 Swift 在 WebView 中查找和突出显示文本 [英] How to Find and Highlight Text in WebView using Swift
问题描述
我正在开发我的第一个应用程序,它涉及从网站上的大量文本中搜索特定的文本字符串.我希望能够搜索特定字符串并突出显示所有实例,并且随着用户键入更多内容,它会自动更新突出显示的事件.类似于任何浏览器中的查找功能.
我在此处找到了
- 右键单击并选择新建文件..."
- 选择空"然后点击下一步"
将您的文件命名为
UIWebViewSearch.js
并单击创建"您现在的项目中有一个名为
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
有一个 UISearchBarDelegate
而 UISearchBarDelegate
只是一个协议,如你所见.现在 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.
- In Xcode, in your project, navigate in the left hand Project navigator to where you would like to add your file.
- Right click and select "New File..."
- Select "Empty" and click "Next"
Name your file
UIWebViewSearch.js
and click "Create"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屋!