높은 모조 WeChat 기사 플로팅 볼
WeChat 최신 버전 6.6.7에는 새로운 기사 플로팅 볼 기능이 추가되었습니다. 기사를 읽고 있는 동안 친구가 갑자기 긴급한 메시지를 보냈고, 즉시 답장을 보내야 합니다. 아니면 스낵바를 지나가다가 일시적으로 WeChat 결제를 열거나 읽기를 일시적으로 중단해야 할 수도 있습니다. 예전에는 기사 세부정보 페이지만 나갈 수 있었고, 작업을 마친 후에는 원본 기사를 나란히 찾을 수 있었습니다. 우리처럼 WeChat을 많이 사용하는 사용자에게는 이런 상황이 발생할 때마다 정말 고통스럽습니다. 그래서 이 기능은 출시되자마자 바로 최신 버전으로 업데이트가 되었어요. 마치 친한 친구를 만나는 듯한 느낌이 들고, 사용하기도 아주 편해요. 아래 애니메이션을 통해 느껴보실 수 있습니다
사실 떠다니는 공이라는 개념은 오래 전부터 존재해 왔습니다. 예를 들어 360 Assistant의 교통 모니터링 공, iPhone의 AssistiveTouch(그 귀엽고 작은 흰색 공) 등이 있습니다.
Github 주소가 마음에 드셨다면 클릭해주세요 ❤️
겪어보니 손이 간지러워서 따라하고 싶을 정도입니다. 귀하의 앱이 이 기능을 통합할 수 있다면 귀하의 앱을 즉시 새로운 수준으로 끌어올릴 수 있다고 생각합니다. 좋아요, WeChat 기사 뜨는 공의 핵심 기술 사항을 하나씩 분석해 보겠습니다.
화면 가장자리 제스처를 사용하여 뷰를 팝업하면 오른쪽 하단에 둥근 모서리 프롬프트가 표시되며 제스처 진행에 따라 이동합니다. UIScreenEdgePanGestureRecognizer
의 진행 상황을 확인하는 방법은 무엇입니까? 시스템과 함께 제공되는 interactivePopGestureRecognizer
캡슐화되어 있으므로 동작을 연결하여 내부에서 동작 진행 상황을 가져올 수 없습니다. 그러므로 우리는 다른 방법을 찾아야 합니다.
self . interactivePopGestureRecognizer ? . delegate = self
func gestureRecognizer ( _ gestureRecognizer : UIGestureRecognizer , shouldRecognizeSimultaneouslyWith otherGestureRecognizer : UIGestureRecognizer ) -> Bool {
return true
}
UIScreenEdgePanGestureRecognizer
를 추가하여 팝 제스처의 진행 상황을 가져옵니다. let gesture = UIScreenEdgePanGestureRecognizer ( target : self , action : #selector ( handleNavigationTransition ( gesture : ) ) )
gesture . edges = . left
self . view . addGestureRecognizer ( gesture )
이런 식으로 동시에 응답할 수 있는 두 개의 UIScreenEdgePanGestureRecognizer
가 있습니다. 시스템과 함께 제공되는 것은 여전히 원래 논리를 유지하고 있으며, 우리가 추가한 새로운 것은 팝 제스처의 진행 상황을 얻는 데 사용됩니다. 서로 화합하고 행복합니다. 이 기술은 iOS의 이 기사에서도 사용됩니다. 1분 안에 주류 앱 프로필 페이지(예: Jianshu, Weibo 등) 통합
플로팅 볼은 어느 페이지에서나 정지될 수 있으므로 새 UIWindow에 배치해야 합니다. 예를 들어 시스템 키보드가 나타나면 UIRemoteKeyboardWindow
에 의해 호스팅됩니다. 그러면 이 창의 수명 주기는 특정 페이지에 의존하지 않으므로 싱글톤을 사용하여 구현하는 것이 더 좋습니다. 이 코드 조각은 비교적 분산되어 있습니다. 소스 코드를 직접 보면 이해할 수 있습니다.
override func point ( inside point : CGPoint , with event : UIEvent ? ) -> Bool {
let roundEntryViewPoint = self . convert ( point , to : roundEntryView )
if roundEntryView . point ( inside : roundEntryViewPoint , with : event ) == true {
return true
}
let collectViewPoint = self . convert ( point , to : collectView )
if collectView . point ( inside : collectViewPoint , with : event ) == true {
return true
}
return false
}
UIBezierPath
통해 1/4원을 그린 다음 CGPath
의 contains(point)
메서드를 사용하여 결정합니다. func updateBGLayerPath ( isSmall : Bool ) {
var ratio : CGFloat = 1
if !isSmall {
ratio = 1.3
}
let path = UIBezierPath ( )
path . move ( to : CGPoint ( x : viewSize . width , y : ( 1 - ratio ) * viewSize . height ) )
path . addLine ( to : CGPoint ( x : viewSize . width , y : viewSize . height ) )
path . addLine ( to : CGPoint ( x : ( 1 - ratio ) * viewSize . width , y : viewSize . height ) )
path . addArc ( withCenter : CGPoint ( x : viewSize . width , y : viewSize . height ) , radius : viewSize . width*ratio , startAngle : CGFloat ( Double . pi ) , endAngle : CGFloat ( Double . pi*3 / 2 ) , clockwise : true )
path . close ( )
bgLayer . path = path . cgPath
}
override func point ( inside point : CGPoint , with event : UIEvent ? ) -> Bool {
return bgLayer . path! . contains ( point )
}
이 주제에 대해 잘 모르는 학생은 이 기사를 참조할 수 있습니다. 이벤트 전달, 응답자 체인, hitTest 및 pointInside의 사용을 이해하기 위한 기사
플로팅볼을 클릭하여 열리는 기사가 플로팅볼의 위치부터 커스텀 전환 애니메이션을 통해 구현되는 것을 확인할 수 있습니다. 전환 애니메이션을 사용자 정의하는 방법을 설명하는 많은 기사가 있지만 몇 줄의 코드로 사용자 정의 전환 효과 + 전체 제스처 드라이버를 신속하게 통합하려면 이 기사를 읽는 것이 좋습니다.
WeChat의 플로팅 볼은 상대적으로 많은 기술적 포인트를 사용하며 코드가 상대적으로 분산되어 있습니다. 앱에 이 기능을 통합하려면 코드를 신중하게 패키징해야 합니다. 요구사항을 어떻게 구현하느냐보다 어떻게 요구사항을 설계하느냐가 더 중요하다고 생각합니다. 모방하는 과정에서 여러 가지 세부적인 로직들이 서로 연동되어 있다는 것을 알게 되었고, 마지막으로 여러분이 사용하고 있는 플로팅볼 기능이 제시되었습니다. 프로그래머와 제품 관리자는 서로 사랑에 빠진다고 합니다. 여기서 이 기능의 제품 관리자에게 엄지손가락을 치켜세우고 싶습니다.
코드에 문제가 있거나 질문이 있는 경우 피드백을 주시면 최대한 빨리 처리해 드리겠습니다. Github 주소가 마음에 드셨다면 클릭해주세요 ❤️