首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >高效学习iOS —— Stroke和路径动画

高效学习iOS —— Stroke和路径动画

作者头像
CC老师
发布于 2022-01-14 07:09:55
发布于 2022-01-14 07:09:55
2K00
代码可运行
举报
运行总次数:0
代码可运行

这是要完成的动画:

先添加需要的代码,这里需要将storyboard的ViewController换成

TableViewController,将Under Top Bars 和 Under Bottom Bars 取消到,然后为其

Embed in Navigation Controller,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import UIKit

func delay(seconds: Double, completion: @escaping ()-> Void) {
  DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}

class ViewController: UITableViewController {
    let packItems = ["Ice cream money", "Great weather", "Beach ball", "Swimsuit for him", "Swimsuit for her", "Beach games", "Ironing board", "Cocktail mood", "Sunglasses", "Flip flops", "Spare flip flops"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        self.title = "try"
        self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
        self.tableView.rowHeight = 64.0
        self.view.backgroundColor = UIColor(red: 0.0, green: 154.0/255.0, blue: 222.0/255.0, alpha: 1.0)

    }

    // MARK: Table View methods
    override func numberOfSections(in tableView: UITableView) -> Int {
      return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return 11
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
      cell.accessoryType = .none
      cell.textLabel!.text = packItems[indexPath.row]
      cell.imageView!.image = UIImage(named: "summericons_100px_\(indexPath.row).png")
      return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath, animated: true)
    }
}

(滑动显示更多)

然后创建一个文件,创建一个MyRefreshView类并且init需要传进来frame和UIScrollView,UIScrollView用来监听外界的拉取动作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyRefreshView: UIView, UIScrollViewDelegate {
    var scrollView: UIScrollView

    init(frame: CGRect, scrollView: UIScrollView) {
        self.scrollView = scrollView
        super.init(frame: frame)

        //add the background image
        let imgView = UIImageView(image: UIImage(named: "refresh-view-bg.png"))
        imgView.frame = bounds
        imgView.contentMode = .scaleAspectFill
        imgView.clipsToBounds = true
        addSubview(imgView)

    }

    required init(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
    }
}

(滑动显示更多)

接下来使用ShapeLayer 和 layer来创建圆形的点和 飞机图片。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//声明属性
  let ovalShapeLayer: CAShapeLayer = CAShapeLayer()
  let airplaneLayer: CALayer = CALayer()

(滑动显示更多)

然后设置好相关属性,这里圆的半径设置为view高度 * 0.8 的一半,这里lineDashPattern是创建路径的描边版本时应用的虚线图案(NSNumbers数组)。默认为nil,设置为[2, 3]之后就会把之前的一条线切割成一条一条的了。然后这里飞机先设置为隐藏的状态。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 ovalShapeLayer.strokeColor = UIColor.white.cgColor
    ovalShapeLayer.fillColor = UIColor.clear.cgColor
    ovalShapeLayer.lineWidth = 4.0
    ovalShapeLayer.lineDashPattern = [2, 3]

    let refreshRadius = frame.size.height/2 * 0.8

    ovalShapeLayer.path = UIBezierPath(ovalIn: CGRect(
      x: frame.size.width/2 - refreshRadius,
      y: frame.size.height/2 - refreshRadius,
      width: 2 * refreshRadius,
      height: 2 * refreshRadius)
      ).cgPath

    layer.addSublayer(ovalShapeLayer)

    let airplaneImage = UIImage(named: "airplane.png")!
    airplaneLayer.contents = airplaneImage.cgImage
    airplaneLayer.bounds = CGRect(x: 0.0, y: 0.0,
                                  width: airplaneImage.size.width,
                                  height: airplaneImage.size.height)

    airplaneLayer.position = CGPoint(
      x: frame.size.width/2 + frame.size.height/2 * 0.8,
      y: frame.size.height/2)

    layer.addSublayer(airplaneLayer)

    airplaneLayer.opacity = 0.0

(滑动显示更多)

这里使用UIScrollViewDelegate,然后调用scrollViewDidScroll和

