当前位置: > > > Swfit - 使用自定义的UIRefreshControl下拉刷新界面

Swfit - 使用自定义的UIRefreshControl下拉刷新界面

默认 UIRefreshControl 下拉刷新界面是一个菊花进度条+一段描述文字,略显单调。其实我们可以使用自己创建的界面视图,方便我们实现各种效果。比如添加个动态图片,添加个动画效果什么的。

1,下面演示如何使用自定义的下拉刷新界面,效果图如下:

(1)随着下拉,界面透明度从0开始慢慢显示出来
          

(2)开始刷新时,文字会有跑马灯效果(字体逐个变大,同时会变色)
          


2,首先使用xib创建一个界面(RefreshView.xib)
(1)其属性做如下设置

(2)在里面添加6个Label,用来显示描述文字(由于文字要单独播放动画,所以要分开)

(3)分别给各个Label添加约束
我习惯先给中间一个定好位,其它的文本标签根据中间的来排。由于是6个Label,那就先设置第3个Label(“刷”)的约束,宽高固定,垂直居中,水平-19居中。
          
设置第2个Label(“拉”)约束,宽高固定,水平距右10,垂直居中
          

其它标签依次类推(间距都是10)

3,主页代码
(1)为更好的看到效果,模拟网络请求,这里使用NSTimer延时3秒生成数据
(2)一定要把 UIRefreshControl backgroundColor tintColor 设置成 UIColor.clearColor()。否则自定义的刷新界面高度不会自动拉伸,会变成固定高度的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import UIKit
 
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
     
    //新闻列表
    @IBOutlet weak var newsTableView: UITableView!
     
    //新闻数组集合
    var dataArray:[HanggeArticle] = [HanggeArticle]()
     
    //拉刷新控制器
    var refreshControl = UIRefreshControl()
     
    var customView: UIView!
     
    var labelsArray: Array<UILabel> = []
     
    var currentColorIndex = 0
     
    var currentLabelIndex = 0
     
    var timer: NSTimer!
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //添加刷新
        refreshControl.addTarget(self, action: "refreshData",
            forControlEvents: UIControlEvents.ValueChanged)
         
        //背景色和tint颜色都要清除,保证自定义下拉视图高度自适应
        refreshControl.backgroundColor = UIColor.clearColor()
        refreshControl.tintColor = UIColor.clearColor()
         
        newsTableView.addSubview(refreshControl)
        loadData()
         
        //加载自定义刷新界面
        loadCustomRefreshView()
    }
     
     
    //自定义刷新界面
    func loadCustomRefreshView() {
        let refreshContents = NSBundle.mainBundle().loadNibNamed("RefreshView",
            owner: self, options: nil)
         
        customView = refreshContents[0] as! UIView
        customView.frame = refreshControl.bounds
         
        customView.alpha = 0.0
         
        for var i=0; i<customView.subviews.count; ++i {
            labelsArray.append(customView.viewWithTag(i + 1) as! UILabel)
        }
         
        refreshControl.addSubview(customView)
    }
     
    //滚动视图开始拖动
    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        if !refreshControl.refreshing {
            self.labelsArray[0].text = "下"
            self.labelsArray[1].text = "拉"
            self.labelsArray[2].text = "刷"
            self.labelsArray[3].text = "新"
            self.labelsArray[4].text = "数"
            self.labelsArray[5].text = "据"
        }
    }
     
    //视图拖动
    func scrollViewDidScroll(scrollView: UIScrollView) {
        //加载界面透明度改变
        let sg = ( scrollView.contentOffset.y * -1 ) / 60.0
        customView.alpha = sg
    }
     
    // 刷新数据
    func refreshData() {
        self.labelsArray[0].text = "数"
        self.labelsArray[1].text = "据"
        self.labelsArray[2].text = "加"
        self.labelsArray[3].text = "载"
        self.labelsArray[4].text = "中"
        self.labelsArray[5].text = "..."
         
        //播放动画
        playAnimateRefresh()
         
        //模拟加载数据
        timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self,
            selector: "loadData", userInfo: nil, repeats: true)
    }
     
    //播放文字动画
    func playAnimateRefresh() {
        //文字放大,变色动画
        UIView.animateWithDuration(0.15, delay: 0.0,
            options: .CurveLinear, animations: { () -> Void in
                 
            self.labelsArray[self.currentLabelIndex].transform =
                CGAffineTransformMakeScale(1.5, 1.5)
            self.labelsArray[self.currentLabelIndex].textColor =
                self.getNextColor()
             
            }, completion: { (finished) -> Void in
                 
                //文字样式还原动画
                UIView.animateWithDuration(0.1, delay: 0.0,
                    options: .CurveLinear, animations: { () -> Void in
                         
                    self.labelsArray[self.currentLabelIndex].transform =
                        CGAffineTransformIdentity
                    self.labelsArray[self.currentLabelIndex].textColor =
                        UIColor.blackColor()
                     
                    }, completion: { (finished) -> Void in
                        ++self.currentLabelIndex
                         
                        if self.currentLabelIndex == self.labelsArray.count - 1 {
                            self.currentLabelIndex = 0
                        }
                         
                        //没加载完则继续播放动画
                        if self.refreshControl.refreshing {
                            self.playAnimateRefresh()
                        }else{
                            self.currentLabelIndex = 0
                        }
                })
        })
    }
     
    //计时器时间到,加载数据
    func loadData() {
        //移除老数据
        self.dataArray.removeAll()
        //随机添加5条新数据(时间是当前时间)
        for _ in 0..<5 {
            let atricle = HanggeArticle(title: "新闻标题\(Int(arc4random()%1000))",
                createDate: NSDate())
            self.dataArray.append(atricle)
        }
        self.newsTableView.reloadData()
        self.refreshControl.endRefreshing()
         
        timer?.invalidate()
        timer = nil
    }
     
    // 返回记录数
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataArray.count;
    }
     
    // 返回单元格内容
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
        -> UITableViewCell {
            let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle,
                reuseIdentifier: "myCell")
             
            //设置单元格标题
            let atricle: HanggeArticle = dataArray[indexPath.row] as HanggeArticle
            cell.textLabel?.text = atricle.title
             
            //设置单元格副标题
            let dateFormatter = NSDateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
            let str = dateFormatter.stringFromDate(atricle.createDate)
            cell.detailTextLabel?.text = str
             
            return cell;
    }
     
    //获取下一个颜色
    func getNextColor() -> UIColor {
        var colorsArray: Array<UIColor> = [UIColor.magentaColor(),
            UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(),
            UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
         
        if currentColorIndex == colorsArray.count {
            currentColorIndex = 0
        }
         
        let returnColor = colorsArray[currentColorIndex]
        ++currentColorIndex
         
        return returnColor
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
 
//新闻结构体
struct HanggeArticle {
    var title:String
    var createDate:NSDate
}

4,源码下载:hangge_936.zip
评论4
  • 4楼
    2016-07-05 21:23
    pencil

    博主你好,
    refreshControl.addTarget(self, action: "refreshData", forControlEvents: .ValueChanged)
    这个绑定的方法是valueChange,现在是向下拉一段距离后就会触发更新,我想实现松开手才进行更新,但是我在绑定方法里面进行了参数修改,尝试无果,望指导

    站长回复

    你可以不使用ValueChanged事件方法,而是改用在scrollViewDidEndDecelerating方法中触发数据刷新操作(记得刷新前判断下refreshControl.refreshing)

  • 3楼
    2016-06-24 11:51
    swiftLearning

    航哥,上拉加载更多怎样做的,个人比较菜,望指导....

    站长回复

    好的,后面我会写篇上拉加载的文章。按计划,要排到下个月了。

  • 2楼
    2015-12-17 15:27
    kuso

    你demo中的文字动画,可以用CA动画替换么?需要注意什么???

    站长回复

    当然可以,毕竟UIView动画本质上是对CoreAnimation动画的封装。
    对于样例中的效果,用UIView动画是因为写起来更简单。如果复杂的效果,UIView动画不好实现的话可以考虑使用CoreAnimation动画。

  • 1楼
    2015-12-17 10:02
    kuso

    我按照你的方法,设置了刷新动画customView.frame = refreshControl.bounds;
    但是动画宽度,高度固定为320,60,refreshControl.bounds赋给自定义动画钱也是320,60为什么?

    站长回复

    不管是4s还是6s,初始化的时候宽高确实都是320,60(因为还没显示出来)。但你下拉刷新的时候,refreshControl高度会动态改变,宽度也根据设备的不同而不同(比如6s就是375)。 同样,customView尺寸在下拉时也会改变