Skip to content

Latest commit

ย 

History

History
414 lines (318 loc) ยท 14.6 KB

IJ.md

File metadata and controls

414 lines (318 loc) ยท 14.6 KB

์•ฑ์Šคํ† ์–ด ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์ ์šฉํ•˜๊ธฐ


  • ๋น„์Šทํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ• ๊นŒ ์ƒ๊ฐ ํ–ˆ์ง€๋งŒ ์ž‘๋™์›๋ฆฌ์™€ ๊ตฌ์กฐ๋ฅผ ๋” ์•Œ๊ณ  ์‹ถ์–ด์„œ ๋„์ „
  • ๋งจ ์ฒ˜์Œ ๊ตฌ์กฐ๋ถ€ํ„ฐ ์ƒ๊ฐ์„ ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ €ํ•ด๋ด„
    • CollectionView๋ฅผ Vertical Scroll๋กœ ๋งŒ๋“ค๊ณ  Cell ์„ ํƒ๋˜์—ˆ์„๋•Œ, ์…€์ด ํŽผ์ณ์ง€๋Š” ๊ตฌ์กฐ๋กœ ์ƒ๊ฐ
    • ์…€์„ ๋ˆŒ๋ €์„๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ, ์Šคํ…Œ์ดํ„ฐ์Šค๋ฐ” ํžˆ๋“  ๋“ฑ ์•„์ดํฐ ํ™”๋ฉด์— ๊ฝ‰์ฐจ๊ฒŒ ๊ตฌํ˜„ ์™„๋ฃŒ
    • ๊ทธ๋Ÿฌ๋‚˜! DetailView๋Š” ๊ธด ์Šคํฌ๋กค์ด ํ•„์š”ํ•ด์„œ ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„์‹œ ๋ถˆ๊ฐ€๋Šฅ

  • ๊ตฌ๊ธ€๋ง ๋ฐ ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐ
  • ํ—ค๋”๋ทฐ์™€ ๋ฐ”๋””๋ทฐ๋กœ(์„ค๋ช…ํ•˜๊ธฐ ํŽธํ•˜๊ฒŒ) xib๋ฅผ ๋‚˜๋ˆ„๊ณ , ์…€์„ ๋ˆŒ๋ €์„๋•Œ ํ—ค๋”๋ทฐ๊ฐ€ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋ฐ”๋””๋ทฐ๋ฅผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์œผ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•ด์ฃผ๋Š” ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„
  • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์˜ push ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ปค์Šคํ…€ํ•ด์„œ ์ ์šฉ, ์ด ๋ถ€๋ถ„์€ ์ž์œ 

extension RecommendViewController: Animatable {
    var containerView: UIView? {
        return self.recommendCollectionView
    }
    
    var childView: UIView? {
        return self.selectedCell
    }
}

์ด๋Ÿฐ์‹์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋ทฐ๊ฐ€ ํ—ค๋”๋ทฐ , childView๋Š” ์Šคํฌ๋กค๋  ๋‹ค์Œ ๋ฉ”์ธ๋ทฐ์ปจ์„ ์˜๋ฏธ ํ•ฉ๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฐ์ƒท 2020-07-17 ์˜คํ›„ 7 31 11

  • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์…€์˜ ๋ณด์—ฌ์ง€๋Š” ๋ทฐ๊ฐ€, ์ดˆ๋ก์ƒ‰๋ทฐ(์ปจํ…Œ์ด๋„ˆ๋ทฐ)๊ฐ€ ๋ณด์—ฌ์ง€๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ์Šคํฌ๋กค๋˜๋Š” ๋ถ€๋ถ„์ด ๋ณด์—ฌ์ง€๋Š” ํ˜•์‹

  • DetailView๋Š” ViewController๋กœ ๋งŒ๋“ค์–ด์ง, ์• ๋‹ˆ๋ฉ”์ด์…˜์€ extension์„ ์ด์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„

extension DetailViewController: Animatable {
    var containerView: UIView? {
        return self.view
    }
    
    var childView: UIView? {
        return self.commonView
    }
    
