2019년 9월 22일 일요일

웹뷰에서 스냅샷 찍기 (Take a SnapShot in WKWebView)

상황 
  • 웹뷰를 로드한 직후, 웹뷰를 스냅샷을 찍어 이미지로 저장하고자 함 

방법 
  • WKNavigationDelegate 를 채택한뒤 webView(_:didFinish:) 메서드에 스냅샷 함수를 호출 
과정 
  • WKNavigationDelegate 채택 및 위임 설정 
  • webView(_:didFinish:) 메서드가 웹뷰가 로드되면 작동함 
  • snapshot 함수 호출 
  • 이미지 뷰 및 레이블에 해당 이미지와 타이틀 설정 
내용
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let config = WKSnapshotConfiguration()
//        config.rect = CGRect(x: 0, y: 0, width: 150, height: 150)
        config.snapshotWidth = 150
        webView.takeSnapshot(with: config) { (snapImage, error) in
            if error == nil {
                guard let myImage = snapImage else { return }
                self.imageView.image = myImage
                
                guard let guardTitle = self.webView.title else { return }
                self.webViewLabel.text = guardTitle
            }
        }
    }

이슈
  • 만약 웹뷰가 숨김 상태라면 (webView.isHidden = true) 시뮬레이터에서는 스냅샷이 작동하지만 디바이스, 기기에서는 작동하지 않았다. (Xcode 10.2, iOS 12.4) 웹뷰를 화면 밖으로 꺼내놓아 작동시킴 (윈도우 밖에 위치시킴) 
더 확인해 볼 내용 
  • WKUIDelegate 와 WKNavigationDelegate의 작동 내용 
  • webView(_:createWebViewWith:for:windowFeatures:) 로 새 웹뷰를 만드는 과정
API Reference: 

참고: 1, 2

웹뷰에서 앞, 뒤 페이지로 이동하기(goForward & goBack in WKWebView)

설명 및 의도 
  • 웹뷰 네비게이션에서 앞, 뒤로 이동할 때 쓸어넘김으로 기능 구현하고자 함 
방법 
  • goBack(), goForward() 함수로 구현 (버튼액션이나 혹은 핸들러 이용시)
  • 또는 웹뷰의 프로퍼티 설정 값 변경으로 구현 
  • 또는 스와이프 제스쳐로 구현 
내용
self.webView.allowsBackForwardNavigationGestures = true

또는 스와이프 제스쳐 (UIGestureRecognizerDelegate 프로토콜 채택) 

이슈 
  • 뒤로가는 스와이프 동작은 방향을 .left 가 아닌 .right 로 지정( 터치를 오른쪽으로 이동하므로)
  • 제스쳐가 중복이 될경우 동작하지 않는 상황 발생하여 딜리게이트 메서드 추가해야 함 (중복된 제스쳐 허용)
더 확인해볼 내용 
  • func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool

Asks the delegate if a gestrue recognizer should require another gesture recognizer to fail. 
  • func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool

Asks the delegate if a gesture recognizer should be required to fail by another gesture recognizer. 
  • func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool

Asks the delegate if two gesture recognizers should be allowed to recognize gestures simultaneously. (제스쳐 두개가 동시에 인식되는지 여부) 

API Reference 

스테이터스 바에 블러 뷰 얹기 (Status Bar added Blur View)


상황 
  • 웹뷰의 top과 bottom을 Safe Area.top,  Safe Area.Bottom 이 아니라 SuperView의 top과 bottom으로 맞춤 
  • 네비게이션바가 숨김처리 되었을 경우 스테이터스 바 뒤로 컨텐츠가 겹쳐 보임
  • 스테이터스 바에 블러뷰를 얹고자 함  
방법 
  • 블러효과를 가진 비쥬얼이펙트뷰를 생성 (블러 효과 prominent로) 
  • 코드상에서 오토레이아웃 지정, Programmatic AutoLayout (top, left, right는 view에 맞추고, 높이를 스테이터스바에 맞춤)
  • 웹뷰와의 경계를 표시하기 위해 레이어로 라인을 그림 (Draw Bottom Line on View) 
내용 
        let blurEffect = UIBlurEffect(style: .prominent)
        let statusBarBlurView = UIVisualEffectView(effect: blurEffect)
        self.view.addSubview(statusBarBlurView)
        
        statusBarBlurView.translatesAutoresizingMaskIntoConstraints = false
        statusBarBlurView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        statusBarBlurView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        statusBarBlurView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        statusBarBlurView.heightAnchor.constraint(equalToConstant: UIApplication.shared.statusBarFrame.height).isActive = true
        
        statusBarBlurView.layer.borderWidth = 0.25

화면

2019년 9월 16일 월요일

탭 전환시 애니메이션 효과 주기


방법 
  • TabBarControllerDelegate Method 구현 
내용
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        
        let fromView = tabBarController.selectedViewController?.view
        let toView = viewController.view
        
        if fromView == toView {
            if isTabActivated {
                initWebView()
            }
            return false
        }
        
        UIView.transition(from: fromView!, to: toView!, duration: 0.3, options: UIView.AnimationOptions.transitionCrossDissolve) { (_) in
        }
        
        return true
    }

이슈 및 추가확인 사항 
  • 해당 방법으로는 AnimationOption의 항목으로 애니메이션 효과를 줄 수 있었다.
  • shouldSelect 와 didSelect 항목이 같이 구현되면 충돌이 있는 것 같다. 작동하던 코드 하나가 더이상 작동하지 않아 shouldSelect로 옮김 
