๐Ÿ’ก work work work/swift

swift ์‹ค์Šต - 4 : OnBoardingView

hanwitjus 2022. 2. 21. 15:21

์ด๋Ÿฐ ๋ชจ์–‘์˜ ๋ทฐ๊ฐ€ onboarding view

 

 

 

์ด๋Ÿฐ ๋ชจ์–‘์˜ 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๋ผ๊ณ  ๋งŒ๋“ค์–ด์„œ ์กฐ๊ฑด์„ ์„ค์ •ํ•ด์คฌ๋‹ค.

 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด.. ๋์ด๋‹ค...

์˜ค๋Š˜ ๋ญ”๊ฐ€ ์ข€ ๊ตฌ์ฐฎ์•„์„œ ์„ค๋ช…์„ ๋Œ€์ถฉํ–ˆ๋‹ค^^

 

 

LIST