{"id":1610,"date":"2022-08-06T19:31:57","date_gmt":"2022-08-06T10:31:57","guid":{"rendered":"https:\/\/blog.enyou.net\/ko\/?p=1610"},"modified":"2022-08-15T21:12:58","modified_gmt":"2022-08-15T12:12:58","slug":"uikit%ec%9c%bc%eb%a1%9c-%ec%82%ac%ec%9a%a9%ec%9e%90-%ec%a0%95%ec%9d%98-textinput-view-%eb%a7%8c%eb%93%a4%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/blog.enyou.net\/ko\/archives\/1610","title":{"rendered":"UIKit\uc73c\ub85c \uc0ac\uc6a9\uc790 \uc815\uc758 TextInput View \ub9cc\ub4e4\uae30"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"473\" height=\"1024\" src=\"https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-473x1024.png\" alt=\"\" class=\"wp-image-1612\" srcset=\"https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-473x1024.png 473w, https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-139x300.png 139w, https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-768x1663.png 768w, https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-709x1536.png 709w, https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1-946x2048.png 946w, https:\/\/blog.enyou.net\/wp-content\/uploads\/2022\/08\/IMG_6008-1.png 1125w\" sizes=\"(max-width: 473px) 100vw, 473px\" \/><\/figure>\n\n\n\n<p>UIKit\uc5d0\uc11c UITextfiled \ub4f1, \uc904 \ubb38\uc790\ub97c \uc785\ub825\ud558\uae30 \uc704\ud55c View\ub4e4\uc740 \uc81c\uacf5\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\ub7f0\ub370 \ub9d0\uc774\uc8e0, \uc904 \ubb38\uc790\uac00 \uc544\ub2cc, \uc704\uc758 \uc2a4\ud06c\ub9b0\uc0f7\uacfc \uac19\uc740 \ube44\ubc00\ubc88\ud638 \ubdf0\ub294 \ub3c4\ub300\uccb4 \uc5b4\ub5bb\uac8c \ub9cc\ub4dc\ub294 \uac78\uae4c\uc694? \ub0b4\ud0a4\uc9c0\ub294 \uc54a\uc9c0\ub9cc, UITextfiled\ub97c hidden \ud55c \ub2e4\uc74c\uc5d0, \ucee4\uc2a4\ud140\ubdf0\ub97c \ubc29\uae08 \uc804 \ud14d\uc2a4\ud2b8 \ud544\ub4dc\uc758 \uc778\ud48b\uacfc \uc5f0\ub3d9 \uc2dc\ud0a4\uba74 \ub418\ub294 \uac78\uae4c\uc694?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ub2f5\uc740 Apple developer \uc0ac\uc774\ud2b8\uc5d0<\/h2>\n\n\n\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/keyboards_and_input\">https:\/\/developer.apple.com\/documentation\/uikit\/keyboards_and_input<\/a><\/p>\n\n\n\n<p>\ud55c \ubc29\uc5d0 \ucc3e\uc9c0\ub294 \uc54a\uace0 \uad6c\uae00\uc5d0 \ud0a4\uc6cc\ub4dc \uac80\uc0c9\ud558\ub2e4\uac00 \ucc3e\uac8c\ub418\uc5c8\uc9c0\ub9cc, \uc774\ubbf8 API \uceec\ub809\uc158\uc73c\ub85c keyboads and input\uc774 \uc81c\uacf5\ub418\uace0 \uc788\uc5c8\uc2b5\ub2c8\ub2e4!<\/p>\n\n\n\n<p>API Collection<br>Keyboards and Input (\ud0a4\ubcf4\ub4dc\uc640 \uc785\ub825)<br>Configure the system keyboard, create your own keyboards to handle input, or detect key presses on a physical keyboard. (\uc2dc\uc2a4\ud15c \ud0a4\ubcf4\ub4dc\ub97c \uc124\uc815\ud558\uace0, \uc785\ub825\uc744 \ubc1b\uae30 \uc704\ud55c \ud0a4\ubcf4\ub4dc\ub97c \ub9cc\ub4dc\uc138\uc694. \ub610\ub294 \ubb3c\ub9ac\uc801\uc778 \ud0a4\ubcf4\ub4dc\ub85c\ubd80\ud130 \ud0a4 \uc785\ub825\uc744 \uc778\uc2dd\ud558\uc138\uc694.)<\/p>\n\n\n\n<p>\ud504\ub85c\ud1a0\ucf5c\uc744 \ucc44\ud0dd\ud558\uace0, \uad6c\ud604\ub9cc \ud558\uba74\ub418\ub294 \uac04\ub2e8\ud55c \uc77c\uc774\uc9c0\ub9cc, \uc608\uc81c \ucf54\ub4dc\ub85c \ub530\ub77c\uac00\ubd05\uc2dc\ub2e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ucf54\ub4dc \uc791\uc131\ud558\uae30<\/h2>\n\n\n\n<p>\ud328\uc2a4\uc6cc\ub4dc \ubdf0\ub97c \uc791\uc131\ud558\uae30 \uc704\ud574\uc11c\ub294 \ub124\uac00\uc9c0 \uc77c\uc744 \ud574\uc8fc\uba74 \ub429\ub2c8\ub2e4.<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>\ud328\ub4dc\uc6cc\ub4dc \ubdf0\uc758 View \uc694\uc18c \uc791\uc131\ud558\uae30<\/li><li>\ud328\uc2a4\uc6cc\ub4dc \ubdf0\uc758 \uc0c1\ud669\uc744 \uc804\ub2ec \ubc1b\uc744 \ub51c\ub9ac\uac8c\uc774\ud2b8 \ud504\ub85c\ud1a0\ucf5c \uc791\uc131\ud558\uae30<\/li><li>UITextInputTraits\ub97c \ud328\uc2a4\uc6cc\ub4dc \ubdf0\uc5d0 \ucc44\ud0dd\ud558\uace0 \uad6c\ud604\ud558\uae30<\/li><li>UIKeyInput\ub97c \ud328\uc2a4\uc6cc\ub4dc \ubdf0\uc5d0 \ucc44\ud0dd\ud558\uace0 \uad6c\ud604\ud558\uae30<\/li><\/ol>\n\n\n\n<p>\uc544\ub798\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public protocol PasscodeFieldDelegate: AnyObject {\n    \/\/ \ud328\uc2a4\ucf54\ub4dc \uae00\uc790 \uc218 \ub9cc\ud07c \uc785\ub825\ud558\uba74 \ud638\ucd9c\ub41c\ub2e4.\n    func passcodeFieldDidEndEditing(_ passcodeFiled: PasscodeField)\n}\n\nfinal public class PasscodeField: UIView {\n    public var keyboardType: UIKeyboardType = .numberPad\n    public var textContentType: UITextContentType = .password\n    public var isSecureTextEntry: Bool = true\n    public var text: String? {\n        get { _text }\n        set {\n            if let text = newValue, text.count >= length {\n                _text = String(text&#91;text.startIndex..<min(text.endIndex,\n                                                          text.index(text.startIndex, offsetBy: length))])\n                if text.count == length {\n                    delegate?.passcodeFieldDidEndEditing(self)\n                }\n            } else {\n                _text = newValue\n            }\n        }\n    }\n    private var _text: String? {\n        didSet {\n            updateIndicatorViews()\n        }\n    }\n    public override var canBecomeFocused: Bool { true }\n    public override var canBecomeFirstResponder: Bool { true }\n    public weak var delegate: PasscodeFieldDelegate?\n    public let length: Int\n    public var foregroundColor: UIColor = .black {\n        didSet {\n            updateForegroundColor()\n        }\n    }\n    \n    private let indicatorsStackView: UIStackView\n    private let indicatorViews: &#91;UIImageView]\n    \n    \n    private func updateIndicatorViews() {\n        let text = self.text ?? \"\"\n        for index in (0..<length) {\n            indicatorViews&#91;index].image = (index < text.count) ? Const.filledImage : Const.emptyImage\n        }\n    }\n    \n    private func updateForegroundColor() {\n        indicatorViews.forEach { view in\n            view.tintColor = foregroundColor\n        }\n    }\n    \n    init(frame: CGRect = .zero, length: Int = 6) {\n        self.length = length\n        \n        self.indicatorsStackView = UIStackView()\n        \n        var indicatorViews: &#91;UIImageView] = &#91;]\n        for _ in (0..<length) {\n            let indicatorView = UIImageView(image: Const.emptyImage)\n            indicatorsStackView.addArrangedSubview(indicatorView)\n            indicatorViews.append(indicatorView)\n        }\n        \n        self.indicatorViews = indicatorViews\n        \n        super.init(frame: frame)\n        \n        setupViews()\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    private func setupViews() {\n        indicatorsStackView.distribution = .equalSpacing\n        \n        addSubview(indicatorsStackView)\n        indicatorsStackView.snp.makeConstraints { make in\n            make.edges.equalToSuperview()\n        }\n        \n        let gesture = UITapGestureRecognizer(target: self, action: #selector(onClick))\n        addGestureRecognizer(gesture)\n        \n        updateForegroundColor()\n    }\n    \n    @objc private func onClick() {\n        becomeFirstResponder()\n    }\n    \n    private enum Const {\n        static let emptyImage: UIImage? = UIImage(systemName: \"circle\")\n        static let filledImage: UIImage? = UIImage(systemName: \"circle.fill\")\n    }\n}\n\nextension PasscodeField: UITextInputTraits { }\n\nextension PasscodeField: UIKeyInput {\n    public var hasText: Bool { return text?.isEmpty ?? false }\n    \n    public func insertText(_ text: String) {\n        self.text = (self.text ?? \"\") + text\n    }\n    \n    public func deleteBackward() {\n        if self.text?.count ?? 0 > 0 {\n            self.text?.removeLast()\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>\uac04\ub2e8\ud558\ub124\uc694!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UIKit\uc5d0\uc11c UITextfiled \ub4f1, \uc904 \ubb38\uc790\ub97c \uc785\ub825\ud558\uae30 \uc704\ud55c View\ub4e4\uc740 \uc81c\uacf5\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\ub7f0\ub370 \ub9d0\uc774\uc8e0, \uc904 \ubb38\uc790\uac00 \uc544\ub2cc, \uc704\uc758 \uc2a4\ud06c\ub9b0\uc0f7\uacfc \uac19\uc740 \ube44\ubc00\ubc88\ud638 \ubdf0\ub294 \ub3c4\ub300\uccb4 \uc5b4\ub5bb\uac8c \ub9cc\ub4dc\ub294 \uac78\uae4c\uc694? \ub0b4\ud0a4\uc9c0\ub294 \uc54a\uc9c0\ub9cc, UITextfiled\ub97c hidden \ud55c \ub2e4\uc74c\uc5d0, \ucee4\uc2a4\ud140\ubdf0\ub97c \ubc29\uae08 \uc804 \ud14d\uc2a4\ud2b8 \ud544\ub4dc\uc758 \uc778\ud48b\uacfc \uc5f0\ub3d9 \uc2dc\ud0a4\uba74 \ub418\ub294 \uac78\uae4c\uc694? \ub2f5\uc740 Apple developer \uc0ac\uc774\ud2b8\uc5d0 https:\/\/developer.apple.com\/documentation\/uikit\/keyboards_and_input \ud55c \ubc29\uc5d0 \ucc3e\uc9c0\ub294 \uc54a\uace0 \uad6c\uae00\uc5d0 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1610","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/posts\/1610"}],"collection":[{"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/comments?post=1610"}],"version-history":[{"count":4,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/posts\/1610\/revisions"}],"predecessor-version":[{"id":1617,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/posts\/1610\/revisions\/1617"}],"wp:attachment":[{"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/media?parent=1610"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/categories?post=1610"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.enyou.net\/ko\/wp-json\/wp\/v2\/tags?post=1610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}