scrollViewWillEndDragging来监听拉取的动作以及高度。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   func scrollViewDidScroll(_ scrollView: UIScrollView) {
    }

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    }

(滑动显示更多)

然后在viewController里面添加refreshVie。声明一个RefreshView属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  var refreshView: RefreshView!

然后,在viewDidLoad里面设置好属性并且添加为子View。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 let refreshRect = CGRect(x: 0.0, y: -kRefreshViewHeight, width: view.frame.size.width, height: kRefreshViewHeight)
    refreshView = RefreshView(frame: refreshRect, scrollView: self.tableView)
    refreshView.delegate = self
    view.addSubview(refreshView)

(滑动显示更多)

在viewController里面重写scrollViewDidScroll 和 scrollViewWillEndDragging方法,然后在里面相对应调用refreshView里面的方法,并且把参数传进去。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // MARK: Scroll view methods
  override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    refreshView.scrollViewDidScroll(scrollView)
  }

  override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    refreshView.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
  }

(滑动显示更多)

然后在refreshView里面的scrollViewDidScroll 和 scrollViewWillEndDragging方法进行对应的处理。

这里需要根据滚动的高度来进行判断进度,先声明一个progress的CGFloat属性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  var progress: CGFloat = 0.0

在scrollViewDidScroll 里面算出向上滚动的高度,然后处理本身view的大小和1比较取最小值,然后根据得到的progress设置ovalShapeLayer的strokeEnd和airplaneLayer的opacity。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offsetY = max(-(scrollView.contentOffset.y + scrollView.contentInset.top), 0.0)
    progress = min(max(offsetY / frame.size.height, 0.0), 1.0)

    redrawFromProgress(self.progress)

  }
   func redrawFromProgress(_ progress: CGFloat) {
    ovalShapeLayer.strokeEnd = progress
    airplaneLayer.opacity = Float(progress)
  }

(滑动显示更多)

接下来再为ovalShapeLayer和airplaneLayer添加动画。这里改变了scrollView的contentInset来显示这个view,再为ovalShapeLayer添加上strokeStart和strokeEnd的动画,然后为airplaneLayer添加上绕圆的位置的变化以及图片角度的变化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func beginRefreshing() {    
    UIView.animate(withDuration: 0.3) {
      var newInsets = self.scrollView.contentInset
      newInsets.top += self.frame.size.height
      self.scrollView.contentInset = newInsets
    }

    let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
    strokeStartAnimation.fromValue = -0.5
    strokeStartAnimation.toValue = 1.0

    let strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd")
    strokeEndAnimation.fromValue = 0.0
    strokeEndAnimation.toValue = 1.0

    let strokeAnimationGroup = CAAnimationGroup()
    strokeAnimationGroup.duration = 1.5
    strokeAnimationGroup.repeatDuration = 5.0
    strokeAnimationGroup.animations = [strokeStartAnimation, strokeEndAnimation]
    ovalShapeLayer.add(strokeAnimationGroup, forKey: nil)

    let flightAnimation = CAKeyframeAnimation(keyPath: "position")
    flightAnimation.path = ovalShapeLayer.path
    flightAnimation.calculationMode = .paced

    let airplaneOrientationAnimation = CABasicAnimation(keyPath: "transform.rotation")
    airplaneOrientationAnimation.fromValue = 0
    airplaneOrientationAnimation.toValue = 2.0 * .pi

    let flightAnimationGroup = CAAnimationGroup()
    flightAnimationGroup.duration = 1.5
    flightAnimationGroup.repeatDuration = 5.0
    flightAnimationGroup.animations = [flightAnimation, airplaneOrientationAnimation]
    airplaneLayer.add(flightAnimationGroup, forKey: nil)
  }

(滑动显示更多)

动画结束后需要把scrollView的contentInset调整回去。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 func endRefreshing() {
        UIView.animate(withDuration: 0.3, delay:0.0, options: .curveEaseOut,
      animations: {
        var newInsets = self.scrollView.contentInset
        newInsets.top -= self.frame.size.height
        self.scrollView.contentInset = newInsets
      },
      completion: {_ in
        //finished
      }
    )
  }

