ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • iOS) Storyboard 없이 개발하기
    iOS 2019. 5. 9. 10:44

     

    개인적으로 공부하며 정리하는 블로그 입니다.
    오류나 부족한 부분이 있을 수 있으니 감안하고 봐주시고 아낌없는 조언 감사드립니다 ^^
    iOS13 버전에 맞춘 개정판을 posting 하였습니다 :) 

     

    iOS는 스토리보드, xib, 코드 크게 3가지 방법을 사용해 개발 할 수 있습니다.

    이중에서 Storyboard를 사용해 쉽게 만들 수 있고, 저도 가장 먼저 Storyboard를 사용하는 법을 익히고 배웠습니다.

     

    하지만 이 3가지 방법 중 기본이 되는 것은 당연히 코드 입니다.

     

    사실 storyboard도 편리하게 사용할 수 도구일뿐, 내부적으로는 코드로 이루어져 있겠죠?

    실제로 현업에서는 회사마다 다양하게 사용하고 계시는 것 같더라구요!

    운이 좋아 storyboard를 사용하는 회사에 가게 된다면 다행이지만...

    코드로 작성할 수 있으면 storyboard나 다른 방식으로는 쉽게 구현이 가능하지만,

    반대의 경우는 좀 더 힘이 들겠구나.. 라는 생각이 들었습니다.

     

    그래서 앞으로는 코드로 개발해보고자 해서 이번에 제대로 한번 정리해볼까 합니다!

     

    이번엔 간단하게 폰트를 바꿔볼 수 있는 Custom Font 앱을 만들어보겠습니다.

    재밌겠죠?

    (네.. 대답은 기대하지 않았습니다 .. )

    그럼 시작해보겠습니다 !

     

    1. AppDelegate.swift 설정

    네 처음 프로젝트를 생성하면 Main.storyboard를 기본적으로 사용하게 되어있어요.

    때문에 코드를 사용하기 위해 간단하게 설정을 해줘야 합니다. 

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
          window = UIWindow(frame: UIScreen.main.bounds)
          window?.makeKeyAndVisible()
          window?.rootViewController = UINavigationController(rootViewController: ViewController())
          
          return true
    
      }

     

    보시면 아시겠지만 

    기본 화면이 되는 window를 만든 후,

    makeKeyAndVisibil()은 화면에서 키보드 입력을 받을 수 있게하는 코드구요,

    ViewController를 rootVC로 사용하겠다는 코드죠.

    이렇게 되면 기본 작업은 끝났습니다!

     

    2. ViewController에 TextField 올리기 

    다음으로 TextField를 한번 넣어보겠습니다. 

    그럼 이제 ViewController의 ViewDidLoad()로 가서 TextField를 한번 붙여볼까요?

    let textView = UITextView()
    view.addSubview(textView)
    

     

    네 실행해보면 아무것도 안 나옵니다 ㅎㅎ 

    왜냐하면 textView의 크기를 지정해 주지 않았기 때문입니다.

     

    우선 자율적으로 layout을 지정해 주기 위해서는 translatesAutoresizingMaskIntoConstraints을 false로 지정해 줘야 합니다.

    이 속성이 true로 되어있으면 뷰의 자동조정 마스크로 인해 크기와 위치가 지정되므로

    constraint를 걸어줬을 때 충돌이 일어나게 된다고 합니다! 

     

    translatesAutoresizingMaskIntoConstraints를 false로 주고 width와 height를 지정해주겠습니다.

    textView.translatesAutoresizingMaskIntoConstraints = false     
    textView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    textView.heightAnchor.constraint(equalToConstant: 100).isActive = true

    네 생성은 됐지만 위치가.... 

    여기서 잠깐! swift의 기본 좌표 개념을 짚어보고 넘어가겠습니다. 

     

     

    네 그림처럼 iOS의 좌표체계는 왼쪽상단이 기준점(0,0) 입니다. 여기서 화살표 방향으로 점점 커지는 것이죠.

    따라서 아무런 위치도 주지않고 단순히 크기만 지정해줬을 땐 (0,0) 위치에 생기게 되는 것 입니다.

     

    그럼 이제 위치를 제대로 한번 잡아볼까요? 

     

    저는 센터에 놓고 양쪽에 간격을 조금 줘볼까해요.

    textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    textView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 50).isActive = true
    textView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -50).isActive = true

     

    자 이렇게 하면 정상적으로 가운데로 위치하는 것을 확인하실 수 있습니다!

    (참, 이때 isActive를 해주는 것을 잊지마세요.. ㅠㅠ)

    네 말 나온김에 이렇게 매번 isActive를 해주기 정말 귀찮으시죠? 해결해보겠습니다. 

    제가 아는 방법은 크게 2가지가 있어요

    1. NSLayoutConstraint.activate(constraints: [NSLayoutconstraint]) 사용

     NSLayoutConstraint.activate([
                textView.widthAnchor.constraint(equalToConstant: 100),
                textView.heightAnchor.constraint(equalToConstant: 100),
                textView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                textView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
                textView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 50),
                textView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -50),
                ])

    2. foreach 사용

    [
        textView.widthAnchor.constraint(equalToConstant: 100),
        textView.heightAnchor.constraint(equalToConstant: 100),
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        textView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 50),
        textView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -50),
    ].forEach({$0.isActive = true})

    여러 검색을 해보다 알게된 방법들인데요. 둘다 딱히 코드 길이에는 상관이 없기에 편하신 대로 사용하시면 될 것 같습니다! 

     

    아무튼 귀찮은 isActive까지 해결했으니 깔끔하게 코드를 분리해봅시다.

     

     let customTextView: UITextView = {
        let textView = UITextView()
        textView.layer.borderWidth = 1.0
        textView.translatesAutoresizingMaskIntoConstraints = false
    
        return textView
    }()
    
    ...
    
    func setCustomTextView(_ textView: UITextView) {
        NSLayoutConstraint.activate([
            textView.widthAnchor.constraint(equalToConstant: 100),
            textView.heightAnchor.constraint(equalToConstant: 100),
            textView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            textView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            textView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 50),
            textView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -50),
        ])
    }

    저는 이런식으로 나눠서 분리해봤어요

     

    3. 버튼 추가하기

    let changeButton: UIButton = {
       let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Change Font", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        button.setTitleColor(UIColor.white, for: .highlighted)
    
        return button
    }()
    
    ...
    
    func setChangeButton(_ button: UIButton) {
            NSLayoutConstraint.activate([
                button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                button.heightAnchor.constraint(equalToConstant: 50),
                button.topAnchor.constraint(equalTo: customTextView.bottomAnchor, constant: 50)
                ])
        }
    

     

    버튼도 같은 방식으로 만들었습니다. 코드를 보시면 어렵지 않게 이해하실 수있으실거에요. 

     

    4. TextView Customizing

    이제 TextView를 글자에 맞게 길이가 변하도록 고쳐보겠습니다. 

    TextField가 아닌 TextView를 쓴 이유도 여기에 있는데요,

    TextField는 1줄만 입력이 가능해서 여러줄을 입력하고 싶다면 TextView를 커스터마이징 해야합니다!

     

    제가 찾은 방법은 textView의 Delegate에서 처리해주는 방법인데요, 다음과 같이 extension으로 처리했습니다.

    Brian Voong님 항상 감사합니다.

    extension UIViewController: UITextViewDelegate {
        
        public func textViewDidChange(_ textView: UITextView) {
            let size = CGSize(width: textView.frame.width, height: .infinity)
            let estimatedSize = textView.sizeThatFits(size)
            
            textView.constraints.forEach { (constraint) in
                if constraint.firstAttribute == .height {
                    constraint.constant = estimatedSize.height
                }
            }
        }
    }

     

    5. Font Change

    저는 간단하게 Font를 몇개 정하고 버튼을 누를때마다 랜덤으로 선택해 TextView의 text를 바꾸는 방식을 사용했습니다.

    (매우 허접하지만 이 글의 핵심은 이게 아니니깐요...!)

     

    let fonts = ["kefa", "papyrus", "zapfino", "bradleyHand"]
    
    ...
    
    let changeButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Change Font", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        button.setTitleColor(UIColor.white, for: .highlighted)
        button.addTarget(self, action: #selector(changeButtonTapped), for: .touchUpInside)
    
        return button
    }()
    
    @objc
    func changeButtonTapped(sender: UIButton) {
        if let font = fonts.randomElement() {
            customTextView.font = UIFont.init(name: font, size: 25)
        }
    }

     

    긴 글 읽어주셔서 감사합니다 ^^

    조금이라도 도움이 되셨다면 좋겠습니다.

    전체 프로젝트는 여기서 확인하실 수 있습니다!

    'iOS' 카테고리의 다른 글

    iOS) Status Bar, Navigation Bar 바꾸기  (0) 2019.06.07
    iOS) Core Data Tutorial  (0) 2019.05.13
    iOS) Gradient 구현하기  (3) 2019.05.12
    iOS) Carousel 구현하기  (4) 2019.05.12
    iOS) Singleton 패턴  (0) 2019.05.08

    댓글

Designed by Tistory.