Today 5/21-5/24
Info.plist
→ Scene Configuration → StoryboardName 탭 아예 삭제guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene) // SceneDelegate의 프로퍼티에 설정해줌
let mainViewController = ViewController() // 맨 처음 보여줄 ViewController
window?.rootViewController = mainViewController
window?.makeKeyAndVisible()
info.plist에서 StoryboardName을 삭제해야하는 이유
AppDelegate의 @main 함수가 Info.plis에서 storyboard의 이름을 참고하여 값이 있다면 시작 viewController로 인스턴스화 하기 때문
[iOS][Swift] - 스토리보드 없이 코드로만 UI 구현하기 (SceneDelegate에서 window설정)
UI 그려보기
UILable
let test = UILabel()
view.backgroundColor = .white // 배경색
view.addSubview(test)
test.text = "text" // test를 위해서 출력할 라벨
test.translatesAutoresizingMaskIntoConstraints = false
test.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
test.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
navigationController
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let mainViewController = ViewController()
let navigationController = UINavigationController(rootViewController: mainViewController)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
로그인 여부에 따라 달라지는 rootViewController
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let userHasLoggedIn: Bool = true
//Login 안헀을 때 VC
let startViewController = StartViewController()
//Login 했을 때 VC
let homeViewController = HomeViewController()
let startVC = userHasLoggedIn ? homeViewController : startViewController
window?.rootViewController = startVC
window?.makeKeyAndVisible()
[iOS]View의 형성과정(window, rootView, Main함수, Appdelegate)
코드로 하니까 스토리보드 사용해도 똑같았던 것들도 생소하게 느껴져서 폰트 넣는 것도 조금 버벅였는데, 서체관리자에서 Finde로 폰트 찾을 때 폰트 그룹 선택하면 bold, regular ... 하나하나 넣지 않아도 한 번에 적용된다. 폰트 이름 찾고싶을 때에는
for family in UIFont.familyNames {
print(family)
for sub in UIFont.fontNames(forFamilyName: family) {
print("====> \(sub)")
}
}
로 설치된 모든 폰트와 패밀리를 출력할 수 있고, 원하는 하나만 찾을 때는
for sub in UIFont.fontNames(forFamilyName: "SF Pro") {
print("====> \(sub)")
}
로 쉽게 출력할 수 있다.
폰트 넣을 때에는 Add Target 꼭 체크하자
info.plist - Fonts provided by application에 확장자까지 잘 추가하자
보통 코드로 뷰를 그릴 때, 이런 식으로 클로져를 통해 생성하고 실행한다.
lazy var startButton: UIButton = {
let button = UIButton()
button.backgroundColor = Colors.Semantic.mdocBlue
button.setTitle("시작하기", for: .normal)
button.titleLabel?.font = UIFont(font: FontFamily.SFProText.regular, size: 16)
button.titleLabel?.textColor = Colors.Layout.I0
button.addTarget(self, action: #selector(didTabButton), for: .touchUpInside)
return button
}()
하지만 이 방법은 한 element를 구성할 때마다 안에서 계속 지역변수를 만들어주고 return해줘야 해서 비효율적이라 생각하고 있었는데, Then 라이브러리를 사용하면 깔끔하고 간소화한 코드를 작성할 수 있었다!
lazy var startButton = UIButton().then {
$0.backgroundColor = Colors.Semantic.mdocBlue
$0.setTitle("시작하기", for: .normal)
$0.titleLabel?.font = UIFont(font: FontFamily.SFProText.regular, size: 16)
$0.titleLabel?.textColor = Colors.Layout.I0
$0.addTarget(self, action: #selector(didTabButton), for: .touchUpInside)
}
Snapkit은 Then과 마찬가지로 코드를 간결하게 쓸 수 있도록 도와준다.
Then은 인스턴스를 만드는데에 도움을 준다면, Snapkit은 AutoLayout을 짤 때 도움을 준다.
mdocLogo.translatesAutoresizingMaskIntoConstraints = false
mdocLogo.heightAnchor.constraint(equalToConstant: 96).isActive = true
mdocLogo.widthAnchor.constraint(equalToConstant: 200).isActive = true
mdocLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
mdocLogo.topAnchor.constraint(equalTo: view.topAnchor, constant: 60*UIScreen.main.bounds.width/100).isActive = true
AutoLayout을 설정할 때 항상 이와 같이 작성을 하는데, 반복된 함수들이 너무 복잡하게 느껴진다.
mdocLogo.snp.makeConstraints { make in
make.height.equalTo(96)
make.width.equalTo(200)
make.centerX.equalToSuperview()
make.top.equalToSuperview().inset(60*screenSize.width/100)
}
이럴 떄 Snapkit을 활용해서 하나의 클로저로 AutoLayout들을 한 묶음으로 만들어줄 수 있어서 좋고, make같은 매개변수를 이용해서 너무나 간결하게 코드를 단축시킬 수 있다.
translatesAutoresizingMaskIntoConstraints = false?
내부에서 정의해줘서 반복되는 autorizingMask꺼두는 작업을 하지 않아도 된다.
offset & inset의 차이
offset은 항상 superview기준이라고 생각하면 된다. superview에서 오른쪽으면 +, 왼쪽이면 -의 값을 갖는다.
inset은 UIEdgeInsets와 같이 edge기준으로 안으로 얼마나 떨어져 있는지를 나타낸다.
box.snp.remakeConstraints { make in
make.top.left.bottom.right.equalToSuperview().inset(50)
}
또한 이렇게 나타낼 수도 있고,
box.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(50)
}
edges를 사용해서 이렇게 하나로 나타낼 수도 있다.
left & leading의 차이
leading, trailing의 경우, right-to-left의 문화권의 경우 화면이 flip되어 나타난다.
하지만, left & right는 모든 문화권에서 같은 의미를 가지므로 같은 ui를 그릴 수 있다.
Constraint의 변수화
@IBOutlet으로 Constraint를 변수화해서 사용하고 싶은 곳에서 값을 변경해 사용할 수 있는데, snapkit에서도 이같은 작업이 가능하다. uninstall로 초기화한 다음 updateOffset으로 값을 변경해줄 수 있다.
var topConstraint: Constraint? = nil
view.snp.makeConstraints { make in
self.topConstraint = make.top.equalTo(superview).offset(padding.top)
}
self.topConstraint.uninstall()
self.topConstraint.updateOffest(5)
혹은 아예 updateConstraints를 사용해서 이렇게 가능하다.
box.snp.makeConstraints { maker in
maker.top.bottom.left.right.equalToSuperview()
}
box.snp.updateConstraints { maker in
maker.top.equalToSuperview().offset(100)
}
ios 15이상부터 TabBar에 있었던 divider(shadow)가 사라지고 default 또한 translucent가 되었다.
하지만 반대로 지금 쓰려는 디자인이 divider가 필요한 디자인이어서 새로 divider를 살려야 했다...
tabBar.layer.borderWidth = 1
tabBar.layer.borderColor = Colors.Layout.I20.cgColor
layer로 접근해서 border값을 바꾸어주면 되는 일이었는데 바꾸다가 cgColor와 UIColor의 차이점이 문득 궁금해졌다.
간단하게 말해서 cgGraphics에 속해있는 layer을 통해 접근할 수 있는 색상에 대하여는 cgColor, UIkit을 통한 윗단계의 UI수정에 대해서는 UIColor를 사용해야하는 것 같았다.