Signal-iOS/SignalUI/Views/OWSSearchBar.swift
Adam Sharp 1a8c9fb5c6
Fix iOS 18 crash on launch due to offscreen rendering
Creating a UIImageView outside a view hierarchy now crashes on iOS 18. We can
avoid this offscreen rendering technique by removing UIImage.asTintedImage(),
configuring the tint colour and template rendering on the UIImage directly, and
rendering with UIGraphicsImageRenderer instead of lower-level Core Graphics
APIs.
2024-08-20 10:47:28 -04:00

95 lines
3.0 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import SignalServiceKit
public class OWSSearchBar: UISearchBar {
public override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
// MARK: -
public var searchFieldBackgroundColorOverride: UIColor? {
didSet {
applyTheme()
}
}
private func configure() {
applyTheme()
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeDidChange, object: nil)
}
// MARK: Theme
public static func applyTheme(to searchBar: UISearchBar) {
AssertIsOnMainThread()
searchBar.tintColor = Theme.secondaryTextAndIconColor
searchBar.barStyle = Theme.barStyle
searchBar.barTintColor = Theme.backgroundColor
// Hide searchBar border.
// Alternatively we could hide the border by using `UISearchBarStyleMinimal`, but that causes an issue when toggling
// from light -> dark -> light theme wherein the textField background color appears darker than it should
// (regardless of our re-setting textfield.backgroundColor below).
searchBar.backgroundImage = UIImage()
if Theme.isDarkThemeEnabled {
let foregroundColor = Theme.secondaryTextAndIconColor
let clearImage = UIImage(imageLiteralResourceName: "x-circle-fill")
searchBar.setImage(
clearImage.withTintColor(foregroundColor, renderingMode: .alwaysTemplate),
for: .clear,
state: .normal
)
let searchImage = UIImage(imageLiteralResourceName: "search")
searchBar.setImage(
searchImage.withTintColor(foregroundColor, renderingMode: .alwaysTemplate),
for: .search,
state: .normal
)
} else {
searchBar.setImage(nil, for: .clear, state: .normal)
searchBar.setImage(nil, for: .search, state: .normal)
}
let searchFieldBackgroundColor: UIColor
if let owsSearchBar = searchBar as? OWSSearchBar, let colorOverride = owsSearchBar.searchFieldBackgroundColorOverride {
searchFieldBackgroundColor = colorOverride
} else {
searchFieldBackgroundColor = Theme.searchFieldBackgroundColor
}
searchBar.traverseHierarchyDownward { view in
guard let textField = view as? UITextField else { return }
textField.backgroundColor = searchFieldBackgroundColor
textField.textColor = Theme.primaryTextColor
textField.keyboardAppearance = Theme.keyboardAppearance
}
}
private func applyTheme() {
Self.applyTheme(to: self)
}
@objc
private func themeDidChange(_ notification: Notification) {
AssertIsOnMainThread()
applyTheme()
}
}