SetupTextField.swift 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2018-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. import UIKit
  21. @objc protocol SetupTextFieldDelegate {
  22. func editingChangedTextField(_ sender: SetupTextField, forEvent event: UIEvent) -> Void
  23. func primaryActionTriggered(_ sender: SetupTextField, forEvent event: UIEvent) -> Void
  24. }
  25. @IBDesignable class SetupTextField: UIView {
  26. private var currentDefaultText: String?
  27. //MARK: Control Properties
  28. @IBInspectable var showIcon: UIImage? {
  29. didSet {
  30. self.icon.image = showIcon?.withTint(Colors.white())
  31. self.icon.isHidden = false
  32. self.textBackground.frame = CGRect(x: 40, y: 0, width: self.frame.width - 40, height: self.frame.height)
  33. self.textField.frame = CGRect(x: 45, y: 5, width: 230, height: 30)
  34. }
  35. }
  36. @IBInspectable var placeholder: String? {
  37. didSet {
  38. let foregroundColor = [NSAttributedString.Key.foregroundColor: UIColor.lightGray] //THREEMA_COLOR_PLACEHOLDER
  39. self.textField.attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: foregroundColor)
  40. self.textField.accessibilityLabel = placeholder
  41. }
  42. }
  43. @IBInspectable var defaultText: String? {
  44. didSet {
  45. self.currentDefaultText = defaultText
  46. }
  47. }
  48. @IBInspectable var capitalization: Int = 0 {
  49. didSet {
  50. if let type = UITextAutocapitalizationType(rawValue: capitalization) {
  51. self.textField.autocapitalizationType = type
  52. }
  53. }
  54. }
  55. @IBInspectable var keyboardType: Int = 0 {
  56. didSet {
  57. if let type = UIKeyboardType(rawValue: keyboardType) {
  58. self.textField.keyboardType = type
  59. }
  60. }
  61. }
  62. @IBInspectable var returnKey: Int = 0 {
  63. didSet {
  64. if let type = UIReturnKeyType(rawValue: returnKey) {
  65. self.textField.returnKeyType = type
  66. }
  67. }
  68. }
  69. @IBInspectable var secureTextEntry: Bool = false {
  70. didSet {
  71. self.textField.isSecureTextEntry = secureTextEntry
  72. }
  73. }
  74. var text: String? {
  75. get {
  76. return self.textField.text
  77. }
  78. set {
  79. self.textField.text = newValue
  80. }
  81. }
  82. override var isFirstResponder: Bool {
  83. get {
  84. return self.textField.isFirstResponder
  85. }
  86. }
  87. //MARK: delegate control events
  88. weak var delegate: SetupTextFieldDelegate?
  89. @objc func editingChanged(_ sender: UITextField, forEvent event: UIEvent) {
  90. self.delegate?.editingChangedTextField(self, forEvent: event)
  91. }
  92. @objc private func touchDown(_ sender: UITextField, forEvent event: UIEvent) {
  93. guard let current = self.currentDefaultText, let currentText = sender.text, currentText.count == 0 else {
  94. return
  95. }
  96. sender.text = current
  97. }
  98. @objc private func primaryActionTriggered(_ sender: UITextField, forEvent event: UIEvent) {
  99. self.delegate?.primaryActionTriggered(self, forEvent: event)
  100. }
  101. //MARK: Initialization
  102. override init(frame: CGRect) {
  103. super.init(frame: frame)
  104. self.setup()
  105. }
  106. required init?(coder aDecoder: NSCoder) {
  107. super.init(coder: aDecoder)
  108. self.setup()
  109. }
  110. @discardableResult
  111. override func becomeFirstResponder() -> Bool {
  112. return self.textField.becomeFirstResponder()
  113. }
  114. @discardableResult
  115. override func resignFirstResponder() -> Bool {
  116. return self.textField.resignFirstResponder()
  117. }
  118. private let icon: UIImageView = {
  119. let icon = UIImageView()
  120. icon.isHidden = true
  121. icon.frame = CGRect(x: 11, y: 11, width: 18, height: 18)
  122. return icon
  123. }()
  124. private let textBackground: UIView = {
  125. let background = UIView()
  126. background.alpha = 0.1
  127. background.backgroundColor = .white
  128. background.layer.borderWidth = 0.5
  129. background.layer.borderColor = UIColor(red:1.0, green:1.0, blue:1.0, alpha:0.1).cgColor
  130. background.layer.cornerRadius = 3
  131. return background
  132. }()
  133. private let textField: UITextField = {
  134. let field = UITextField()
  135. field.textColor = UIColor.white
  136. field.tintColor = UIColor.white
  137. field.backgroundColor = .clear
  138. field.borderStyle = .none
  139. field.textAlignment = .left
  140. field.font = UIFont.systemFont(ofSize: 16.0, weight: .light)
  141. field.autocorrectionType = UITextAutocorrectionType.no
  142. field.spellCheckingType = UITextSpellCheckingType.no
  143. field.keyboardAppearance = UIKeyboardAppearance.dark
  144. return field
  145. }()
  146. //MARK: Private Methods
  147. private func setup() {
  148. self.backgroundColor = UIColor.clear
  149. let background = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height))
  150. background.backgroundColor = UIColor.clear
  151. background.layer.borderWidth = 0.5
  152. background.layer.borderColor = UIColor(red:1.0, green:1.0, blue:1.0, alpha:0.1).cgColor
  153. background.layer.cornerRadius = 3
  154. self.textBackground.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
  155. self.textField.frame = CGRect(x: 5, y: 5, width: 270, height: 30)
  156. self.textField.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
  157. self.textField.addTarget(self, action: #selector(touchDown), for: .touchDown)
  158. self.textField.addTarget(self, action: #selector(primaryActionTriggered), for: .primaryActionTriggered)
  159. self.textField.delegate = self
  160. self.textField.tintColor = Colors.mainThemeDark()
  161. self.addSubview(background)
  162. self.addSubview(self.icon)
  163. self.addSubview(textBackground)
  164. self.addSubview(self.textField)
  165. }
  166. }
  167. extension SetupTextField: UITextFieldDelegate {
  168. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  169. // Check if it has lowercase characters
  170. if self.capitalization != 0 && string.rangeOfCharacter(from: CharacterSet.lowercaseLetters) != nil {
  171. if let textCurrent = textField.text,
  172. let rangeCurrent = Range<String.Index>(range, in: textCurrent) {
  173. // Get current cursor position
  174. let selectedTextRangeCurrent = textField.selectedTextRange
  175. // Replace lowercase character with uppercase character
  176. textField.text = textField.text?.replacingCharacters(in: rangeCurrent, with: string.uppercased())
  177. if let selectedTextRangeCurrent = selectedTextRangeCurrent {
  178. // Set current cursor position, if cursor position + 1 is valid
  179. if let newPosition = textField.position(from: selectedTextRangeCurrent.start, offset: 1) {
  180. textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
  181. }
  182. }
  183. }
  184. return false
  185. }
  186. return true;
  187. }
  188. }