반응형

iOS 앱을 만들다 보면 가장 처음 접하게 되는 문제가 이 키보드 가림 문제이다.
보통 책이나 웹상에 떠도는 소스들을 보다보면 매우 간단하게 UITextFiled 하나만 배치하여 키보드가 나타나면 뷰를 올려주고 키보드가 내려가면 다시 뷰를 내려주는 단순한 상황만 언급할 뿐 실제 현업에서 발생 가능한 UITextField가 여러개일 때
즉 상단에 위치한 UITextField컨트롤은 키보드가 보여줘도 그대로 놔둬야 하고 하단에 위치한 UITextField 컨트롤은 키보드만큼 올려줘야 하는 상황에 대해 제대로 해결책을 제시하는 글은 찾기 힘들다.
오늘 소개할 이 방법 말고도 여러 방법들이 있겠지만 초보자도 쉽게 따라할 수 있는 방법을 택하여 소개하고자 한다.

대략 순서는 이러하다.
1. viewDidLoad에서 UITextField Delegate  연결 
2. viewDidLoad에서 NotificationCenter를 이용하여 Observer 등록 : 키보드 Show, Hide 이벤트 확인
3. UITextField가 키보드에 가려졌는지 확인을 위한 해당 컨트롤의 위치좌표(Y) 확인
4. 가려졌다면 뷰 이동 O, 안가려졌다면 뷰 이동 X
5. 모든 작업 종료 후 viewWillDisappear에서 2번에서 등록했던 Observer 제거

입력 전 화면
첫번째 컨트롤에 포커스 된 화면(키보드가 가려지지 않으므로 뷰 이동 X)
두번째 컨트롤에 포커스 된 화면(키보드가 가려졌으므로 뷰 이동 O)
세번째 컨트롤에 포커스 된 화면(키보드가 내려간 상태였다면 뷰 이동이 되어야 하지만 이미 키보드가 올라온 상태이므로 뷰 이동 X)

1. TextField의 처리를 위해 UITextFieldDelegate 프로토콜 추가
(이후 TextField 컨트롤은 편의상 컨트롤이라 칭함)
class
MyViewController: UIViewController, UITextFieldDelegate {
}

2. 컨트롤 변수와 컨트롤을 연결(너무 기초라 패스)
위에서부터 순서대로 txtTmp, txtId, txtPw
    @IBOutlet weak var txtTmp: UITextField!
    @IBOutlet weak var txtId: UITextField!
    @IBOutlet weak var txtPw: UITextField!

3. viewDidLoad()에서 컨트롤 변수의 delegate 연결 및 키보드를 내리기 위해 완료 버튼(done)을 추가해준다.
        txtTmp.delegate = self
        txtId.delegate = self
        txtPw.delegate = self

        txtTmp.returnKeyType = .done
        txtId.returnKeyType = .done
        txtPw.returnKeyType = .done

4. 키보드가 올라왔나 내려갔나 확인을 위해 NotificationCenter로 Observer 등록        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
이렇게 구현하면 keyboardWillShow, Hide가 없다고 에러가 뜰텐데 원칙상 선 구현 후 정의를 내려야 하지만 편의상 그냥 구현한다.

5. 키보드가 올라왔을 때 컨트롤이 키보드에 가려졌을 때 뷰를 그만큼 올려주는 처리와 내려갔을 때 뷰의 위치를 다시 되돌려 놓는 처리 그리고 지금 컨트롤이 키보드에 가려졌는지 안가려졌는지 확인을 위한 처리 구현

먼저 키보드가 컨트롤을 가렸는지 확인을 위해 변수 하나를 실수형으로 선언한다.
    var
fCurTextfieldBottom: CGFloat = 0.0

현재 포커싱된 컨트롤의 좌표를 구하기 위해 textFieldDidBeginEditing에서 현재 컨트롤의 y좌표와 해당 컨트롤의 높이를 더하면 나중에 키보드에 의해 가려졌는지 확인이 가능하므로 계산 후 일단 보관해둔다.
    func textFieldDidBeginEditing(_ textField: UITextField) {        
        fCurTextfieldBottom = textField.frame.origin.y + textField.frame.height    
    }

이제 4번에서 등록한 selector함수인 키보드가 나타났을 때와 내려갔을 때 함수를 구현한다.
키보드의 사이즈(구조체)를 keyboardSize에 보관 후 현재뷰의 높이에서 빼주면 키보드가 잡아먹는 정확한 위치를 알 수 있다.
이를 앞서 계산해 보관해둔 fCurTextfieldBottom와 비교하여 fCurTextfieldBottom가 작거나 같으면 가려지지 않았으니 무시하고 크다면 1px이라도 가려졌으므로 현재 뷰를 키보드가 잡아먹는 높이만큼 올려주면 된다.
    @objc func keyboardWillShow(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if fCurTextfieldBottom <= self.view.frame.height - keyboardSize.height {
                return
            }
            if self.view.frame.origin.y == 0 {
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
    }

키보드가 사라졌을 땐 간단하다.
그냥 뷰가 이동됐으면 다시 원상복구해주고 아니면 아무런 처리를 하지 않는다.
    @objc func keyboardWillHide(notification: NSNotification) {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y = 0
        }
    }

