IOS development – list returns the top button (ScrollToTopButton)

First, the origin of ScrollToTopButton

IOS development - list returns the top button (ScrollToTopButton)
Paste_Image.png

A few days ago, received a request: list from bottom to top slide more than one screen, appear to return to the top button, hover 3 seconds later disappeared. Analysis of a list of waves is actually UITableView, we all know that when the UIScrollView scrollsToTop attribute assigned to true, click the status bar will be returned to the top, then why do you need this requirement? Well, that’s a good question. Here’s a wave of explanation from the product manager, and figure two is the discussion of colleagues. I think it doesn’t matter if you don’t add it, but when it comes out, it’s pretty good to use it.
about ScrollToTopButton, in fact, it is a view, and then addSubview, a UIButton, why do you write that? Well… Is it convenient to adapt? Let’s just feel that way. Then why is it called ScrollToTopButton? As the name suggests, roll to the top of the button well, no way, I can not think of a good name.

IOS development - list returns the top button (ScrollToTopButton),
, diagram 1,.Png
IOS development - list returns the top button (ScrollToTopButton)
, figure two,.Png

Two, a wave operation effect

Aha, ha, ha, pretty good, huh?! Next, look at the specific code and Implementation…

IOS development - list returns the top button (ScrollToTopButton)
run.gif

Three, a wave of analysis

How to add ScrollToTopButton to the view, there are two options: one is to write a UIScrollView extension in the expansion, write a method, then the corresponding interface in controller, you can call the extension method; the two is the use of runtime in the load function, the didMoveToSuperview method to replace the UIView system. In the replacement method, add ScrollToTopButton. But there are problems.

1, about the realization of ScrollToTopButton

What do you want to see, I write junk code? Not good? Here, I don’t post my garbage code. At the end of the article will be posted GitHub address, interested students can go to see, what suggestions, welcome great God message guidance.

Code description

  • About the observe method of KVO, why can’t there be relevant monitoring method? Why isn’t there a removeObserver method that doesn’t crash? This article will give you some answers. Share a KVO extension, if you do not want to import FBKVOController, and the KVO expansion, observe only needs to be written into the system can be, don’t forget to removeObserver at the appropriate time, or will crash.
  • For requirements, hover after 3 seconds, when the scroll is stopped. The method used here is open func perform (aSelector: Selector with _, anArgument: Any, afterDelay delay:? TimeInterval) and open class to delay the hidden func cancelPreviousPerformRequests (withTarget aTarget: Any, selector aSelector: Selector, object anArgument: Any?) method to cancel delay execution. Why doesn’t
    delay using GCD’s dispatch_after? As far as I know, once the dispatch_after is delayed, there seems to be no correlation method to cancel the delay. That is to say, when we stopped rolling, called dispatch_after, but when we are rolling again, dispatch_after delay is not be canceled, the time delay is set to, or will be delayed code. The delay in the
    performSelector method can be invoked by calling the cancelPreviousPerformRequests method to cancel. It is important to note that when you invoke this method, you need to pass in a method that was previously delayed. Reference article: cancel the deferred execution function cancelPreviousPerformRequestsWithTarget 2, and how do you add ScrollToTopButton to view? (1) the advantage of writing a UIScrollView extended write extension is that you can call extensions as long as it is UIScrollView or inherited from UIScrollView. Why is it possible to return to ScrollToTopButton without returning? When you return ScrollToTopButton, you can save it and then make a judgment, and call the addScrollToTopBtn method if it is nil. In fact, do not do so, written in the viewDidload method, there should be no problem. Extension UIScrollView func (addScrollToTopBtn) {-> ScrollToTopButton {return ScrollToTopButton (frame: CGRect (x: (self.width – 40) / 2, y:, self.height + 100, width: 40, height: 40), scrollView: self)}} calling this method: if the method returns a value: _ = tableView.addScrollToTopBtn (), is _ the variable you define, here I will omit; if there is no return value: (tableView.addScrollToTopBtn). Do you think it’s simple and convenient? The controller doesn’t need to care about how ScrollToTopButton is implemented and how to add it to view.
    said before, “with extended methods, there will be problems.”. If the entire list, there are dozens of app, then you need to control in this list of dozens of 11, paste (tableView.addScrollToTopBtn), this code program ape is “very lazy”, there is no way you can, the controller each list do not write this code, you can return to the top of the button, all added to the list? Look at the second method. (2) the use of Method Swizzling – Methods of exchange, if there are students who do not understand Method Swizzling, recommended to see the jade make the world a blog, Objective-C, Method, Swizzling, written in great detail. Of course, you can also learn through other articles.