    func presentingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    ) {
        self.heightConstraint.constant = fromFrame.height
        
        // Show the close button
        self.closeButton.alpha = 1
        self.asCard(true)
        self.view.layoutIfNeeded()
        let safeAreaTop = self.view.window?.safeAreaInsets.top ?? .zero
        print("safeAreaTop ๊ฐ’: \(safeAreaTop)")
        
        self.commonView.topConstraintValue = safeAreaTop + 16
        
        // Animate the common view to a height of 500 points
        self.heightConstraint.constant = 405
        sizeAnimator.addAnimations {
            self.view.layoutIfNeeded()
        }
        
        // Animate the view to not look like a card
        positionAnimator.addAnimations {
            self.asCard(false)
        }
    }
    
    func dismissingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    ) {
        self.topConstraint.isActive = true
        if scrollView.contentOffset.y > commonView.frame.height {
            self.topConstraint.constant = -commonView.frame.height
            self.view.layoutIfNeeded()
            
            // Still want to animate the common view getting pinned to the top of the view
            self.topConstraint.constant = 0
        }
        self.commonView.topConstraintValue = 16
        self.heightConstraint.constant = toFrame.height
        sizeAnimator.addAnimations {
            self.closeButton.alpha = 0
            self.view.layoutIfNeeded()
        }
        
        // ์นด๋“œ์ฒ˜๋Ÿผ ๋ณด์—ฌ์ง€๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜
        positionAnimator.addAnimations {
            self.asCard(true)
        }
    }
}
  • ํ—ค๋”๋ทฐ์˜ ํƒ‘ํ—ค์ดํŠธ๋ฅผ ์ด์šฉํ•ด ์กฐ์ ˆ
  • ๋ฆฌ์ปค๋ฉ˜๋“œ๋ทฐ์—์„œ ์ƒ๋‹จ, ์ค‘๋‹จ, ํ•˜๋‹จ ์…€์„ ์„ ํƒ์‹œ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ํ—ค๋”์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ ์šฉ

protocol Animatable {
    var containerView: UIView? { get }
    var childView: UIView? { get }

    func presentingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    )

    func dismissingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    )
}

/// Default implementations
extension Animatable {
    func presentingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    ) {}

    func dismissingView(
        sizeAnimator: UIViewPropertyAnimator,
        positionAnimator: UIViewPropertyAnimator,
        fromFrame: CGRect,
        toFrame: CGRect
    ) {}
}
  • Animatable ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•ด ์• ๋‹ˆ๋ฉ”์ดํŒ… ๊ตฌํ˜„

  • ํ—ค๋”๋ทฐ์™€ ์Šคํฌ๋กค๋ทฐ๊ฐ€ ํ™”๋ฉด ์ „์ฒด์™€ ๊ฝ‰์ฐจ๊ฒŒ ๋˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ์ฝ”๋“œ ์ฐธ์กฐ ๋ฐ ๊ณต๋ถ€๋กœ ๊ตฌํ˜„
  • extension์„ ์ด์šฉํ•ด CustomTransitionAnimation ๊ตฌํ˜„
  • NavigationContorller์˜ Push๊ฐ€ ํ•ด๋‹น ์ปค์Šคํ…€ ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ๊ตฌํ˜„ ๋˜๊ฒŒ ๊ตฌํ˜„