(滑动显示更多)

然后声明一个属性 isRefreshing来判断是否正在动画

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 isRefreshing = true

在beginRefreshing里面设为true,在endRefreshing设为false。然后在scrollViewDidScroll里面判断,如果正在执行动画就不调用redrawFromProgress。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 if !isRefreshing {
      redrawFromProgress(self.progress)
    }

(滑动显示更多)

再scrollViewWillEndDragging里面判断,如果没有正在执行动画并且progress大于等于1,那么就执行动画。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if !isRefreshing && self.progress >= 1.0 {
      beginRefreshing()
    }
  }

(滑动显示更多)

这里由外界决定什么时候结束刷新,那么就可以用delegate 或者 闭包来通知外界开始动画了。

这里声明一个闭包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    var refreshViewDidRefresh :(() -> Void)?

在scrollViewWillEndDragging里面判断不为空则调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        if !isRefreshing && self.progress >= 1.0 {
            if (refreshViewDidRefresh != nil) {
                refreshViewDidRefresh!()
            }
            beginRefreshing()
        }
    }

(滑动显示更多)

在ViewController 里面使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        if !isRefreshing && self.progress >= 1.0 {
            if (refreshViewDidRefresh != nil) {
                refreshViewDidRefresh!()
            }
            beginRefreshing()
        }
    }

(滑动显示更多)

这样动画就完成啦。

完整代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import UIKit

func delay(seconds: Double, completion: @escaping ()-> Void) {
  DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}
let kRefreshViewHeight: CGFloat = 110.0

class ViewController: UITableViewController {

    let packItems = ["Ice cream money", "Great weather", "Beach ball", "Swimsuit for him", "Swimsuit for her", "Beach games", "Ironing board", "Cocktail mood", "Sunglasses", "Flip flops", "Spare flip flops"]
    var refreshView: MyRefreshView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.view.backgroundColor = .clear
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        self.title = "try"
        self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]

        self.tableView.rowHeight = 64.0
        self.view.backgroundColor = UIColor(red: 0.0, green: 154.0/255.0, blue: 222.0/255.0, alpha: 1.0)
        let refreshRect = CGRect(x: 0.0, y: -kRefreshViewHeight, width: view.frame.size.width, height: kRefreshViewHeight)
        refreshView = MyRefreshView(frame: refreshRect, scrollView: self.tableView)

        refreshView.refreshViewDidRefresh = { [weak self] in
            delay(seconds: 4) {
                self?.refreshView.endRefreshing()
            }
        }
        view.addSubview(refreshView)
    }

    // MARK: Table View methods
    override func numberOfSections(in tableView: UITableView) -> Int {
      return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return 11
    }

    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
      refreshView.scrollViewDidScroll(scrollView)
    }

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
      refreshView.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
      cell.accessoryType = .none
      cell.textLabel!.text = packItems[indexPath.row]
      cell.imageView!.image = UIImage(named: "summericons_100px_\(indexPath.row).png")
      return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath, animated: true)
    }
}


(滑动显示更多)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import UIKit
import QuartzCore
protocol MyRefreshViewDelegate: class {
    func refreshViewDidRefresh(_ refreshView: MyRefreshView)
}
class MyRefreshView: UIView, UIScrollViewDelegate {
    var scrollView: UIScrollView
    weak var delegate: MyRefreshViewDelegate?
    let ovalShapeLayer: CAShapeLayer = CAShapeLayer()
    let airplaneLayer: CALayer = CALayer()
    var progress: CGFloat = 0.0
    var isRefreshing = false
    var refreshViewDidRefresh :(() -> Void)?

