Quellcode durchsuchen

scroll search result text to visible area

cyberta vor 3 Jahren
Ursprung
Commit
835e8202fb

+ 23 - 4
deltachat-ios/Chat/ChatViewController.swift

@@ -955,13 +955,32 @@ class ChatViewController: UITableViewController {
         }
     }
 
-    private func scrollToMessage(msgId: Int, animated: Bool = true) {
+    private func scrollToMessage(msgId: Int, animated: Bool = true, scrollToText: Bool = false) {
         DispatchQueue.main.async { [weak self] in
             guard let self = self else { return }
             guard let index = self.messageIds.firstIndex(of: msgId) else {
                 return
             }
             let indexPath = IndexPath(row: index, section: 0)
+
+            if scrollToText {
+                self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
+                let cell = self.tableView.cellForRow(at: indexPath)
+                if let messageCell = cell as? BaseMessageCell {
+                    let textYPos = messageCell.getTextOffset(of: self.searchController.searchBar.text)
+                    let currentYPos = self.tableView.contentOffset.y
+                    let padding: CGFloat = 12
+                    self.tableView.setContentOffset(CGPoint(x: 0,
+                                                            y: textYPos +
+                                                                currentYPos -
+                                                                2 * UIFont.preferredFont(for: .body, weight: .regular).lineHeight -
+                                                                padding),
+                                                    animated: animated)
+
+                    return
+                }
+            }
+
             self.tableView.scrollToRow(at: indexPath, at: .top, animated: animated)
         }
     }
@@ -1807,7 +1826,7 @@ extension ChatViewController: ChatSearchDelegate {
         } else {
             searchResultIndex -= 1
         }
-        scrollToMessage(msgId: searchMessageIds[searchResultIndex])
+        scrollToMessage(msgId: searchMessageIds[searchResultIndex], animated: true, scrollToText: true)
         searchAccessoryBar.updateSearchResult(sum: self.searchMessageIds.count, position: searchResultIndex + 1)
         self.reloadData()
     }
@@ -1819,7 +1838,7 @@ extension ChatViewController: ChatSearchDelegate {
         } else {
             searchResultIndex += 1
         }
-        scrollToMessage(msgId: searchMessageIds[searchResultIndex])
+        scrollToMessage(msgId: searchMessageIds[searchResultIndex], animated: true, scrollToText: true)
         searchAccessoryBar.updateSearchResult(sum: self.searchMessageIds.count, position: searchResultIndex + 1)
         self.reloadData()
     }
@@ -1843,7 +1862,7 @@ extension ChatViewController: UISearchResultsUpdating {
                     self.searchAccessoryBar.updateSearchResult(sum: self.searchMessageIds.count, position: self.searchResultIndex + 1)
 
                     if let lastId = resultIds.last {
-                        self.scrollToMessage(msgId: lastId, animated: false)
+                        self.scrollToMessage(msgId: lastId, animated: true, scrollToText: true)
                     }
                     self.reloadData()
                 }

+ 12 - 0
deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift

@@ -406,6 +406,18 @@ public class BaseMessageCell: UITableViewCell {
         return backgroundColor
     }
 
+    func getTextOffset(of text: String?) -> CGFloat {
+        guard let text = text else { return 0 }
+        let offsetInLabel = messageLabel.label.offsetOfSubstring(text)
+        if offsetInLabel == 0 {
+            return 0
+        }
+
+        let labelTop = CGPoint(x: messageLabel.label.bounds.minX, y: messageLabel.label.bounds.minY)
+        let point = messageLabel.label.convert(labelTop, to: self)
+        return point.y + offsetInLabel
+    }
+
     override public func prepareForReuse() {
         accessibilityLabel = nil
         textLabel?.text = nil

+ 17 - 0
deltachat-ios/Extensions/Extensions.swift

@@ -99,3 +99,20 @@ extension UINavigationController {
         }
     }
 }
+
+extension UILabel {
+    func offsetOfSubstring(_ substring: String) -> CGFloat {
+        guard let text = text else {
+            return 0
+        }
+
+        let searchIndexes = text.ranges(of: substring, options: .caseInsensitive)
+        guard let firstIndex = searchIndexes.first else {
+            return 0
+        }
+
+        let prefix = text.substring(to: firstIndex.lowerBound)
+        let size: CGSize = prefix.size(withAttributes: [NSAttributedString.Key.font: font])
+        return size.height
+    }
+}

+ 16 - 0
deltachat-ios/Extensions/String+Extension.swift

@@ -9,6 +9,22 @@ extension String {
         return String(self[idx1..<idx2])
     }
 
+    func substring(to: Index) -> String {
+        return String(self[startIndex..<to])
+    }
+
+    func ranges(of string: String, options: String.CompareOptions = []) -> [Range<Index>] {
+        var result: [Range<Index>] = []
+        var startIndex = self.startIndex
+        while startIndex < endIndex,
+            let range = self[startIndex...].range(of: string, options: options) {
+                result.append(range)
+                startIndex = range.lowerBound < range.upperBound ? range.upperBound :
+                    index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
+        }
+        return result
+    }
+
     // O(n) - returns indexes of subsequences -> can be used to highlight subsequence within string
     func contains(subSequence: String) -> [Int] {
         if subSequence.count > count {