extension CustomTransitionAnimation {
    // Custom push animations
    internal func presentTransition(_ transitionContext: UIViewControllerContextTransitioning) {
        print("presentTransition ์ง„์ž…")
        let container = transitionContext.containerView

        // ===========================================================
        // Step 1: Get the views we are animating
        // ===========================================================

        // Views we are animating FROM
        guard
            let fromVC = transitionContext.viewController(forKey: .from) as? Animatable,
            let fromContainer = fromVC.containerView,
            let fromChild = fromVC.childView
        else {
            return
        }

        // Views we are animating TO
        guard
            let toVC = transitionContext.viewController(forKey: .to) as? Animatable,
            let toView = transitionContext.view(forKey: .to)
        else {
            return
        }
        
        

        // Preserve the original frame of the toView
        let originalFrame = toView.frame

        container.addSubview(toView)

        // ===========================================================
        // Step 2: Determine start and end points for animation
        // ===========================================================

        // Get the coordinates of the view inside the container
        let originFrame = CGRect(
            origin: fromContainer.convert(fromChild.frame.origin, to: container),
            size: fromChild.frame.size
        )
        let destinationFrame = toView.frame

        toView.frame = originFrame
        toView.layoutIfNeeded()

        fromChild.isHidden = true

        // ===========================================================
        // Step 3: Perform the animation
        // ===========================================================

        let yDiff = destinationFrame.origin.y - originFrame.origin.y
        let xDiff = destinationFrame.origin.x - originFrame.origin.x

        // For the duration of the animation, we are moving the frame. Therefore we have a separate animator
        // to just control the Y positioning of the views. We will also use this animator to determine when
        // all of our animations are done.

        // Animate the card's vertical position
        let positionAnimator = UIViewPropertyAnimator(duration: self.positioningDuration - 0.1, dampingRatio: 0.7) //base dampingRatio 0.7
        positionAnimator.addAnimations {
            // Move the view in the Y direction
            toView.transform = CGAffineTransform(translationX: 0, y: yDiff)
        }

        // Animate the card's size
        let sizeAnimator = UIViewPropertyAnimator(duration: self.resizingDuration - 0.1, curve: .easeInOut)
        sizeAnimator.addAnimations {
            // Animate the size of the Card View
            toView.frame.size = destinationFrame.size
            toView.layoutIfNeeded()

            // Move the view in the X direction. We concatenate here because we do not want to overwrite our
            // previous transformation
            toView.transform = toView.transform.concatenating(CGAffineTransform(translationX: xDiff, y: 0))
        }

        // Call the animation delegate
        toVC.presentingView(
            sizeAnimator: sizeAnimator,
            positionAnimator: positionAnimator,
            fromFrame: originFrame,
            toFrame: destinationFrame
        )

        // Animation completion.
        let completionHandler: (UIViewAnimatingPosition) -> Void = { _ in
            toView.transform = .identity
            toView.frame = originalFrame

            toView.layoutIfNeeded()

            fromChild.isHidden = false

            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }

        // Put the completion handler on the longest lasting animator
        if (self.positioningDuration > self.resizingDuration) {
            positionAnimator.addCompletion(completionHandler)
        } else {
            sizeAnimator.addCompletion(completionHandler)
        }

        // Kick off the two animations
        positionAnimator.startAnimation()
        sizeAnimator.startAnimation()
    }

๋„ค์ด๋ฒ„์ง€๋„APi ์ด์šฉํ•œ ์ง€๋„์•ฑ ์ด๋™, ๊ทธ์— ๋”ฐ๋ฅด๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ


        let marker = NMFMarker()
        
        let bookstoreLatitude:Double = Double( self.detailBookStoreModel[0].latitude)
        let bookstoreLongitude:Double = Double(self.detailBookStoreModel[0].longitude)
        
        marker.position = NMGLatLng(lat: bookstoreLatitude, lng: bookstoreLongitude)
  • ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋กœ ๋งˆ์ปค๋ฅผ ์ง€๋„์— ํ‘œํ˜„ ๊ฐ€๋Šฅ
  • ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ์•ฑ์—์„œ ์ง€๋„๋ฅผ ๋ณด๋ฉด, ๋ณด์ด์ง€ ์•Š์Œ...Why? ์ง€๋„์˜ ์นด๋ฉ”๋ผ ์ด๋™ ๋˜ํ•œ ๋งˆ์ปค๋กœ ์ด๋™์‹œ์ผœ์•ผํ•จ
  let cameraUpdate = NMFCameraUpdate(scrollTo: NMGLatLng(lat: bookstoreLatitude, lng: bookstoreLongitude))
        
        cameraUpdate.reason = 3
        cameraUpdate.animation = .fly
        cameraUpdate.animationDuration = 2
        