Here, we use the runtime method to exchange, replace the system method by our own method, add judgment in our own method, and then add the button to the list. The requirement is that when we slide the list, it will return to the top of the button display, the first one is to think of whether to replace the scrollViewDidScroll method, after a few attempts, unfortunately not. Runtime exchange of methods that can be applied to replace the class itself. No agent scrollView, second thought is to replace the contentOffset set method, but the final scheme is choose to replace the UIView didMoveToSuperview method, this method is to call this method when the view of the parent view changes often, so we can replace this system method.
to the new extension of the UIScrollView, UIScrollView+Runtime, &lt, objc/runtime.h> import #import; in the load method (if Swift, then the initialize method), replacement method. Why in the load method, you can get to know iOS + initialize and +load through this article. There may be some articles that will say that in the load method, write a dispatch_once, so that the code is executed only once. In fact, this is not necessary to add a dispatch_once, because the load itself will only enter once. So it doesn’t matter if you don’t add dispatch_once. The specific implementation of load is as follows:

(void + load) {Method ori_Method = class_getInstanceMethod ([UIScrollView, class], @selector (didMoveToSuperview)); Method ud_Mothod = class_getInstanceMethod ([UIScrollView class], @selector (ud_didMoveToSuperview)); method_exchangeImplementations (ori_Method, ud_Mothod);} - {[self (void) ud_didMoveToSuperview ud_didMoveToSuperview] if (self.superview; & & ([self isMemberOfClass:[UITableView class]])) {for (UIView *view in self.superview.subviews if ([view isKindOfClass:[ScrollToTopButton) {class]]} {return}); [[ScrollToTopButton alloc] initWithFrame:CGRectMake (self.width, self.height, 48, 48) scrollView: (UIScrollView * self]);}}

When the code is finished, a Command+R, and the result is crash.

IOS development - list returns the top button (ScrollToTopButton)
Paste_Image.png

in the crash information can be seen because of the didMoveToSuperview method problems. It turned out that UIScrollView didn’t implement the didMoveToSuperview method, and the direct exchange of IMP was dangerous. Because if this method is not implemented in this class, class_getInstanceMethod () is a return to the parent class Method (method_exchangeImplementations), so the original implementation of the superclass (IMP) with this kind of Swizzle exchange. In this way, other parent and other subclasses of methods call will be a problem, the most serious is Crash.
what about that? Then you can’t use UIScrollView extensions, but we can change to UIView extensions, and the effect is the same. After the
is modified, run again. No, crash. Just look for a list. After sliding, the button that returns to the top is also displayed. That means that the runtime method is already available. However, because it is the extension of UIView, in our ud_didMoveToSuperview, we need to evaluate the current self, [self isMemberOfClass:[UITableView class], is UITableView, we can add a button to return to the top of the.
needs special attention here: in the way we replace, be sure to call your own method, non systematic method, otherwise it will lead to a dead loop. [self ud_didMoveToSuperview]; this line of code is actually called the didMoveToSuperview method of the system.

What’s the problem with the program exchanged with Method Swizzling?

  • With this scheme, all lists have been added, but if I have some lists, don’t add them? Do you think there is a hole? One way to do this is to use the ud_didMoveToSuperview method in if to determine the list to be added, but doing so destroys the package.
  • The second problem is the problem of ScrollToTopButton’s “frame”. Because we’re taking scrollView.superview for calculations, and if there’s a similar tool view on the bottom of the view? That ScrollToTopButton’s frame is calculating wrong.
  • Another problem is that you’ll find this ScrollToTopButton, created only, without remove. After hiding, it is also just hidden, and there is no remove from the current view, which also needs to be solved.
  • For the above problems, I haven’t come up with a better solution at present. If there are better solutions for students, welcome to pass the message guidance.
    IOS development - list returns the top button (ScrollToTopButton)
    Paste_Image.png
IOS development - list returns the top button (ScrollToTopButton)
Paste_Image.png

(3) in addition to the above two programs, there are no third programs? The answer is yes.

We can also write exactly the same code in each controller that needs to be added, from the creation button to the add.
but this way of writing is not only disgusting, but also disgusting others. This repetitive code is not maintainable at all. If it changes to another day, this button needs to be replaced, and then you break down. Write less repetitive code, and write more maintenance, multipurpose extensions and packages…

Four, to a demo

ScrollToTopButtonDemo
, if you are interested in students, you can download this very simple demo, written a bit rotten, but the emphasis is on the above ideas and methods of implementation. I write garbage code, just look at it.