swift TableViewCell折叠动画

前段时间学习了一下swift的基础动画,于是找了个TableViewcell的动画项目来学习学习Folding cell

FoldingCell-sample.gif

学习的过程中遇到了一些坑,在这里分享一下,给大家借鉴借鉴

UITableViewController

首先我刚看到这个动画的时候,我先给这个动画进行了分解,在这个动画开始前,应该是先修改了cell 的高度,于是我先着手修改cell的高度

//定义了cell打开时和关闭时的高度
let openCellHeight: CGFloat = 505
let closeCellHeight: CGFloat = 180

//设置所有cell 的初始高度
var cellHeights: [CGFloat] = []
override func viewDidLoad() {
        super.viewDidLoad()
        cellHeights = Array(repeating: closeCellHeight, count: rowCount)

    }
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellHeights[indexPath.row]
    }

//并在创建的 UITableViewController内重写didSelectorRowAt 方法
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
       let cell = tableView.cellForRow(at: indexPath) as! TestTableViewCell
        
        let cellIsCollapsed = cellHeights[indexPath.row] == closeCellHeight
        if cellIsCollapsed {
            cellHeights[indexPath.row] = openCellHeight
        } else {
            cellHeights[indexPath.row] = closeCellHeight
        }
        tableView.reloadData()
    }

这时点击cell会有高度的变化,但是你会发现cell的高度变化是一瞬间的,并不是慢慢变大,于是我查找了一下资料,发现使用tabelView.beginUpdates()和tabelView.endUpdates()来代替tableView.reloadData()实现cell高度渐变的效果,并且使用UIView.animate(withDuration: TimeInterval, animations: () -> Void)来设置了tabelViewcell高度变化的时间差

UIView.animate(withDuration: druation, delay: 0, options: .curveEaseIn, animations: { () -> Void in
            tableView.beginUpdates()
            tableView.endUpdates()
        }, completion: nil)

这时我们就能通过设置druation来控制cell高度变化的时间,但是,这时你会发现点击cell 后整个cell会变成灰色,经过查找后发现这是由cell的selectionStyle引起的,我们需要把cell.selectionStyle设置为UITableViewCellSelectionStyle.none或者在storybord的界面选择cell后修改Selection为None。

UITableTableCell

第一步,我们要实现点击前和点击后cell的view显现两个不同的View,我们需要在cell 内的ContentView中创建两个高度不同的View(这里我们把forgroundView设为cell关闭时的View,constrainView为cell 打开后的View)当cell是对应的高度时就设置该view的alphe为1,另一个着为0。在我们设置动画之前,我们需要设置的forgroundView和constrainView的位置,我的做法是在storyboard为两个view 都设置了上左右和Height的约束,并把forgroundView和constrainView的Top约束连接到UITableTableCell里并设置它们的constant大小相同

    @IBOutlet weak var foreguoundTop: NSLayoutConstraint!
    @IBOutlet weak var constrainTop: NSLayoutConstraint!

constrainTop.constant = foreguoundTop.constant

第二步,我们先实现一个view能折叠翻转,这时我就想起之前学习的CABasicAnimation的transform.rotation,于是我先试着在forgroundView延底部翻转

animation1 = CABasicAnimation(keyPath: "transform.rotation.x")
        animation1.fromValue = 0
        animation1.toValue = -CGFloat.pi / 2.0
        animation1.duration = 0.13

forgroundView.layer.add(animation1, forKey: "forgroundView")

这时你能发现forgroundView是延中线翻转的我们需要延底部的,这时我们需要设置forgroudView的layer.anchorPoint,默认的View的layer.anchorPoint都为CGPoint(x: 0.5, y: 0.5),这个是View的中心点,要让forgroundView延底部转,我们需要设置layer.anchorPoint为CGPoint(x: 0.5, y: 1),这时你发现forgroundView的确能延底部翻转,但是你会发现修改layer.anchorPoint后forgroundView的位置发生了偏移,往上偏移了半个forgroundView的高度,查阅资料后发现两条公式:

frame.origin.x = position.x - anchorPoint.x * bounds.size.width 
frame.origin.y = position.y - anchorPoint.y * bounds.size.height

