일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- native flutter view
- Flutter UIKitView MethodChannel
- swift 문자
- FlutterView MethodChannel
- 안드로이드 바로가기
- 스위프트
- 스위프트 UserDefaults
- Swift flutterviewcontroller
- flutter rotate
- flutter 회전
- swift sms
- 앱 백그라운드 푸시 데이터 저장
- silent push
- 푸시 데이터 저장
- swift autolayout
- 안드로이드 에러
- NotificationService Extension
- 안드로이드 앨범
- 노티피케이션 익스텐션
- 안드로이드 숏컷
- Flutter NativeView
- 스위프트 푸시
- Swift flutterview
- 스위프트 카메라
- 플러터 뷰 컨트롤러
- 스위프트 테이블 뷰 셀
- 안드로이드 FCM
- 스위프트 웹뷰
- 앱 꺼졌을 때 푸시 데이터 저장
- 스위프트 앨범
- Today
- Total
Things take time
[SWIFT] Static Cell을 사용하는 테이블 뷰의 커스터마이징(뷰 추가하기) 본문
[개요]
제목만으로는 헛갈리는 내용이다.
간략히 설명하면
iOS의 테이블 뷰 안에 들어가는 Cell은 두 가지 타입이 존재한다.
Static / Dynamic
뜻은 다 알것이고, 간략히 스토리보드상에서 UI의 대부분을 그려야할 때, 데이터가 크게 변하지 않을때(물론 변하더라도 static에서 조정 가능) 사용하며, Dynamic은 일반적으로 책에서 소개하는 테이블 뷰 셀이다.
그리고 static은 section이라는 부분이 있어서, 테이블 뷰의 셀들을 관리하는 그 상위의 영역이 존재한다.
즉, 1개의 테이블에는 1개 이상의 섹션이 존재하며, 각 섹션은 1개 이상의 셀을 포함하고 있다. 그러므로 셀들의 공통집합들을 섹션으로 구분하고, 이 섹션의 집합이 테이블 뷰가 되는 것이다.
dynamic은 하나의 테이블 뷰에는 1개이상의 셀로만 구성되어있다.
그리고 결론과 마찬가지 이지만, static cell을 사용할 수 있는 것은 해당 테이블뷰가 포함된 뷰 컨트롤러는 UITableViewController를 상속받아아야한다. 즉, 일반적인 UIViewController를 상속받는 일반 뷰 컨트롤러에서는 static cell을 가진 테이블 뷰를 사용할 수없다!
[문제]
static cell로 사용하고 있던 UITableViewController를 상속받는 컨트롤러의 UI가 변경되었다.
해당 화면 전체는 당연히 모두 테이블 뷰로 이루어진 화면이었으나, 테이블 뷰 하단에 고정된 영역이 필요하다는 것이었다. (스크롤을 해도 영향을 받지않는 fixed view)
구글링을 통해 열심 열심히 알아본결과 해당 테이블 뷰의 Footer영역을 고정시킬 수 있는 방법, 혹은 또 다른 뷰를 넣어 고정시키는 방법 등을 조사했으나, 결론은 둘다 안 됨. 이유는 위에서 설명한 것과 같았다.
그래서 하는 수 없이 새로 뷰 컨트롤러를 생성하여 테이블 뷰 하나와 하단에는 UIView를 넣어 코드를 작성하기 시작했다. 그러나 이미 만들어진 뷰를 다시 재작성하기엔 너무 작업량이 방대했다.
스토리보드에만 작성한 각 Section별 Cell을 모두 커스터마이징하여 각각의 cell로 만들어서 작업해야 했고, UI, Constaraint 등 생각할게 많았다.
그래서 다시 또 열심히 알아본 결과, 기존 static cell을 사용하는 소스코드의 viewDidLoad에 아래의 화면을 추가하고 마무리 지었다.
[소스]
weak var _staticView: UIView?
전역으로 사용할 _staticView를 선언한다.
override func viewDidLoad() { super.viewDidLoad() // bounds : 현재 뷰의 경계 사이즈, origin을 찍으면 0부터 시작 / frame : 현재 뷰의 superview에서 상대, origin을 찍으면 superview에서 위치한 값부터 시작 // tableView의 frame은 self.view.frame과 같음 (테이블 뷰 컨트롤러를 상속받는 뷰 컨트롤러기 때문) // 70 = 50(사이즈) + 20(TopLayoutGuide) let tableViewHeight = self.tableView.frame.height let tableViewWidth = self.tableView.frame.width let staticView = UIView(frame: CGRect(x: 0, y: tableViewHeight - 70, width: tableViewWidth * 0.8, height: 50)) staticView.backgroundColor = UIColor.white let ivQuit = UIImageView(frame: CGRect(x: 0, y: staticView.frame.height - 50, width: 50, height: 50)) ivQuit.image = UIImage(named: "Set_Logout") let ivSetting = UIImageView(frame: CGRect(x: staticView.frame.width - 50, y: staticView.frame.height - 50, width: 50, height: 50)) ivSetting.image = UIImage(named: "Setting_On") ivQuit.isUserInteractionEnabled = true ivSetting.isUserInteractionEnabled = true ivSetting.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(moveSetting))) ivQuit.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(quitView))) staticView.addSubview(ivQuit) staticView.addSubview(ivSetting) self.tableView.addSubview(staticView) // 전역 선언 self._staticView = staticView // contentInset : 현재 스크롤 뷰와 그 안에 있는 콘텐츠 뷰 사이의 거리(top, left, bottom, right) // contentOffSet : 현재 스크롤 뷰 안에 있는 콘텐츠 뷰가 가진 현재 위치(x,y) // 현재 테이블 뷰 의 bottom(3번째 파라미터)의 값을 +80으로 하겠다는 의미(staticView가 올라갔으니 스크롤을 끝까지 했을때 하단 것도 보이기 위함) self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 70, 0) // 스크롤의 위치 (해당 위치만큼 재조정해야 테이블 뷰 내의 스크롤의 위치가 정상적으로 잡힘) self.tableView.scrollIndicatorInsets = self.tableView.contentInset }
staticView라는 UIView는 현재 테이블 뷰의 크기를 기준으로 frame값을 할당하였다.
나 같은경우에는 현재 테이블 뷰 자체가 컨테이너 뷰 안에 들어있어, 컨테이너 뷰 안에 제약조건이 걸린 상태이기 때문에 또 값을 계산하였다 (0.8 곱하기 같은.. 아래 스크린샷 참고)
어쨌든 위의 소스는 필요한 크기만큼의 뷰를 생성하여 테이블 뷰안에 넣었다. 그리고 contentInset을 통해 테이블 뷰 안에들어가는 콘텐츠들의 마진, 거리 값을 bottom부분만 위로 70으로 조정했으며, 그에 따라 스크롤할 때 보이는 우측의 스크롤위치도 조정해주었다.
override func scrollViewDidScroll(_ scrollView: UIScrollView) { _staticView?.transform = CGAffineTransform(translationX: 0, y: scrollView.contentOffset.y) } override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { self.tableView.bringSubview(toFront: _staticView!) }
그리고 스크롤을 할때마다 staticView는 하단에 고정되어야하므로, 현재 스크롤뷰 안에있는 데이터들의 위치 중 y의 값만큼을 staticView가 이동하게 했다.
그리고 아래의 willDisPlay는 cell이 보여질때마다 호출되는 함수로 staticView가 무조건 앞에 나오라는 의미의 코드 한 줄을 추가했다.
** 참고
나의 경우에는 위 처럼 패널을 오픈했을 때, 화면의 80%만을 차지하는 컨테이너뷰와 그 안에 테이블뷰컨트롤러를 상속받는 뷰 컨트롤러를 넣었기 때문에, 아래 staticView의 크기를 계산할 때는 저 화면에 열린 흰색 바탕의 뷰 크기만을 필요로 했다.
그러나 저 바탕 뷰의 경우에는 viewDidLoad에서 얻어낼 수가 없다. 제약조건이 걸린 뷰는 viewDidLoad에선 실제 값을 얻어낼 수 없고 이후, viewDidLayoutSubView라는 함수가 호출되었을 때 알아낼 수 있기 때문이다.
또한 호출된 순서는 viewDidLoad -> tableView기본 함수들(cellForRowAt, willDisplay같은..) -> viewDidLayoutSubView 순서기때문에, 만약 화면이 보여지는 viewDidLoad에서 실제 값을 알고 싶다면 나처럼 viewDidLoad에서 제약조건의 값들을 다시 계산해야하는 번거로움이 있다.
viewDidLayoutSubView에서 코드를 넣으면 tableView기본 함수들에서 _staticView가 뭐냐고 에러를 뱉기 때문에 사용할 수 없었다.
'iOS (기능)' 카테고리의 다른 글
[SWIFT] UIScrollbar의 Scrollbar(indicator)접근하기 (0) | 2018.12.24 |
---|---|
[iOS] Reject : Guideline 4.2.6 (0) | 2018.12.13 |
[SWIFT] SMS 문자 메시지 보내기 (4) | 2018.05.23 |
[SWIFT] String <-> Float(CGFloat) 변환, Int -> Cgflaot (0) | 2018.05.17 |
[SWIFT] UILabel의 text 속성(여러 색상 넣기, 폰트 바꾸기 등) (0) | 2018.03.28 |