앞서 추가했던 done의 처리도 해주어 키보드가 내려가게끔 구현해준다.
    func textFieldShouldReturn(_ textField: UITextField) -> Bool
         textField.resignFirstResponder()
         return true
     }

이렇게만 해두면 기본적인 처리는 다 되었고 만약 완료버튼(done) 대신 뷰의 아무곳이나 터치했을 때 키보드가 내려가길 원한다면
viewDidLoad에 제스쳐를 등록 후 
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(endEditing)))

관련 함수를 구현해주면 깔끔하게 처리가 가능하겠다.
   
@objc func endEditing() {
        txtTmp.resignFirstResponder()
        txtId.resignFirstResponder()
        txtPw.resignFirstResponder()
    }

 

반응형
Posted by Hippalus
,

반응형

- (void)viewDidLoad {
     [super viewDidLoad];

     
UIView *view = [UIView new];
     view.backgroundColor = [UIColor redColor];

     
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
     [self.view addSubview:view];
     
     NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:100];

     NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:100];

     NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];

     NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];

     [self.view addConstraints:@[left, top]];
     [view addConstraints:@[height, width]];
}


width에 constant를 뷰의 넓이와 동일하게 한다면
CGRect rcData = [[UIScreen mainScreen] bounds];
     NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:rcData.size.width];


반응형
Posted by Hippalus
,

반응형

vue.js를 설치하기 위해선 npm을 통해 설치하여야 하지만 npm을 이용하기 위해선 또 brew를 선설치하여야 한다.
brew.sh/index_ko로 이동해보면 아래와 같이 친절하게 터미널 명령어가 존재하는데 이를 복사하여 터미널에 붙여넣기 후 엔터를 친다.

Homebrew 홈페이지

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

그럼 sudo 권한을 위해 아이맥 비밀번호를 물어보고 이를 입력하면 한참을 다운로드에서 머물다 설치가 마무리 된다.
대략 20분 이상 걸린것 같다.(회사라 느린것인지 모름)

Terminal Homebrew 설치화면

Homebrew가 설치 되었다면 이제 node를 설치한다.
터미널에서 brew install node 를 입력하고 엔터

node 설치화면

npm이 설치되었으니 이제 본격적인 vue cli 설치를 진행한다.
터미널에서 npm install -g @vue/cli 를 입력하고 엔터
(CLI란 뷰 프로젝트를 빠르게 개발하고 빌드하고 서비스를 런칭시켜주는 틀)

다른 설치파일들과 달리 1~2분 이내로 금방 설치가 완료 된다.

vue 설치 완료 화면

기본 설치까지 모두 완료 되었으므로 이제 실제 vue 프로젝트를 생성해보도록 한다.
프로젝트 생성방법은 터미널에서 vue create 폴더명이므로
vue create test 입력 후 엔터

참고로 화살표키로 다른 기본 설치와 매뉴얼 설치를 선택할 수 있다.

기본 옵션설치이므로 default에서 엔터 설치

default 그대로 설치 진행 중 화면


프로젝트 설치가 완료되면 아래와 같이 생성된 프로젝트를 실행해 볼 수 있도록 친절히 안내가 나온다.
(node.js를 경험해봤다면 익숙한 방식이다.)

🎉  Successfully created project test.
👉  Get started with the following commands:
 $ cd test
 $ npm run serve

실제 ls 명령어를 통해 폴더를 확인해보면 test란 폴더가 생성되어 있고

우측 끝에 test란 폴더가 보임

cd 명령어를 통해 이동해보면 아래와 같은 구조로 프로젝트가 생성되어 있음을 알 수 있다.
test
    src
        App.vue
        assets
        components
        main.js

생성된 프로젝트를 실행하고 실제 브라우저에서 접속해보도록 한다.
먼저 프로젝트 폴더로 이동하기 위해 터미널에서 
$ cd test 입력 후 엔터

그리고 npm을 통해 프로젝트를 실행하기 위해 터미널에서 
$ npm run serve 입력 후 엔터를 치면 정상설치가 되었을 경우 아래처럼 친절하게 접속 가능한 주소를 알려준다.

App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://000.000.000.000:8080/
  Note that the development build is not optimized.
  To create a production build, run npm run build.

아무 브라우저나 열고 위 주소를 입력해보자

test로 생성해본 프로젝트 웹 접속 화면

여기까지 간단하게 처음 npm 설치부터 vue 테스트 프로젝트 설치 및 접속까지 알아보았다.

반응형
Posted by Hippalus
,