且position不受anchorPoint影响,所以当我们修改View的anchorPoint时变化的就是frame.origin,如果我们要不影响forgroundView的位置
我们需要先记录forgroundView的frame,修改完anchorPoint后再赋值forgroundView的frame

var imageFrame = forgroundView.frame
        forgroundView.layer.anchorPoint = CGPoint(x: 0.5, y: 1)
        forgroundView.frame = imageFrame

在这里我要分享一个我遇到的坑,当初我设置animation和修改anchorPoint都是在cell的awakeFormNib()方法里,这里无论我怎么修改forgroundView的frame,forgroun都不会有任何变化,后来查阅资料才发现,原来awakeFormNib的调用是在ViewController创建之前就调用了,这时获取的View的frame都是不对的,所以无法重新赋值,所以我建议修改frame放在viewDidLayoutSubviews或之后的方法里
第三步
我们现在已经可以在不移动forgroundView情况下翻转forgroundView了,但是我们发现中间翻转的时候是有白色的View的,这是需要创建的,这里我就把显现的ImageViews和需要翻转的animationViews分别创建,这时我们就需要获取forgroundView和constainsView的视图赋值给显现的View

public extension UIView {
    func setSampleView(frame: CGRect) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
        guard let context = UIGraphicsGetCurrentContext() else {
            print("fail")
            return nil
        }
        context.translateBy(x: frame.origin.x * -1   , y: frame.origin.y * -1 )
        layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

这里我扩展了UIView来获取forgroundView和constainsView的视图

let firstImage = constrainView.setSampleView(frame: CGRect(x: constrainView.bounds.minX, y: constrainView.bounds.minY, width: forgroundView.frame.width, height: forgroundView.frame.height))
        firstViewBg = UIImageView(image: firstImage)
        firstViewBg.frame = CGRect(x: constrainView.bounds.minX, y: constrainView.bounds.minY, width: forgroundView.frame.width, height: forgroundView.frame.height)

这样我们就可以获取以forgroundView和constrainView为图片的ImageViews和animationViews
第四步
这时我们需要把动画连接起来,我看了FoldingCell里它是通过设置动画的beginTime使动画连续起来,而我选择使用animationDidStop()来使动画连接起来,这个方法的调用需要cell继承CAAnimationDelegate
并且需要设置animatiom需要设置delegate和设置isRemoveOnCompletion为false

animation1.isRemovedOnCompletion = false
animation1.delegate = self

//上一个animation结束时就执行下一个动画
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if anim == firstImageView.layer.animation(forKey: "firstImageView") {
            firstImageView.alpha = 0
            secondImageView.alpha = 1
            secondImagebgView.alpha = 1
            firstViewBg.layer.masksToBounds = false
            secondImageView.layer.add(animation2, forKey: "secondImageView")
        }
}

当我们我们都设置好之后,运行起来之后我们会发现,我们的翻转并没有那种3D的立体感,这个我们需要设置layer.transform

var animationTransform = CATransform3DIdentity

animationTransform.m34 = -2.5 / 2000

firstImageView.layer.transform = animationTransform

CALayer中有一个transform属性便是专门用来控制3D形变的,transform属性默认值为CATransform3DIdentity, 在CATransform3DIdentity结构体中有一个m34允许我们将正交投影修改为有近大远小立体效果的透视投影,其中m34 = -1.0/z,这个z为观察者与控件之间的距离, m34必须在赋值transform之前设置才会生效.
到此我们的动画基本久已经完成了,在此我想补充一点,可能我们做到这之后运行起来可能会感觉View有时会有一种闪现的感觉,查找资料后,发现animation有个fillMode的属性我们设置未kCAFillModeForwards后能解决该问题

animation1.fillMode = kCAFillModeForwards

到此动画就算基本完成了附上代码

总结

新手刚学,知识水平有限,如有错误之处,还望指出.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 1 CALayer IOS SDK详解之CALayer(一) http://doc.okbase.net/Hell...
    Kevin_Junbaozi阅读 5,126评论 3 23
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,462评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,094评论 5 13
  • 在iOS实际开发中常用的动画无非是以下四种:UIView动画,核心动画,帧动画,自定义转场动画。 1.UIView...
    请叫我周小帅阅读 3,076评论 1 23
  • Core Animation Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,...
    45b645c5912e阅读 3,013评论 0 21