API Reference 
  • func tabBarController(UITabBarController, shouldSelect: UIViewController) -> Bool
  • UIView.AnimationOptions 

참고: 1, 2, 3.

화면 스크롤시 애니메이션으로 네비게이션 바 숨기기

목적 및 의도 
  • 화면을 스크롤 할 때 애니메이션효과와 함께 네비게이션바를 숨기기 
  • 기본 프로퍼티 hidesBarsOnSwipe로 네비게이션 바 숨김이 가능하지만 탭바와 애니메이션 타이밍이 조금 다름. (탭바의 경우 터치 종료시점에 애니메이션이 발생) 
  • 탭바와 동일한 방식으로 숨기기 
방법  

self.navigationController?.hidesBarsOnSwipe = true

또는 

이슈 및 더 확인해 볼 내용
  • 웹 페이지의 헤더 부분 및 Reload 되는 화면에서 프레임 문제 발생하여 자연스럽지 않음 
  • 웹뷰의 제약조건 확인 필요 (webView.top,  Safe Area, SuperView.top)
  • 웹뷰(WKWebView)의 Back, Forward 할 때 프레임이 조금씩 맞지 않는 것 같다. 네비게이션 바가 숨겨진 상태에서 앞으로 갈 때에는(goForward) 네비게이션 바가 숨겨진 상태는 비워둔 채 웹페이지가 로드되고, 뒤로 갈때에는 네비게이션 바에 가려진 상태로 뒤로가진다. 
  • 웹뷰에서의 네비게이션 바 숨기기는 조금 더 찾아볼 필요가 있음 
참고: 12345.

화면 스크롤시 애니메이션으로 탭바 숨기기


목적 및 의도 
  • 화면(웹뷰)를 아래로 스크롤 하여 탭바를 숨길 때 애니메이션 효과를 주기 
방법 
  • lastOffsetY 변수 선언
  • webview scrollview delegate 선언 
  • delegate method 구현 
내용 
// Mark: ScrollViewDelegate method. 
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
      lastOffsetY = scrollView.contentOffset.y
    }
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        let hide = scrollView.contentOffset.y > self.lastOffsetY
        if  hide {
            visibleTabBar(isHidden: true)
        } else {
            visibleTabBar(isHidden: false)
        }
    }

// Mark: Custom method
    func visibleTabBar(isHidden: Bool) {
        guard let tabBar = self.tabBarController?.tabBar else {return}
        if tabBar.isHidden == isHidden {
            return
        }
        let frame = tabBar.frame
        let height = tabBar.frame.size.height
        let offsetY = isHidden ? height : -height
        if tabBar.isHidden == true {
          tabBar.isHidden = false
        }
        UIView.animate(withDuration: 0.3, animations: {
            self.tabBarController?.tabBar.frame = frame.offsetBy(dx: 0, dy: offsetY)
        }) { (_) in
            tabBar.isHidden = isHidden
        }
    }

이슈 및 추가 확인 사항 
  • tabBar.isHidden 으로는 애니메이션 효과를 주지 못해 먼저 애니메이션효과와 함께 프레임을 조정한 뒤, isHidden 값을 true 로 변경하였음
  • 스크롤 여부 확인 방법 더 찾아보기: scrollView.panGestureRecognizer.translation(in: scrollView).y <


화면 스크롤시 탭바 숨기기


목적 및 의도
  • 웹뷰를 아래로 스크롤시 탭바를 숨기기, 위로  스크롤시 탭바 보이기 (toggle tabbar hide/show) 
방법
  • lastOffsetY 변수 선언
  • webview scrollview delegate 선언 
  • delegate method 구현 
내용
webView.scrollView.delegate = self
var lastOffsetY: CGFloat = 0
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        lastOffsetY = scrollView.contentOffset.y
    }
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        let hide = scrollView.contentOffset.y > self.lastOffsetY
        guard let tabBar = self.tabBarController?.tabBar else { return; }
        tabBar.isHidden = hide
    }

이슈 및 추가확인사항
  • 애니메이션 효과 없음 



2019년 9월 15일 일요일

선택된 탭에서 해당 탭바 아이템 클릭하여 기능 구현


설명 및 의도 
  • 웹뷰를 사용하는 탭에서 해당 탭바 아이템을 선택할 경우 웹뷰의 첫 화면으로 이동하고자 함 
예시 
  • 네이버 뉴스 포탈화면에서 기사(아티클)화면으로 이동한 뒤 다시 탭 아이템을 선택할 경우 뉴스 포탈로 이동 
  • 다른 탭에서 넘어올 때에는 뉴스 포털화면이 아닌 읽고 있던 페이지로 이동 
방법 
  • isTapActivated 불리언 변수 생성 
  • 다른 탭으로 이동하거나, 탭이 선택될 때 불리언 값 변경 
  • tabbarControllerDelegate 설정 
과정
  • var isTapActivated = true 
  • viewdidDisappear(_:)  에서 isTapActivated 값을 false , viewdidAppear(_:) 에서 isTapActivated 값을 true 로 변경 
  • if tabBarController.selectedViewController == self && isTapActivated { initWebView() }
이슈 및 추가확인사항 
  • 해당 뷰 컨트롤러에 네비게이션 컨트롤러를 임베드할경우 작동하지 않음
  • viewDidDisappear(_:) 가 아닌 viewWillDisappear(_:)에서 isTapActivated 값 변경 
API Reference 
  • Protocol UITabBarControllerDelegate
  • func tabBarController(UITabBarController, shouldSelcet: UIViewController) -> Bool
  • func tabBarController(UITabBarController, didSelect: UIViewController) -> Bool