수색…
키보드를 표시 할 때 UIScrollView / UITableView 스크롤
거기에 사용할 수있는 몇 가지 방법이 있습니다 :
- 키보드 모양 이벤트 알림을 구독하고 오프셋을 수동으로 변경할 수 있습니다.
//Swift 2.0+
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourVCClassName.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourVCClassName.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
}
func keyboardWillHide(notification: NSNotification) {
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
//Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
if (userInfo) {
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardEndFrame.size.height, 0);
}
}
- (void)keyboardWillHide:(NSNotification *)notification {
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
- 또는 TPKeyboardAvoidingTableView 또는 TPKeyboardAvoidingScrollView와 같은 기성품 솔루션을 사용 하십시오. https://github.com/michaeltyson/TPKeyboardAvoiding
보기에 탭으로 키보드 닫기
키보드 밖에서 탭하여 키보드를 숨기려면이 해킹 트릭을 사용할 수 있습니다 (Objective-C에서만 작동).
- (void)viewDidLoad {
[super viewDidLoad];
// dismiss keyboard when tap outside a text field
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.view action:@selector(endEditing:)];
[tapGestureRecognizer setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:tapGestureRecognizer];
}
Swift에는 더 많은 코드가 있습니다.
override func viewDidLoad() {
super.viewDidLoad()
// dismiss keyboard when tap outside a text field
let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(YourVCName.dismissKeyboard))
view.addGestureRecognizer(tapGestureRecognizer)
}
//Calls this function when the tap is recognized.
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
다른 Swift 3 / iOS 10 예제
class vc: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
txtSomeField.delegate = self
}
}
extension vc: UITextFieldDelegate {
//Hide the keyboard for any text field when the UI is touched outside of the keyboard.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
self.view.endEditing(true) //Hide the keyboard
}
}
맞춤형 인앱 키보드 만들기
기본 인앱 키보드입니다. 같은 방법으로 키보드 레이아웃을 만들 수 있습니다. 다음은 수행해야 할 주요 사항입니다.
- 소유자가
UIView
하위 클래스 인 Swift 또는 Objective-C 클래스 인 .xib 파일에서 자판 배열을 만듭니다. - 사용자 정의 키보드를 사용하도록
UITextField
지시하십시오. - 대리자를 사용하여 키보드와 기본보기 컨트롤러간에 통신합니다.
.xib 자판 배열 파일을 만듭니다.
- Xcode에서 파일> 새로 만들기> 파일 ...> iOS> 사용자 인터페이스>보기 로 이동하여 .xib 파일을 만듭니다.
- 내 Keyboard.xib 전화 했어.
- 필요한 단추를 추가하십시오.
- 자동 레이아웃 제약 조건을 사용하여 키보드의 크기에 관계없이 단추의 크기가 그에 맞게 조정됩니다.
- File 's Owner (루트 뷰가 아닌)를
Keyboard
클래스로 설정합니다. 이것은 일반적인 오류의 원인입니다. 다음 단계에서이 클래스를 만듭니다. 끝에있는 메모를 참조하십시오.
.swift UIView 하위 클래스 키보드 파일 만들기
Xcode에서 File> New> File ...> iOS> Source> Cocoa Touch Class 로 이동하여 Swift 또는 Objective-C 클래스를 만듭니다. 새로 생성 된 클래스의 수퍼 클래스로
UIView
선택나는 내
Keyboard.swift
(Objective-C의Keyboard
클래스)Swift에 다음 코드를 추가합니다.
import UIKit // The view controller will adopt this protocol (delegate) // and thus must contain the keyWasTapped method protocol KeyboardDelegate: class { func keyWasTapped(character: String) } class Keyboard: UIView { // This variable will be set as the view controller so that // the keyboard can send messages to the view controller. weak var delegate: KeyboardDelegate? // MARK:- keyboard initialization required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initializeSubviews() } override init(frame: CGRect) { super.init(frame: frame) initializeSubviews() } func initializeSubviews() { let xibFileName = "Keyboard" // xib extention not included let view = NSBundle.mainBundle().loadNibNamed(xibFileName, owner: self, options: nil)[0] as! UIView self.addSubview(view) view.frame = self.bounds } // MARK:- Button actions from .xib file @IBAction func keyTapped(sender: UIButton) { // When a button is tapped, send that information to the // delegate (ie, the view controller) self.delegate?.keyWasTapped(sender.titleLabel!.text!) // could alternatively send a tag value } }
Objective-C에 다음 코드를 추가합니다.
Keyboard.h 파일
#import <UIKit/UIKit.h> // The view controller will adopt this protocol (delegate) // and thus must contain the keyWasTapped method @protocol KeyboardDelegate<NSObject> - (void)keyWasTapped:(NSString *)character; @end @interface Keyboard : UIView @property (nonatomic, weak) id<KeyboardDelegate> delegate; @end
Keyboard.m 파일
#import "Keyboard.h" @implementation Keyboard - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; [self initializeSubviews]; return self; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; [self initializeSubviews]; return self; } - (void)initializeSubviews { NSString *xibFileName = @"Keyboard"; // xib extention not included UIView *view = [[[NSBundle mainBundle] loadNibNamed:xibFileName owner:self options:nil] firstObject]; [self addSubview:view]; view.frame = self.bounds; } // MARK:- Button actions from .xib file -(IBAction)keyTapped:(UIButton *)sender { // When a button is tapped, send that information to the // delegate (ie, the view controller) [self.delegate keyWasTapped:sender.titleLabel.text]; // could alternatively send a tag value } @end
- .xib 파일의 버튼에서 버튼 콜백까지 Swift 또는 Objective-C 소유자의
@IBAction
메소드로 드래그 액션을 제어하여 모두 연결합니다. - 프로토콜 및 위임 코드에 유의하십시오. 대리인이 작동하는 방법에 대한 간단한 설명은 이 대답 을 참조하십시오.
보기 컨트롤러 설정
메인 스토리 보드에
UITextField
를 추가하고IBOutlet
을 사용하여보기 컨트롤러에 연결하십시오. 그것을textField
합니다.Swift에서 View Controller에 대해 다음 코드를 사용하십시오.
import UIKit class ViewController: UIViewController, KeyboardDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() // initialize custom keyboard let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300)) keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped // replace system keyboard with custom keyboard textField.inputView = keyboardView } // required method for keyboard delegate protocol func keyWasTapped(character: String) { textField.insertText(character) } }
Objective-C에 다음 코드를 사용하십시오.
.h 파일
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
.m 파일
#import "ViewController.h" #import "Keyboard.h" @interface ViewController ()<KeyboardDelegate> @property (nonatomic, weak) IBOutlet UITextField *textField; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // initialize custom keyboard Keyboard *keyboardView = [[Keyboard alloc] initWithFrame:CGRectMake(0, 0, 0, 300)]; keyboardView.delegate = self; // the view controller will be notified by the keyboard whenever a key is tapped // replace system keyboard with custom keyboard self.textField.inputView = keyboardView; } - (void)keyWasTapped:(NSString *)character { [self.textField insertText:character]; } @end
- View Controller는 앞서 정의한
KeyboardDelegate
프로토콜을 사용합니다.
일반적인 오류
EXC_BAD_ACCESS
오류가 발생하는 것은 nib File 's Owner 에서처럼보기의 사용자 정의 클래스를 Keyboard
로 설정했기 때문일 수 있습니다.
Keyboard.nib
을 선택한 다음 파일 소유자를 선택하십시오.
루트보기의 사용자 정의 클래스가 비어 있는지 확인하십시오.
노트
이 예제는 원래이 스택 오버플로 응답 에서옵니다.
싱글 톤 + 델리게이트를 사용하여 키보드 관리하기
키보드 관리를 처음 시작할 때 각 ViewController에서 별도의 알림을 사용했습니다.
알림 방법 (NSNotification 사용) :
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardNotification(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
}
func keyboardNotification(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
let duration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseOut.rawValue
let animationCurve: UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrame?.origin.y >= UIScreen.mainScreen().bounds.size.height {
lowerViewBottomConstraint.constant = 0
} else {
lowerViewBottomConstraint.constant = endFrame?.size.height ?? 0.0
}
view.animateConstraintWithDuration(duration, delay: NSTimeInterval(0), options: animationCurve, completion: nil)
}
}
내 문제는 내가 하나의 ViewController마다이 코드를 반복해서 쓰는 것을 발견했다는 것이다. 조금 실험 한 후 Singleton + Delegate 패턴을 사용하여 많은 코드를 재사용하고 모든 키보드 관리를 한 곳에서 구성 할 수있었습니다!
싱글 톤 + 위임 방법 :
protocol KeyboardManagerDelegate: class {
func keyboardWillChangeFrame(endFrame: CGRect?, duration: NSTimeInterval, animationCurve: UIViewAnimationOptions)
}
class KeyboardManager {
weak var delegate: KeyboardManagerDelegate?
class var sharedInstance: KeyboardManager {
struct Singleton {
static let instance = KeyboardManager()
}
return Singleton.instance
}
init() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KeyboardManager.keyboardWillChangeFrameNotification(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
}
@objc func keyboardWillChangeFrameNotification(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
let duration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseOut.rawValue
let animationCurve: UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
delegate?.keyboardWillChangeFrame(endFrame, duration: duration, animationCurve: animationCurve)
}
}
이제 ViewController에서 키보드를 관리하려면 해당 ViewController에 대한 대리자를 설정하고 모든 대리자 메서드를 구현해야합니다.
class ViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
KeyboardManager.sharedInstance.delegate = self
}
}
// MARK: - Keyboard Manager
extension ViewController: KeyboardManagerDelegate {
func keyboardWillChangeFrame(endFrame: CGRect?, duration: NSTimeInterval, animationCurve: UIViewAnimationOptions) {
if endFrame?.origin.y >= UIScreen.mainScreen().bounds.size.height {
lowerViewBottomConstraint.constant = 0
} else {
lowerViewBottomConstraint.constant = (endFrame?.size.height ?? 0.0)
}
view.animateConstraintWithDuration(duration, delay: NSTimeInterval(0), options: animationCurve, completion: nil)
}
}
이 방법은 매우 사용자 정의 할 수 있습니다! UIKeyboardWillHideNotification
대한 기능을 추가하고 싶다고 UIKeyboardWillHideNotification
. 이것은 KeyboardManagerDelegate
메소드를 추가하는 것만큼이나 쉽습니다.
KeyboardManagerDelegate
와 UIKeyboardWillHideNotification
:
protocol KeyboardManagerDelegate: class {
func keyboardWillChangeFrame(endFrame: CGRect?, duration: NSTimeInterval, animationCurve: UIViewAnimationOptions)
func keyboardWillHide(notificationUserInfo: [NSObject: AnyObject])
}
class KeyboardManager {
init() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KeyboardManager.keyboardWillChangeFrameNotification(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KeyboardManager.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillHide(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
delegate?.keyboardWillHide(userInfo)
}
}
하나의 ViewController에 func keyboardWillHide(notificationUserInfo: [NSObject: AnyObject])
만 구현하려고한다고 가정 func keyboardWillHide(notificationUserInfo: [NSObject: AnyObject])
. 이 방법을 선택적으로 만들 수도 있습니다.
typealias KeyboardManagerDelegate = protocol<KeyboardManagerModel, KeyboardManagerConfigureable>
protocol KeyboardManagerModel: class {
func keyboardWillChangeFrame(endFrame: CGRect?, duration: NSTimeInterval, animationCurve: UIViewAnimationOptions)
}
@objc protocol KeyboardManagerConfigureable {
optional func keyboardWillHide(userInfo: [NSObject: AnyObject])
}
*이 패턴은 @objc
남용을 피하는 데 도움이됩니다. 자세한 내용은 http://www.jessesquires.com/avoiding-objc-in-swift/ 를 참조하십시오!
요약하면, Singleton + Delegate를 사용하여 키보드를 관리하는 것이 알림을 사용하는 것보다 효율적이고 사용하기 쉽다는 것을 알았습니다.
키보드가있을 때 위 또는 아래로보기 이동
참고 : 이 기능은 iOS에서 제공하는 내장 키보드에서만 작동합니다.
빠른:
UIViewController 의 뷰가 표시 될 때 프레임의 원점을 늘리고 숨겨진 경우 축소 시키려면 클래스에 다음 함수를 추가합니다.
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
그리고 클래스의 viewDidLoad()
메서드에서 다음 옵저버를 추가합니다.
NotificationCenter.default.addObserver(self, selector: #selector(Login.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(Login.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
그리고 이것은 키보드의 height 속성을 사용하여 모든 화면 크기에서 작동합니다.
목표 -C :
Objective-C에서 같은 작업을 수행하기 위해이 코드를 사용할 수 있습니다.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height;
self.view.frame = f;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}