        detailNaverMapView.mapType = .basic
        detailNaverMapView.minZoomLevel = 5.0
        detailNaverMapView.maxZoomLevel = 18.0
        detailNaverMapView.zoomLevel = 15.0
        detailNaverMapView.moveCamera(cameraUpdate, completion: { (isCancelled) in
            if isCancelled {
                print("์นด๋ฉ”๋ผ ์ด๋™ ์ทจ์†Œ")
            } else {
                print("์นด๋ฉ”๋ผ ์ด๋™ ์„ฑ๊ณต")
            }
        })
        
        
        marker.mapView = detailNaverMapView
  • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€๋„์˜ ํ™•๋Œ€ ๋ ˆ๋ฒจ ๋ฐ ์นด๋ฉ”๋ผ๋ฅผ ์ด๋™ ์‹œ์ผœ์ฃผ๋ฉด ์›ํ•˜๋Š” ๊ณณ์˜ ์œ„๋„ ๊ฒฝ๋„๊ฐ’์˜ ๋งˆ์ปค๋ฅผ ์ง€๋„๋ทฐ๋กœ ํ‘œํ˜„ ๊ฐ€๋Šฅ

  • ๋˜ํ•œ ๋‹ค์Œ์˜ ๋งˆ์ปค ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋ฅผ ์ด์šฉํ•ด ๋„ค์ด๋ฒ„์ง€๋„ ์•ฑ์œผ๋กœ ์ด๋™๊ฐ€๋Šฅ

        marker.touchHandler = { (overlay) in
            
            print("๋งˆ์ปค ํด๋ฆญ๋จ")
            self.goToNaverMap()
            
            return true
        }
  • ์•ฑ์˜ ์Šคํ‚ค๋งˆURL์„ ์ด์šฉํ•ด ํ•ด๋‹น ์•ฑ์œผ๋กœ ์ด๋™ ๊ฐ€๋Šฅ, ๋„ค์ด๋ฒ„ ์ง€๋„ ์•ฑ์ด ์—†์„์‹œ ์•ฑ์Šคํ† ์–ด ๋„ค์ด๋ฒ„์ง€๋„๋กœ ์ด๋™
    func goToNaverMap(){
        let appStoreURL = URL(string: "http://itunes.apple.com/app/id311867728?mt=8")!
        
        let latitude: Double = Double(self.detailBookStoreModel[0].latitude)
        let longtitude: Double = Double(self.detailBookStoreModel[0].longitude)
        
        if let detailMapURL = URL(string: "nmap://place?lat=\(latitude)&lng=\(longtitude)&name=Cozy%ea%b0%80%20%ec%b6%94%ec%b2%9c%ed%95%98%eb%8a%94%20%ec%84%9c%ec%a0%90&gamsung.Cozy=Cozy"), UIApplication.shared.canOpenURL(detailMapURL)
        { // ์œ ํšจํ•œ URL์ธ์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
            if #available(iOS 10.0, *) { //iOS 10.0๋ถ€ํ„ฐ URL๋ฅผ ์˜คํ”ˆํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ณ€๊ฒฝ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
                UIApplication.shared.open(detailMapURL, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(appStoreURL)   
            }
        }
    }

  • ์‹ค์ œ ์•„์ดํฐ์—์„œ ์ž‘๋™์‹œ ๊ตฌํ˜„์ด ์ž˜๋˜์–ด์ง
  • ๋„ค์ด๋ฒ„์ง€๋„ ์•ฑ์„ ๊ฐ”๋‹ค๊ฐ€ ๋‹ค์‹œ, Cozy์•ฑ์œผ๋กœ ๋Œ์•„์˜ฌ์‹œ ํƒญ๋ฐ”๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ
 let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willEnterForegroundNotification, object: nil)
  • ์•ฑ๋”œ๋ฆฌ๊ฒŒ์ดํŠธ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ˜ธ์ถœ์‹œ ๋‹ค์‹œ ํ•œ๋ฒˆ ํƒญ๋ฐ”๋ฅผ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•ด์ฃผ์–ด ๋ฌธ์ œ ํ•ด๊ฒฐ
  • ๋‹ค๋ฅธ ์•ฑ์„ ๊ฐ”๋‹ค๊ฐ€ ๋‹ค์‹œ ๋Œ์•„์˜ฌ์‹œ, ํ˜ธ์ถœ๋ฌธ์ œ๋กœ ์ธํ•ด ํƒญ๋ฐ” ํžˆ๋“ ์ด ํ’€๋ฆฌ๋Š” ๊ฒƒ์œผ๋กœ ์ถ”์ •