    init(frame: CGRect, scrollView: UIScrollView) {
        self.scrollView = scrollView
        super.init(frame: frame)

        //add the background image
        let imgView = UIImageView(image: UIImage(named: "refresh-view-bg.png"))
        imgView.frame = bounds
        imgView.contentMode = .scaleAspectFill
        imgView.clipsToBounds = true
        addSubview(imgView)

        ovalShapeLayer.strokeColor = UIColor.white.cgColor
        ovalShapeLayer.fillColor = UIColor.clear.cgColor
        ovalShapeLayer.lineWidth = 4.0
        ovalShapeLayer.lineDashPattern = [2, 3]

        let refreshRadius = frame.size.height/2 * 0.8

        ovalShapeLayer.path = UIBezierPath(ovalIn: CGRect(
            x: frame.size.width/2 - refreshRadius,
            y: frame.size.height/2 - refreshRadius,
            width: 2 * refreshRadius,
            height: 2 * refreshRadius)
        ).cgPath

        layer.addSublayer(ovalShapeLayer)

        let airplaneImage = UIImage(named: "airplane.png")!
        airplaneLayer.contents = airplaneImage.cgImage
        airplaneLayer.bounds = CGRect(x: 0.0, y: 0.0,
                                      width: airplaneImage.size.width,
                                      height: airplaneImage.size.height)

        airplaneLayer.position = CGPoint(
            x: frame.size.width/2 + frame.size.height/2 * 0.8,
            y: frame.size.height/2)

        layer.addSublayer(airplaneLayer)

        airplaneLayer.opacity = 0.0

    }

    // MARK: Scroll View Delegate methods

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = max(-(scrollView.contentOffset.y + scrollView.contentInset.top), 0.0)
        progress = min(max(offsetY / frame.size.height, 0.0), 1.0)

