swift ์ค์ต - 4 : OnBoardingView
์ด๋ฐ ๋ชจ์์ view๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋ฐฐ์ ๋ค.
์์ ๋ค์ด๊ฐ๋ ๋ด์ฉ๋ค(๊ธ, ์ด๋ฏธ์ง)์ ํ๋์ฝ๋ฉ์ ํด์ ๊ทธ๋ฐ์ง
๋ ๋ ๊ฑธ๋ฆฌ๊ณ ์ํํ๊ฒ ์๋๊ธด ํ๋๋ฐ ์ํผ ๊ตฌํํด์ผ ํ ๊ฒ์
1. OnBoardingView
2. Page Control Bar
3. ๋ง์ง๋ง ํ์ด์ง์์ ํ์ธ ๋ฒํผ ๋จ๊ฒ ๋ง๋ค๊ธฐ
(+) ํ์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ฉ์ธ ๋ทฐ ์ปจํธ๋กค๋ฌ๋ก ์ด๋
ํฌ๊ฒ ์ด๋ ๊ฒ 3๊ฐ์ง ์ด๋ค.
1. OnBoardingView
๋จผ์ OnBoardingItemViewController์ ์ด๋ฆ์ผ๋ก swiftํ์ผ ์ปจํธ๋กค๋ฌ์ xib ํ์ผ์ ํจ๊ป ์์ฑํ๋ค.
์ฌ๊ธฐ์๋ ํ๋ฉด์ ๋ณด์ฌ์ง ์จ๋ณด๋ ํ๋ฉด์ ๊ตฌ์ฑํ๋ ๊ฒ์ด๋ค.
์จ๋ณด๋ ํ๋ฉด์ ๊ตฌ์ฑ์ ์ด๋ฐ์์ผ๋ก ๋ ๊ฒ์ด๋ค.
๋งจ ์์ ์ด๋ฏธ์ง๋ทฐ๊ฐ ์๊ณ
๊ทธ ๋ฐ์ title label, description label์ด ์์ ๊ฒ์ด๋ค.
์ด๋ ๊ฒ ์ค์ ํด๋๊ณ ์ ์์๋ค์ ์๋ฏธ์๋ ๊ฐ๋ค์ ๋ฟ๋ ค์ค์ผ ํ๊ธฐ๋๋ฌธ์
์์๋ ์ผ๋ก ์ฝ๋์ ๋์ด์ ํ์ํ ์์ค์ฝ๋๋ฅผ ์์ฑํ๋ค.
class OnBoardingItemViewController: UIViewController {
var mainText = ""
var subText = ""
var topImage: UIImage? = UIImage()
@IBOutlet private weak var topImageView: UIImageView!
@IBOutlet private weak var mainTitleLabel: UILabel!{
didSet{
mainTitleLabel.font = UIFont.systemFont(ofSize: 20, weight: .medium)
}
}
@IBOutlet private weak var descriptionLabel: UILabel!{
didSet{
descriptionLabel.font = UIFont.systemFont(ofSize: 14, weight: .light)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
mainTitleLabel.text = mainText
descriptionLabel.text = subText
topImageView.image = topImage
}
}
์ฌ๊ธฐ์ ์ฃผ์ํ ์ฌํญ์ View์ LifeCycle์ ์ ๊ธฐ์ตํด์ผ ํ๋ค๋ ์ ์ด๋ค.
viewDidLoad์ ์์๋ค์ ๋ด์ฉ์ ๋ฟ๋ ค์ฃผ๋ ค๊ณ ํ๋ค๋ณด๋ฉด ์์ง View๊ฐ ๋ก๋๋๊ธฐ ์ ์ด๋ผ
์์๋ ์ผ๋ก ๊ฐ์ ธ์จ ์์๋ค์ด ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ์ง ์์ ์ํ์ผ ์ ์๋ค.
๊ทธ๋ ๊ฒ ๋๋ฉด ๊ฐ์ ์ ๊ทผ ํ ์ ์์ผ๋ ๊ทธ ์ ์ ์ ์ํด์ผ ํ ๊ฒ๊ฐ๋ค.
๊ทธ๋ฆฌ๊ณ OnBoardingPageViewController ๋ผ๋ ์ด๋ฆ์ swift ํ์ผ์ ๋ง๋ค์ด์
๊ทธ ์์์ ๋ ์ด์์ ์์๋ค์ ๊ฐ์ ์ง์ ํด์ฃผ๊ณ , Page View์์ ๋ฐ๋์ ๊ตฌํํด์ผ ํ
UIPageViewControllerDelegate, UIPageViewControllerDatasource ๋๊ฐ์ง๋ฅผ ๊ตฌํํ๋ค.
(tableView์์๋ ๊ทธ๋ฌ๋ ๊ฒ ์ฒ๋ผ pageView๋ ๊ผญ ์ ๋๊ฐ๋ ์ ์ธํด์ผ ํ๋ค.)
func makePageVC() {
let itemVC1 = OnBoardingItemViewController.init(nibName: "OnBoardingItemViewController", bundle: nil)
itemVC1.mainText = "Focus on your ideal buyer"
itemVC1.topImage = UIImage(named: "onboarding1")
itemVC1.subText = "When you write a product description with a huge crowd of buyers in mind, your description become wishy-washy and you end up addressing no one at all."
let itemVC2 = OnBoardingItemViewController.init(nibName: "OnBoardingItemViewController", bundle: nil)
itemVC2.mainText = "Entice with benefits"
itemVC2.topImage = UIImage(named: "onboarding2")
itemVC2.subText = "When we sell a product bluh bluh something something really good cool nice man."
// ... ์๋ต
setViewControllers([itemVC1], direction: .forward, animated: true, completion: nil)
self.dataSource = self
}
๋ ์ด์์ ์์๋ค์ ๋ํ ๊ฐ์ ๊ทธ๋ฅ ์ด๋ ๊ฒ ํ๋ ์ฝ๋ฉ์ผ๋ก ํด์ฃผ๊ณ , setViewController๋ก ๋ทฐ๋ฅผ ๋ฑ๋กํด์ค๋ค.
2. Page Control Bar
ํ์ฌ ๋ช๋ฒ์งธ ํ์ด์ง์ ์๋ ์ง ๋ฑ์ ์๋ ค์ฃผ๋ ์ธ๋์ผ์ดํฐ๋ฅผ ๋ง๋๋ ค๊ณ ํ๋ค.
์ง๊ธ OnBoardingPageViewController๋ฅผ xibํ์ผ๊ณผ ํจ๊ป ์์ฑํ๊ฒ ์๋๋ผ ๋ชจ๋ ๋ค ์ฝ๋๋ก ํด์ผํ๋ค.
var pageControl = UIPageControl()
func makePageControl(){
self.view.addSubview(pageControl)
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.currentPageIndicatorTintColor = .black
pageControl.pageIndicatorTintColor = .lightGray
pageControl.numberOfPages = pages.count
pageControl.currentPage = startIndex
pageControl.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -80).isActive = true
pageControl.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
pageControl.isUserInteractionEnabled = true
pageControl.addTarget(self, action: #selector(pageControlTapped), for: .valueChanged)
}
makePageControl์ด๋ผ๋ ํจ์๋ฅผ ํ๋ ๋ง๋ค์ด์ ๊ทธ ์์์ ์กฐ์ ์ ํด์ฃผ๋ ค๊ณ ํ๋ค.
๋จผ์ ์ ์ญ๋ณ์๋ก UIPageControlํ์ pageControl์ ์ ์ธํด์ฃผ๊ณ
์์ด๋, ์คํ ๋ ์ด์์ ๋ฑ๋ฑ์ ์ค์ ํด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค ๋ถ๋ถ์ ๋๋ ์๋๋ ํ์ด์ง๊ฐ ์ฎ๊ฒจ๊ฐ ์ ์๊ฒ ํ๊ธฐ ์ํด์
pageControlTapped ๋ผ๋ ํจ์๋ ๋ง๋ค์๋ค.
@objc func pageControlTapped(sender: UIPageControl){
if sender.currentPage > self.currentIndex {
self.setViewControllers([pages[sender.currentPage]], direction: .forward, animated: true, completion: nil)
}
else{
self.setViewControllers([pages[sender.currentPage]], direction: .reverse, animated: true, completion: nil)
}
์์ addTarget ๋ฉ์๋์์ ์ฌ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ objective-c runtime์ ์์ ๋ถ์ฌ์ฃผ๊ณ , ์ธ๋ฑ์ค๋ฅผ ์ ๊ณ์ฐํด์
direction์ forward๋ก ํ ์ง reverse๋ก ํ ์ง ๊ฒฐ์ ํ์ฌ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
3. ๋ง์ง๋ง ํ์ด์ง์ ํ์ธ ๋ฒํผ
๋ง์ง๋ง ํ์ด์ง์์ ํ์ธ ๋ฒํผ์ ๋จ๊ฒ ๋ง๋๋ ค๊ณ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ํ์ธ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ฉ์ธ๋ทฐ๋ก ๋์ด๊ฐ๋ค.
func makeBottomButton(){
let button = UIButton()
button.setTitle("ํ์ธ", for: .normal)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = UIColor.systemBlue
button.addTarget(self, action: #selector(dismissPageVC), for: .touchUpInside)
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
buttonMargin = button.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 0)
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
button.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
button.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
buttonMargin?.isActive = true
hideButton()
}
๋ฒํผ๋ ๋ง์ฐฌ๊ฐ์ง๋ก makeBottomButton์ด๋ผ๊ณ ํจ์๋ฅผ ๋ง๋ค์ด ์ฝ๋๋ก ๋ง๋ค๊ณ ,
๋ฒํผ์ ์จ๊ฒผ๋ค ๋์๋ค ํ๊ฒ ํด์ผ ํ๋ฏ๋ก
๊ทธ ๊ธฐ๋ฅ์ constant ๊ฐ์ ๋๋ ธ๋ค ์ค์๋ค ํ๋ ๋ฐฉ์์ผ๋ก ํ๋ค.
์ฒ์์ ์ค์ ํด๋์ ๊ฐ์ ๊ธฐ์ตํ๊ธฐ ์ํด์ buttonMargin์ด๋ผ๋ ๋ณ์๋ฅผ ํ๋ ์ ์ธํด์
button์ bottomAnchor ์ค์ ์ํ๋ฅผ ์ ์ฅํ๊ฒ ํ๊ณ
func buttonPresentationStyle(){
if currentIndex == pages.count - 1 {
self.showButton()
}else{
self.hideButton()
}
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 0.2, delay: 0, options: [.curveEaseInOut], animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
func showButton(){
buttonMargin?.constant = 0
}
func hideButton(){
buttonMargin?.constant = 120
}
์ด๋ ๊ฒ ๊ฐ๊ฐ์ ์กฐ๊ฑด๋ณ๋ก ๋ฒํผ์ ๋ณด์ฌ์ฃผ๊ณ ์จ๊ธฐ๋ ์ฝ๋๋ฅผ ์ ์ด์ ๊ฐ๊ฐ์ ํ์ด๋ฐ์ ๋ง๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฒํผ์ ๋๋ ์ ๋ ๋ฉ์ธ๋ทฐ๋ก ๋์๊ฐ๋ฉด์ ๋ณด๋ ํ์ด์ง๊ฐ ๋ซํ๊ฒ ํ๊ธฐ ์ํด์
@objc func dismissPageVC(){
self.dismiss(animated: true, completion: nil)
}
์ด๋ ๊ฒ ๋ ํจ์๋ฅผ ์ ์ธํ๋ฉด ๋๋ค.
๋ง์ง๋ง์ผ๋ก
๋ฉ์ธ ViewController์์
override func viewDidAppear(_ animated: Bool) {
let pageVC = OnBoardingPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: .none)
if didShowOnboardingView == false {
didShowOnboardingView = true
pageVC.modalPresentationStyle = .fullScreen
self.present(pageVC, animated: true, completion: nil)
}
}
viewDidAppear ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ํด์
๋ณด๋ ํ์ด์ง๋ฅผ ํ์คํฌ๋ฆฐ์ผ๋ก ๋จ๊ฒ ํ๊ฒ ํ๊ณ ,
ํ๋ฒ ํ์ธ๋ฒํผ์ ๋๋ฅด๊ณ ๋ฉ์ธ์ผ๋ก ๋์๊ฐ๋ฉด ๋ค์ ๋จ์ง ์๊ฒ ํ๊ธฐ ์ํด
flag ๋ณ์ ์ฒ๋ผ didShowOnboardingView๋ผ๊ณ ๋ง๋ค์ด์ ์กฐ๊ฑด์ ์ค์ ํด์คฌ๋ค.
์ด๋ ๊ฒ ํ๋ฉด.. ๋์ด๋ค...
์ค๋ ๋ญ๊ฐ ์ข ๊ตฌ์ฐฎ์์ ์ค๋ช ์ ๋์ถฉํ๋ค^^