TableView์˜ ์œ ๋™์ ์ธ Label์˜ ํ—ค์ดํŠธ์— ๋”ฐ๋ผ ์…€์˜ ํฌ๊ธฐ๊ฐ€ ๊ฐ๊ธฐ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ

    var index: Int = 0
                self.myDetailReviewModel.forEach { element in
                    let eachLabel: UILabel = {
                        let label = UILabel()
                        label.numberOfLines = 0
                        label.text = self.myDetailReviewModel[index].content
                        index += 1
                        return label
                    }()
                    
                    
                    let size = eachLabel.sizeThatFits(CGSize(width: 100, height: 100))
                    print(size.height/10)
                    self.eachCellHeight.append(320 + (size.height/10))
                }
  • ์ž„์˜์˜ ๋ ˆ์ด๋ธ”์— ํ…์ŠคํŠธ๋ฅผ ๋„ฃ์–ด์„œ, ํ—ค์ดํŠธ ์‚ฌ์ด์ฆˆ๋ฅผ ๋Œ€๋žต์ ์œผ๋กœ ๊ตฌํ•จ
  • ํ—ค์ดํŠธ๊ฐ’์ด ๋„ˆ๋ฌด ํฌ๊ฒŒ ์žกํ˜€์„œ, /10์œผ๋กœ ๋น„์œจ๊ฐ’์„ ์กฐ์ ˆ์‹œ ์›ํ•˜๋Š” ์ •๋„์˜ ์‚ฌ์ด์ฆˆ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • ์…€์˜ ์˜คํ† ๋ ˆ์ด์•„์›ƒ๋„ ๋ ˆ์ด๋ธŒ์ด ๊ฐ€๋ณ€์ ์œผ๋กœ ๋ณ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์žก์•„๋‘์–ด์•ผํ•จ
    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 100
  • ์˜คํ† ๋ฉ”ํ‹ฑ์…€์„ ์ด์šฉํ•ด ํ—ค์ดํŠธ ๊ฐ’์„ ์กฐ์ •ํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ์Œ

ํƒญ๋ฐ”ํžˆ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์•ˆ๋จนํžˆ๋Š” ๋ฒ„๊ทธ ๋ฐœ์ƒ

  • ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ, ํ˜ธ์ถœ๋“ฑ์„ ๋ฐ”๊ฟ” ๋ณด์•˜์œผ๋‚˜ ์›์ธ์ด ๋”ฑํžˆ ์žกํžˆ์ง€ ์•Š์Œ

  • 11pro, xs, promax ๊ณ„์—ด์€ ์ž˜๋˜๋‚˜, ํ™ˆ๋ฒ„ํŠผ์ด ์žˆ๋Š” ์•„์ดํฐ8, SE2, 8+์—์„œ๋Š” ํ”„๋ ˆ์ž„์˜ ํ—ค์ดํŠธ ์œ„๋“œ๋“ฑ ๊ณ„์‚ฐ์ด ๋งž๊ฒŒ ๋˜๋‚˜, ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ isHidden ๋˜ํ•œ ์—๋Ÿฌ ๋ฐœ์ƒ

  • ๊ธฐ๊ธฐ๋ณ„๋กœ ๋ถ„๊ธฐ์ฒ˜๋ฆฌ๋กœ ํ•ด๊ฒฐ, ํ”„๋กœ์ ํŠธ๊ฐ€ ๋๋‚œ ํ›„ ์กฐ๊ธˆ ๋” ์›์ธ์„ ๋ถ„์„!

switch deviceHeight {
        case 667.0: //iphone 6, 6s, 7, 8 => 4.7 inch
            self.tabBarController?.tabBar.isHidden = false
        case 812.0: //iphone X, XS => 5.8 inch
            self.setTabBarHidden(false)
        default:
            self.setTabBarHidden(false)
        }