CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết blog CFSDN này Giải pháp thứ ba cho việc sử dụng WebView để tạo ảnh chụp màn hình dài trên iOS đã được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này, hãy nhớ thích nó.
Lời nói đầu.
WebView là một điều khiển trình duyệt nhúng. Có hai loại WebView chính trong iOS: UIWebView và WKWebView đã bắt đầu được sử dụng sau iOS2 và WKWebView đã bắt đầu được sử dụng trong iOS8.
Do nhu cầu của dự án, SnapshotKit, một thư viện ảnh chụp màn hình dài, gần đây đã được triển khai. Trong số đó, cần hỗ trợ các thành phần UIWebView và WKWebView để tạo ảnh chụp màn hình dài. Để hiện thực hóa tính năng này, tôi đã tham khảo rất nhiều thông tin và thử nghiệm nhiều ý tưởng mới lạ khác nhau, cuối cùng tôi đã nhận ra một giải pháp kỹ thuật mới và thông minh.
Phần sau đây chủ yếu tóm tắt các điểm triển khai tương ứng, ưu điểm và nhược điểm của "các giải pháp hiện có trên Internet" và "giải pháp mới của tôi" về nhu cầu "WebView để tạo ảnh chụp màn hình dài".
Hiện có một giải pháp để tạo ảnh chụp màn hình dài bằng WebView.
Theo thông tin tìm kiếm trên Google, hiện nay có 2 cách chính để tạo ảnh chụp màn hình dài bằng iOS WebView:
- Tùy chọn 1: Sửa đổi các thành phần Khung và ảnh chụp màn hình
- Cách 2: Phân trang nội dung thành phần ảnh chụp màn hình và tổng hợp ảnh dài
Việc thực hiện cụ thể Đề án 1 và Đề án 2 sẽ được mô tả ngắn gọn dưới đây.
Tùy chọn 1: Sửa đổi các thành phần Khung và ảnh chụp màn hình.
Các điểm chính khi triển khai giải pháp một là: sửa đổi frameSize của webView.scrollView thành contentSize, sau đó chụp ảnh màn hình của toàn bộ webView.scrollView.
Tuy nhiên, giải pháp này chỉ áp dụng cho thành phần UIWebView vì nó tải tất cả nội dung của trang web cùng một lúc. Thành phần WKWebView, để tiết kiệm bộ nhớ, chỉ tải phần hiển thị khi tải nội dung trang web - điều này tương tự như thành phần UITableView. Sau khi sửa đổi frameSize của webView.scrollView, thao tác chụp ảnh màn hình ngay lập tức được thực hiện. Lúc này, WKWebView chưa tải nội dung của trang web nên ảnh chụp màn hình dài được tạo ra bị trống.
Mã cốt lõi của giải pháp một như sau:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
phần mở rộng UIScrollView {
công cộng
hàm takeSnapshotOfFullContent() -> UIImage? {
để originalFrame = self.frame
hãy để originalOffset = self.contentOffset
self.frame = CGRect.init(nguồn gốc: originalFrame.origin, kích thước: self.contentSize)
self.contentOffset = .zero
hãy để backgroundColor = self.backgroundColor ?? UIColor.white
UIGraphicsBeginImageContextWithOptions(self.bounds.size,
ĐÚNG VẬY
, 0)
bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext()
khác
{
trở lại
không
}
bối cảnh.setFillColor(backgroundColor.cgColor)
bối cảnh.setStrokeColor(backgroundColor.cgColor)
self.drawHierarchy(trong: self.bounds, afterScreenUpdates:
ĐÚNG VẬY
)
hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.frame = originalFrame
self.contentOffset = originalOffset
trở lại
hình ảnh
}
}
|
Mã kiểm tra:
?
1
2
3
4
5
|
riêng tư
hàm takeSnapshotOfUIWebView() {
hãy để hình ảnh = self.webView.scrollView.takeSnapshotOfFullContent()
}
|
Cách 2: Chụp ảnh màn hình phân trang của nội dung thành phần và ghép lại thành một ảnh dài.
Các điểm chính của việc triển khai giải pháp thứ hai là: cuộn nội dung của thành phần WebView trong các trang, sau đó tạo ảnh chụp màn hình trang và cuối cùng kết hợp tất cả ảnh chụp màn hình trang thành một ảnh dài.
Giải pháp này áp dụng cho các thành phần UIWebView và các thành phần WKWebView.
Mã cốt lõi của tùy chọn 2 như sau:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
phần mở rộng UIScrollView {
công cộng
func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
hãy để originalOffset = self.contentOffset
var trangNum = 1
nếu như
self.contentSize.height > self.bounds.height {
pageNum = Int(floorf(Float(self.contentSize.height / self.bounds.height)))
}
hãy để backgroundColor = self.backgroundColor ?? UIColor.white
UIGraphicsBeginImageContextWithOptions(self.contentSize,
ĐÚNG VẬY
, 0)
bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext()
khác
{
hoàn thành(nil)
trở lại
}
bối cảnh.setFillColor(backgroundColor.cgColor)
bối cảnh.setStrokeColor(backgroundColor.cgColor)
self.drawScreenshotOfPageContent(0, maxIndex: pageNum) {
hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.contentOffset = originalOffset
hoàn thành(hình ảnh)
}
}
fileprivate func drawScreenshotOfPageContent(_ index: Int, maxIndex: Int, hoàn thành: @escaping () -> Void) {
self.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.frame.size.height), hoạt hình:
SAI
)
hãy để pageFrame = CGRect(x: 0, y: CGFloat(index) * self.frame.size.height, width: self.bounds.size.width, height: self.bounds.size.height)
DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
self.drawHierarchy(trong: pageFrame, afterScreenUpdates:
ĐÚNG VẬY
)
nếu như
chỉ số < maxIndex {
self.drawScreenshotOfPageContent(index + 1, maxIndex: maxIndex, hoàn thành: hoàn thành)
}
khác
{
hoàn thành()
}
}
}
}
|
Mã kiểm tra:
?
1
2
3
4
5
6
7
8
9
10
11
12
|
riêng tư
hàm takeSnapshotOfUIWebView() {
self.uiWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
}
}
riêng tư
hàm takeSnapshotOfWKWebView() {
self.wkWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
}
}
|
Giải pháp mới để tạo ảnh chụp màn hình dài bằng WebView.
Ngoài Phương án 1 và Phương án 2, còn có phương án nào mới không?
Câu trả lời là có và chắc chắn.
Điểm mấu chốt của giải pháp mới này là: chức năng in WebView của hệ thống iOS.
Hệ thống iOS hỗ trợ in nội dung WebView sang file PDF. Với tính năng này, thiết kế của giải pháp mới như sau:
- In tất cả nội dung của thành phần WebView sang một trang PDF
- Chuyển đổi PDF sang hình ảnh
Mã cốt lõi của giải pháp mới như sau:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
import UIKit
nhập WebKit
cuối cùng nội bộ
lớp học
WebViewPrintPageRenderer: UIPrintPageRenderer {
riêng tư
định dạng var: UIPrintFormatter
riêng tư
nội dung varKích thước: CGSize
bắt buộc init(formatter: UIPrintFormatter, contentSize: CGSize) {
self.formatter = trình định dạng
self.contentSize = kích thước nội dung
siêu.init()
self.addPrintFormatter(trình định dạng, startingAtPageAt: 0)
}
ghi đè var paperRect: CGRect {
trở lại
CGRect.init(nguồn gốc: .zero, kích thước: contentSize)
}
ghi đè var printableRect: CGRect {
trở lại
CGRect.init(nguồn gốc: .zero, kích thước: contentSize)
}
riêng tư
hàm printContentToPDFPage() -> CGPDFPage? {
hãy để dữ liệu = NSMutableData()
UIGraphicsBeginPDFContextToData(dữ liệu, self.paperRect, nil)
self.prepare(for DrawPages: NSMakeRange(0, 1))
hãy để bounds = UIGraphicsGetPDFContextBounds()
UIGraphicsBeginPDFPage()
self.drawPage(tại: 0, trong: giới hạn)
UIGraphicsEndPDFContext()
hãy để cfData = dữ liệu như CFData
bảo vệ cho phép nhà cung cấp = CGDataProvider.init(dữ liệu: cfData)
khác
{
trở lại
không
}
hãy để pdfDocument = CGPDFDocument.init(nhà cung cấp)
hãy để pdfPage = pdfDocument?.page(at: 1)
trở lại
Trang pdf
}
riêng tư
hàm covertPDFPageToImage(_ pdfPage: CGPDFPage) -> UIImage? {
hãy để pageRect = pdfPage.getBoxRect(.trimBox)
hãy để contentSize = CGSize.init(chiều rộng:
sàn nhà
(pageRect.size.width), chiều cao:
sàn nhà
(pageRect.size.height))
UIGraphicsBeginImageContextWithOptions(contentSize,
ĐÚNG VẬY
, 2.0)
bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext()
khác
{
trở lại
không
}
ngữ cảnh.setFillColor(UIColor.white.cgColor)
bối cảnh.setStrokeColor(UIColor.white.cgColor)
ngữ cảnh.fill(pageRect)
ngữ cảnh.saveGState()
ngữ cảnh.translateBy(x: 0, y: contentSize.height)
ngữ cảnh.scaleBy(x: 1.0, y: -1.0)
context.interpolationQuality = .low
ngữ cảnh.setRenderingIntent(.defaultIntent)
ngữ cảnh. drawPDFPage(pdfPage)
ngữ cảnh.restoreGState()
hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
trở lại
hình ảnh
}
hàm nội bộ printContentToImage() -> UIImage? {
bảo vệ cho pdfPage = self.printContentToPDFPage()
khác
{
trở lại
không
}
hãy để hình ảnh = self.covertPDFPageToImage(pdfPage)
trở lại
hình ảnh
}
}
phần mở rộng UIWebView {
công cộng
func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), hoạt hình:
SAI
)
DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
hãy để renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)
hãy để hình ảnh = renderer.printContentToImage()
hoàn thành(hình ảnh)
}
}
}
phần mở rộng WKWebView {
công cộng
func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), hoạt hình:
SAI
)
DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
hãy để renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)
hãy để hình ảnh = renderer.printContentToImage()
hoàn thành(hình ảnh)
}
}
}
|
WebViewPrintPageRenderer là lớp cốt lõi của giải pháp này, chịu trách nhiệm in nội dung của thành phần WebView sang PDF, sau đó chuyển đổi PDF thành hình ảnh. UIWebView và WKWebView triển khai các tiện ích mở rộng tương ứng.
Mã kiểm tra:
?
1
2
3
4
5
6
7
8
9
10
11
12
|
riêng tư
hàm takeSnapshotOfUIWebView() {
self.uiWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
}
}
riêng tư
hàm takeSnapshotOfWKWebView() {
self.wkWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
}
}
|
So sánh ưu nhược điểm của ba giải pháp kỹ thuật.
Vậy, ưu nhược điểm của từng giải pháp kỹ thuật trong 3 giải pháp này là gì và phù hợp với những kịch bản nào?
Giải pháp 1: Chỉ áp dụng cho UIWebView; nếu trang web chứa nhiều nội dung, nó sẽ chiếm quá nhiều bộ nhớ khi tạo ảnh chụp màn hình dài. Vì vậy, giải pháp này chỉ phù hợp với những tình huống không cần hỗ trợ WKWebView và nội dung trang web không có quá nhiều nội dung.
Tùy chọn 2: Áp dụng cho UIWebView và WKWebView và đặc biệt phù hợp với WKWebView. Nhờ cơ chế phân trang để tạo ảnh chụp màn hình, việc sử dụng bộ nhớ sẽ giảm đi một cách hiệu quả. Tuy nhiên, có một vấn đề với giải pháp này: nếu trang web có phần tử location: cố định (chẳng hạn như thanh điều hướng cố định ở đầu trang web), phần tử đó sẽ xuất hiện lặp lại trên hình ảnh dài được tạo ra.
方案三:适用 UIWebView 和 WKWebView。其中最重要的一步——“把WebView内容打印到PDF” 是由iOS系统实现,所以该方案的性能在理论上是可以得到保障的。不过,这个方案存在一个问题:在把网页内容打印到PDF时,iOS系统获取的 contentSize 比WebView的实际contentSize 要大,从而导致生成的图片在靠近底部的内容部分和实际存在一点差异。具体可以下载运行我的长截图库 SnapshotKit 的 Demo,通过其中的 UIWebView 和 WKWebView 截图示例查看具体截图效果.
以上三个方案,总的来说,解决了部分场景的需求,但都不够完美,仍需做进一步的优化.
Tóm tắt.
Trên đây là toàn bộ nội dung bài viết mong rằng nội dung bài viết có giá trị tham khảo nhất định cho quá trình học tập, làm việc của mọi người. Nếu có thắc mắc gì có thể để lại tin nhắn để trao đổi.
原文链接:https://juejin.im/post/5b9d145ae51d450e7579d1e5 。
最后此篇关于iOS使用WebView生成长截图的第3种解决方案的文章就讲到这里了,如果你想了解更多关于iOS使用WebView生成长截图的第3种解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Tôi là một lập trình viên xuất sắc, rất giỏi!