UIAlertController 만들기

2 답변 글타래를 보이고 있습니다
  • 글쓴이
    • lidium
      참가자
      • 글작성 : 9
      • 답글작성 : 8
      770 포인트

      저번시간 PageViewController에 이어, 이번에는 UIAlertController와 같은 뷰를 구현하려 합니다.

      위와 같은 형태를 ActionSheet라고 하고, 저렇게 커스텀된 요소들이 있지만, 좀 더 커스텀이 되기를 원합니다.
      예를 들면 이렇게 생겼습니다.


      선택된 항목은 Bold도 되어야 하고, 배경도 흰색으로 꽉 채워야 합니다. 예쁘게 만들어 보겠습니다.
      누르면 아래에서 위로 애니메이션 되며 뷰를 띄워줘야 합니다. 스토리보드로는 한계가 있습니다
      (스토리보드로 이런거 어떻게 만들어야할지 사실 감이 잘 안오기도 합니다)
      따라서 코드로 만들어 보았습니다. CollectionView를 사용하였습니다.

      class Setting: NSObject {
          let name: SettingName
      
          init(name: SettingName) {
              self.name = name
          }
      }
      

      Setting에 필요한 객체를 미리 enum이나 Struct로 선언해서 보관해 두고 사용할 것입니다.

      Swift File 이름은 SettingLauncher입니다.
      아래 생성할 CollectionView가

      이런 화면을 만들어낼 것입니다.

      let collectionView: UICollectionView = {
              let layout = UICollectionViewFlowLayout()
              let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
              // 빈 CollectionView 선언, 있다가 CellSize를 부여할 것
              cv.backgroundColor = UIColor.white
              return cv
          }()
      

      CollectionView를 선언하고, 아래와 같이 사이즈를 줍니다. CellHeight는 50입니다.

      func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
      
              let setting = self.settings[indexPath.item]
              handleDismiss(setting: setting)
      
          }
      
          func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
              return settings.count
          }
      
          func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
              let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SettingCell
      
              let setting = settings[indexPath.item]
              cell.setting = setting
      
              return cell
          }
      
          func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
              return CGSize(width: collectionView.frame.width, height: cellHeight)
          }
      
          func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
              return 0
          }
      

      또한, 코드로 구현한 Layout은

       override init() {
              super.init()
      
              collectionView.dataSource = self
              collectionView.delegate = self
      
              collectionView.register(SettingCell.self, forCellWithReuseIdentifier: cellId)
          }
      

      와 같이 register, datasource, delegate를 선언해주어야 합니다.

      CollectionView를 만들었으니, 이제 Action을 추가하겠습니다.
      네비게이션 바의 버튼을 눌렀을 때 Action이 수행되도록 하겠습니다.

       func showSettings() {
              //show menu
      
              //        if let window = UIApplication.shared.keyWindow {
              // shard.keyWindow가 Deprecated 되었다고 합니닷 아래와 같이 사용
      
              if let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {
      
                  blackView.backgroundColor = UIColor(white: 0, alpha: 0.5)
                  blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
      
                  window.addSubview(blackView)
                  window.addSubview(collectionView)
      
                  let height: CGFloat = CGFloat(settings.count) * cellHeight
                  let y = window.frame.height - height
                  //  y : collectionView가 그려지는 시작 위치
      
                  collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: height)
      
                  blackView.frame = window.frame
                  blackView.alpha = 0
      
                  UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
      
                      self.blackView.alpha = 1
                      self.collectionView.frame = CGRect(x:0, y: y, width: self.collectionView.frame.width, height: self.collectionView.frame.height)
      
                  }, completion: nil)
              }
          }
      

      showSettings()에서는 BlackView와 CollectionView를 addSubView()를 비롯하여 직접 구현하는 장소입니다.
      BlackView라는 View는 배경을 어둡게 해주는 역할을 합니다. 아래와 같은 화면이 됩니다.

      해당 배경이 Opacity가 있는 BlackView입니다. UIView.Animate()에서는 BlackView의 Alpha와,
      CollectionView의 frame이 변경됨을 알 수 있습니다.

      또한, showSetting()은 호출이 되어야 하는데, 어느 버튼에서나 Selector를 사용해서 호출해내면 됩니다.
      저는 위에서 이야기한 바와 같이 NavigationItem의 Button을 이용할 것입니다.

      NavigationBar는 원래 ViewController파일에 존재하므로, ( 제 경우 – HomeViewController )
      HomeVC에서

          lazy var settingsLauncher: SettingsLauncher = {
              let launcher = SettingsLauncher()
              launcher.homeController = self
              return launcher
          }()
      

      와,

       func setupNavBarButtons() {
              let moreButton = UIBarButtonItem(image: UIImage(named: "nav_more_icon")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleMore))
      
              navigationItem.rightBarButtonItem = moreButton
          }
      
          @objc func handleMore() {
               settingsLauncher.showSettings()
           }
      

      를 만들어주면, 네비게이션의 버튼을 누를 경우 showSettings()가 실행이 됩니다.

      후기를 써보자면…
      저번에도 CollectionView로 만들었는데, 이번 뷰 커스텀을 하며 느낀 점은
      컬렉션뷰는 생각보다 다재다능하고 여러군데에 사용이 가능하지만,
      본래 목적에 가장 잘 어울린다는 점이기도 합니다(..)
      이상입니다. 감사합니다!

      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      • 이 게시글은 lidium에 의해 2 years, 1 month 전에 수정됐습니다.
      avatar
    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 552
      19,990 포인트

      커스텀뷰가 멋지네요!

      다른 이야기지만 맨 아래 움짤에서는 페이지 컨트롤이 홈바와 겹쳐서 가리네요. 위치를 잡을 때 view가 아니라 safe area를 사용하면 괜찮아질 것 같습니다.

      그런데 이 커스텀 뷰를 만들면서 테이블뷰가 아니라 콜렉션뷰를 사용한 이유가 궁금합니다 🙂

      avatar
      • lidium
        참가자
        • 글작성 : 9
        • 답글작성 : 8
        770 포인트

        항상 감사합니다!

        TableView가 해당 gif에는 제일 잘 어울리긴 하네요,,,,

        원래 목적은 맨 위 라이브러리 gif와 같이 확장성을 가진 친구를

        맨 처음에 기획하다 보니..? 그랬던 것 같기도 합니다!

         

        페이지 컨트롤도 도와주신대로 해결해 냈습니다!

        • 야곰
          키 마스터
          • 글작성 : 37
          • 답글작성 : 552
          19,990 포인트

          그렇군요~
          커스텀뷰를 좋아하시나 봅니다.
          커스텀뷰 장인!

          avatar
    • 도미닉
      참가자
      • 글작성 : 44
      • 답글작성 : 86
      5,460 포인트

      우와..

      avatar
2 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 260-27-00477
통신판매업 신고번호 : 제 2020-충북청주-0663 호
고객센터 : 카카오톡채널 @yagom