当前位置: > > > 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()。否则自定义的刷新界面高度不会自动拉伸,会变成固定高度的。
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尺寸在下拉时也会改变