        if !isRefreshing {
            redrawFromProgress(self.progress)
        }
    }

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        if !isRefreshing && self.progress >= 1.0 {
            if (refreshViewDidRefresh != nil) {
                refreshViewDidRefresh!()
            }
            beginRefreshing()
        }
    }

    func redrawFromProgress(_ progress: CGFloat) {
        ovalShapeLayer.strokeEnd = progress
        airplaneLayer.opacity = Float(progress)
    }

    func beginRefreshing() {
        isRefreshing = true

        UIView.animate(withDuration: 0.3) {
            var newInsets = self.scrollView.contentInset
            newInsets.top += self.frame.size.height
            self.scrollView.contentInset = newInsets
        }

        let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
        strokeStartAnimation.fromValue = -0.5
        strokeStartAnimation.toValue = 1.0

        let strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd")
        strokeEndAnimation.fromValue = 0.0
        strokeEndAnimation.toValue = 1.0

        let strokeAnimationGroup = CAAnimationGroup()
        strokeAnimationGroup.duration = 1.5
        strokeAnimationGroup.repeatDuration = 5.0
        strokeAnimationGroup.animations = [strokeStartAnimation, strokeEndAnimation]
        ovalShapeLayer.add(strokeAnimationGroup, forKey: nil)

        let flightAnimation = CAKeyframeAnimation(keyPath: "position")
        flightAnimation.path = ovalShapeLayer.path
        flightAnimation.calculationMode = .paced

        let airplaneOrientationAnimation = CABasicAnimation(keyPath: "transform.rotation")
        airplaneOrientationAnimation.fromValue = 0
        airplaneOrientationAnimation.toValue = 2.0 * .pi

        let flightAnimationGroup = CAAnimationGroup()
        flightAnimationGroup.duration = 1.5
        flightAnimationGroup.repeatDuration = 5.0
        flightAnimationGroup.animations = [flightAnimation, airplaneOrientationAnimation]
        airplaneLayer.add(flightAnimationGroup, forKey: nil)
    }

    func endRefreshing() {

        isRefreshing = false

        UIView.animate(withDuration: 0.3, delay:0.0, options: .curveEaseOut,
                       animations: {
            var newInsets = self.scrollView.contentInset
            newInsets.top -= self.frame.size.height
            self.scrollView.contentInset = newInsets
        },
                       completion: {_ in
            //finished
        }
        )
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


(滑动显示更多)

原文链接:

https://blog.csdn.net/LinShunIos/article/details/121290126

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloCoder全栈小集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
iOS开发之多表视图滑动切换示例(仿"头条"客户端)
  好长时间没为大家带来iOS开发干货的东西了,今天给大家分享一个头条新闻客户端各个类别进行切换的一个示例。在Demo中对所需的组件进行的简单封装,在封装的组件中使用的是纯代码的形式,如果想要在项目中进行使用,稍微进行修改即可。   废话少说,先介绍一下功能点,下图是整个Demo的功能点,最上面左边的TabBarButtonItem是用来减少条目的,比如下图有三个按钮,点击减号会减少一个条目。右边的为增加一个条目。点击相应的按钮是切换到对应的表视图上,下方红色的是滑动的指示器,同时支持手势滑动。运行具体效果
lizelu
2018/01/11
3.9K0
iOS开发之多表视图滑动切换示例(仿"头条"客户端)
iOS_NestedScrollView(嵌套ScrollView)
首先需要了解UIGestureRecognizerDelegate协议的这个方法:
mikimo
2022/08/24
1.1K0
从案例出发,由浅到深了解 iOS 动画
iOS 的动画框架很成熟,提供必要的信息,譬如动画的起始位置与终止位置,动画效果就出来了
猿_人类
2019/11/07
8750
iOS-UIScrollerView
xy_ss
2023/11/22
3180
iOS-UIScrollerView
iOS开发之有间距的UITableViewCell
UITableView是最常用的一个iOS控件,现要做一个如下图的UITableView,其中白色部分就是cell,可是默认的UITableView中cell之间是没有间隔的,那么办呢?网上有2种做法
YungFan
2018/05/03
1.7K0
iOS开发之有间距的UITableViewCell
六天完成一个简单iOS App - 第四天
第四天任务: 今天主要任务完成精华模块的搭建。 精华页面的搭建 精华页面中全部界面的显示 日期的处理 热门评论的显示和处理 精华页面的搭建 精华页面分为全部、视频、声音、图片、段子五个界面,五个界面可
xx_Cc
2018/05/10
1.6K0
iOS-QQ音乐播放器的简单实现
一. QQ音乐播放器的简单实现 每个音乐播放器的实现都大致相同,个人认为难点在于歌曲播放与Slider的同步,歌词的解析与播放的同步。这些过程虽然繁琐,但是理解起来并不难。先来看看简单实现结果吧。 Q
xx_Cc
2018/05/10
3K0
VVeboTableView 源码解析
最近在看一些iOS性能优化的文章,我找到了VVeboTableView这个框架。严格来说这个不属于框架,而是作者用自己的方式优化UITableView的一个实践。
用户2932962
2018/08/30
1.3K0
VVeboTableView 源码解析
iOS流布局UICollectionView系列七——三维中的球型布局
        通过6篇的博客,从平面上最简单的规则摆放的布局,到不规则的瀑布流布局,再到平面中的圆环布局,我们突破了线性布局的局限,在后面,我们将布局扩展到了空间,在Z轴上进行了平移,我们实现了一个类似UIPickerView的布局模型,其实我们还可以再进一步,类比于平面布局,picKerView只是线性排列布局在空间上的旋转与平移,这次,我们更加充分了利用一下空间的尺寸,来设计一个圆球的布局模型。以下是前几篇博客地址:
珲少
2018/08/16
1.6K0
iOS流布局UICollectionView系列七——三维中的球型布局
[iOS] 列表滑动展开隐藏头部HeaderView
首先看一下BiliBili客户端的视频浏览界面。默认界面Header完全展开,并且Header显示AV号(别乱想,就是视频编号了)以及播放按钮。滑动之后Header被压缩,按钮移到AV号左边。
wOw
2018/09/18
3.6K0
[iOS] 列表滑动展开隐藏头部HeaderView
Swift 自定义布局实现 Cover Flow 效果
大家早上好,今天我又给大家带来了一篇关于 UICollectionView 系列的文章,在上一篇文章中,我们实现了一个酷炫的瀑布流布局,带大家初步的了解了在 UICollectionView 中该如何创建自定义布局。但是上一篇中实现的自定义布局稍显简单,只能说是比较粗略的计算了下布局各个 item 的位置,搞明白了继承自 UICollectionFlowLayout 子类它需要重载的方法的意义,那么今天这篇文章我们就来实现一个更加复杂的自定义布局: Cover Flow 效果吧!
HelloWorld杰少
2022/08/04
2.1K0
Swift 自定义布局实现 Cover Flow 效果
iOS开发过程中的奇淫技巧记录
为了修改带分组tableview的section header跟随置顶的问题,网上的奇淫技巧比方通过修改scroller的回调方法,体验不好,正规的方法是修改为tableView的UITableViewStyleGrouped模式,但该模式下列表section Header的高度过高,需要设置一个footer的高度:
呱牛笔记
2023/05/02
7020
iOS开发过程中的奇淫技巧记录
新闻类App顶部菜单栏封装
最近有一个需求,类似今日头条顶部的菜单栏。唯一区别是需要带可移动的下划线。网上查找资料,发现解决方案大部分是用UIScrollView实现。下方VC控制用UICollectionView。这样可以解决问题,但是不完美,当标签很多的时候,这时候的UIScrollView上会有大量写死的Button,没有达到复用的目的。所以自己封装了一个空间。菜单栏使用UICollectionView,VC控制使用PageViewController。
王大锤
2018/12/20
1.2K0
【IOS开发基础系列】UIScrollView专题
       在滚动过程当中,其实是在修改原点坐标。当手指触摸后,scroll view会暂时拦截触摸事件,使用一个计时器。假如在计时器到点后没有发生手指移动事件,那么scroll view 发送 tracking events 到被点击的subview。假如在计时器到点前发生了移动事件,那么 scroll view 取消tracking 自己发生滚动。
江中散人_Jun
2023/10/16
1.2K0
【IOS开发基础系列】UIScrollView专题
Swift日常开发随笔
提示:之所以为空白,是因为我把下拉列表中的tableView.reloadData()这行代码屏蔽掉了,加入的数组没有刷新。
编程怪才-凌雨画
2020/10/11
2.1K0
iOS UITableView 滑动到底部加载更多数据
很多APP都是滑动到底部时点击加载更多才会加载数据,这样用户体验就会有间断感,所以我们想用户看到最后时自动加载数据 怎么做呢
码客说
2019/10/22
2.5K0
UIScrollView进阶技巧
UIScrollView是iOS开发中经常用到的UI控件,像图片轮播之类的效果都可以用UIScrollView来实现,当然轮播什么的网上有很多教程了,我就不多说了。今天主要讲三个跟交互有关的效果(稍微有点标题党啊,其实也没有多进阶……),也不是直接用的UIScrollView,而是它的子类UITableView和UIWebView。先看一下效果图吧,都来自我自己的项目:
Sheepy
2018/09/10
1.1K0
UIScrollView进阶技巧
iOS WKWebView+UITableView混排
WKWebView+UITableView混排 做内容展示页的时候,经常会用到WKWebView+UITableView的混排功能,现在此做一个总结,该功能的实现我采用了四种方法。 方案1: webView作为tableView的Header, 撑开webView,显示渲染全部内容,当内容过多时,比如大量高清图片时,容易造成内存暴涨(不建议使用),此方案简单粗暴 , 仅适用于内容少的场景,具体实现不在此赘述,直接看代码。 方案2: 简书的内容页实现方案 : UIWebView与UITableV
且行且珍惜_iOS
2020/06/09
1.9K0
iOS  WKWebView+UITableView混排
处于UITableView中心线cell的处理
中心cell的处理.gif 本效果主要是为了获得处于UITableView的屏幕中心线或者指定位置的cell并进行处理的需求,此效果的技术点主要在于获得处于中心线位置的cell,虽然tableView有方法可以直接获得处于某坐标点的cell,但我还是想用自己的方法去实现,锻炼一下脑壳子,,,, //UIScrollView代理方法,滑动过程中执行 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ //获得UITableView中可见的cel
且行且珍惜_iOS
2018/05/22
4550
实现 iOS 无感知上拉加载更多
什么是无感知,这个这样理解:在网络情况正常的情况下,用户对列表进行连续的上拉时,该列表可以无卡顿不停出现新的数据。
网罗开发
2021/08/13
2.6K0
相关推荐
iOS开发之多表视图滑动切换示例(仿"头条"客户端)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档