High imitation WeChat article floating ball
In the latest version 6.6.7 of WeChat, a new article floating ball function has been added. While you are reading the article, a friend suddenly sends an urgent message, and you need to reply immediately. Or maybe you happen to be passing by a snack bar and need to temporarily open WeChat payment, or temporarily interrupt reading. In the past, I could only exit the article details page, and after finishing my work, I could find the original article next to each other. For heavy WeChat users like us, it’s really painful every time we encounter this situation. Therefore, when this function was launched, it was immediately updated to the latest version. This function feels like meeting a close friend, and it is very easy to use. You can feel it through the animation below
In fact, the concept of floating balls has been around for a long time. For example, 360 Assistant’s traffic monitoring ball, iPhone’s own AssistiveTouch (that cute little white ball), etc.
If you like the Github address, click it ❤️
After experiencing it, my hands are itchy and I can’t help but want to imitate it. If your APP can integrate this function, I think it can instantly elevate your APP to a new level. Okay, let’s dissect the core technical points of the WeChat article floating ball one by one:
When we use the screen edge gesture to pop the view, there will be a rounded corner prompt in the lower right corner, which moves with the progress of the gesture. How to get the progress of UIScreenEdgePanGestureRecognizer
? Because interactivePopGestureRecognizer
that comes with the system is encapsulated, we cannot hook its action to get the gesture progress inside. Therefore, we need to find another way.
self . interactivePopGestureRecognizer ? . delegate = self
func gestureRecognizer ( _ gestureRecognizer : UIGestureRecognizer , shouldRecognizeSimultaneouslyWith otherGestureRecognizer : UIGestureRecognizer ) -> Bool {
return true
}
UIScreenEdgePanGestureRecognizer
to the UINavigationController to obtain the progress of the pop gesture. let gesture = UIScreenEdgePanGestureRecognizer ( target : self , action : #selector ( handleNavigationTransition ( gesture : ) ) )
gesture . edges = . left
self . view . addGestureRecognizer ( gesture )
In this way, there are two UIScreenEdgePanGestureRecognizer
that can respond at the same time. The one that comes with the system still maintains the original logic, and the new one we added is used to obtain the progress of the pop gesture. The two are in harmony and enjoy themselves. This technique of mine is also used in this article on iOS: Integrate mainstream APP profile pages (such as Jianshu, Weibo, etc.) in one minute
Since the floating ball can be suspended on any page, it must be placed on a new UIWindow. For example, when the system keyboard pops up, it is hosted by a UIRemoteKeyboardWindow
. Then the life cycle of this window does not depend on a certain page, so it is better to use a singleton to implement it. This piece of code is relatively scattered. You can understand it by looking directly at the source code.
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
, and then use the contains(point)
method of CGPath
to determine. 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 )
}
Students who don’t know much about this topic can refer to this article. An article to understand the use of event delivery, responder chain, hitTest and pointInside
You can see that the article opened by clicking on the floating ball is implemented through a custom transition animation, starting from the position of the floating ball. There are many articles explaining how to customize transition animation, but I recommend you read this article to quickly integrate custom transition effects + full gesture driver with a few lines of code
WeChat's floating ball uses relatively many technical points, and the code is relatively scattered. If your APP wants to integrate this function, you need to carefully package the code. I think how to design a requirement is more important than how to implement it. In the process of imitating, I found that there are many detailed logics, which are interlocking with each other, and finally the floating ball function you are using is presented. It is said that programmers and product managers are in love with each other. Here I want to give a thumbs up to the product manager of this function?
If there are any problems in the code, or if you have any questions, you can give me feedback and I will deal with it as soon as possible. If you like the Github address, click it ❤️