iOS Manually Implements tableview Reusable Mechanisms

Keywords: github iOS

How tableview is implemented:
1. When adding a reusable Id to a view to use, look for a reusable view from the reuse cache pool and create one to add to the cache pool if not
2. Remove invisible view s from the screen and put them in a reusable pool
This is a simple implementation of this reusable feature, creating a small demo with a single view of screen size that can slide indefinitely in just two views

First you need to write a dataSourse protocol for external use

protocol CustomTableViewDataSource:NSObjectProtocol {
    func CustomTableView(_ customTableView: NKCustomTableView, viewForRow itemView:UIView, and index:Int) ->UIView
}

Simple implementation of reusable functionality, so there is no need to dynamically add views, the number and size are all written to death. This set is equivalent to a cache pool, where arrays can be used, but since finding a reusable view is random access and does not require sequential storage, there is no need to use array to determine and decide whether a view can be reused requires a flag, which is handled using the tag that comes with viewYes, when tag 1 is reusable for delegates (not currently shown on the interface), and 0 is not reusable (already shown on the interface)

lazy var views:Set<UIView> = {

        let size = self.frame.size

        var view1 = UIView()
        view1.backgroundColor = UIColor.blue
        view1.frame.size = size
        view1.tag = 1

        var view2 = UIView()
        view2.backgroundColor = UIColor.orange
        view2.frame.size = size
        view2.tag = 1

        return NSSet(array: [view1,view2]) as! Set<UIView>
    }()//Initialize view, where you can only see up to two copies of the same screen, so initializing two is sufficient

You then need to add a view after initialization, where you create a first tag to determine if it's initialized, because layoutsubviews aren't called only once, and when I try, I find that it happens to be called just once when my finger's movement is equal to the width of the screen (I didn't notice for a long time at first)?

 override func layoutSubviews() {
        super.layoutSubviews()
        if first{
            for view in views {
                view.frame.origin = CGPoint(x: 0, y: 0)
                view.tag = 0
                dataSource?.CustomTableView(self, viewForRow: view, and: currentItem)
                self.addSubview(view)
                break
            }
            first = false
        }

    }

Implementing from scratch eliminates the need for scrollview to be a parent and inherits the UIView directly, so you need to decide on your own gesture sliding to position the child view you added to the view to achieve the effect of sliding, override the toucesMoved method, and add two recorded variables

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        //Gets the finger offset of each call to the method relative to the last call
        let offset = (touches.first?.previousLocation(in: self).x)! - (touches.first?.location(in: self).x)!
        //Record the distance from the left side of the current screen to the origin
        contentOffset += offset

After the screen sliding is completed, two functions are required. The first one detects if the view leaves the visible range of the screen, and if it does, removes the view and adds it to the reusable hash table. The left and right boundaries in this code are provided for the second function, which is used when adding the view to the corresponding location. Record the range that can be displayed at the current location to determine the reusable bits.Where should location be added

        //Record the left and right boundaries of the view when it has been displayed
        var rightBound:CGFloat = 0
        var leftBound:CGFloat = CGFloat(MAXFLOAT)
        //Traverse the hash table to find the current view to display
        for view in views {
            if view.tag == 0 {
                //Offset all view s to display
                view.frame.origin.x = view.frame.origin.x - offset
                //Determine if the current View is invisible if its left border is larger than the leftmost edge of the screen, or if its right border is smaller than the rightmost edge of the screen
                if view.frame.origin.x > self.frame.size.width || view.frame.origin.x < -self.frame.size.width{
                    //Remove the View and make it reusable
                    view.removeFromSuperview()
                    for subView in view.subviews{
                        subView.removeFromSuperview()
                    }
                    view.tag = 1
                }else{
                    //Record left and right boundary values when the view will not be removed
                    rightBound = max(rightBound, view.frame.origin.x + view.frame.width)
                    leftBound = min(leftBound, view.frame.origin.x)
                }
            }
        }

Second function, automatically removes the view from the reuse pool and adds it to the corresponding location

    func autoAddView(leftBound:CGFloat,rightBound:CGFloat){
        //If the viewable right boundary is smaller than the screen right boundary, a new view will appear
        if rightBound < self.frame.size.width {
            currentItem += 1
            //Convenient hash table to find reusable view s
            for view in views {
                if 1 == view.tag {
                    //Position the view at the right boundary and make it non-reusable
                    view.frame.origin = CGPoint(x: rightBound, y: CGFloat(0))
                    if dataSource != nil {
                        dataSource?.CustomTableView(self, viewForRow: view, and: currentItem)
                    }
                    self.addSubview(view)
                    view.tag = 0
                    break
                }
            }
        }else if leftBound > 0{//If the viewable left boundary is larger than the screen left boundary, a new view will appear
            currentItem -= 1
            for view in views {
                if 1 == view.tag {
                    if dataSource != nil {
                        dataSource?.CustomTableView(self, viewForRow: view, and: currentItem)
                    }
                    view.frame.origin = CGPoint(x: leftBound - self.frame.size.width, y: CGFloat(0))
                    self.addSubview(view)
                    view.tag = 0
                    break
                }
            }
        }
    }

This completes a simple, reusable, infinite sliding view with code reference https://github.com/NKJay/NKCustomTableView
I'm just an iOS white graduate. I'm not very expressive. What's wrong with this? I'd like you to point out

Posted by stevepatd on Thu, 06 Jun 2019 09:24:55 -0700