一种卡片翻转效果

作者: Hayder | 来源:发表于2017-01-08 23:27 被阅读545次

最近业余写项目,实现了一种翻转卡片的效果,感觉效果还不错,记录下。首先来看下效果图:


卡片翻转效果图.gif

实现思路:
整个效果由一个背景图和3个卡片视图组成。获得一个数据数组后,在第一个卡片图上添加拖动Pan手势,修改卡片视图的transform中的Rotation属性。拖动结束后,刷新下3个卡片视图,每拖动结束一次就刷新一下3张卡片视图。

下面来看代码:
第一步: 初始化UI

//3张卡片视图
fileprivate var firstCell: WYClassBreakCell?
fileprivate var secondCell: WYClassBreakCell?
fileprivate var thirdCell: WYClassBreakCell?

fileprivate func setupUI(){
    
    //1.添加背景
    addSubview(bgImageView)
    
    //2.添加numLabel
    addSubview(numLable)
    
    //3.添加cell
    let margin: CGFloat = 10
    let cellWith: CGFloat = kScreenW - 2*30
    let cellHeight: CGFloat = cellWith/3*4
    let x: CGFloat = (kScreenW - cellWith)/2
    let y: CGFloat = (self.bounds.height - cellHeight)/2-30 - margin

    var lastView: UIView = self
    
    for i in 0..<3
    {
        let cell = WYClassBreakCell.classBreakCell()
        cell.layer.anchorPoint = CGPoint(x: 0.5, y: 2.0)
        cell.layer.position = CGPoint(x:0, y: 0)
        cell.frame = CGRect(x: x, y: y - CGFloat(i)*margin, width: cellWith, height: cellHeight)
        cell.tag = i + 1
        
        if(i != 0)
        {
            insertSubview(cell, belowSubview: lastView)
            lastView = cell
        }else
        {
            //只有第一张添加手势
            let pan = UIPanGestureRecognizer(target: self, action: #selector(pan(pan:)))
            cell.addGestureRecognizer(pan)
        
            addSubview(cell)
            lastView = cell
        }
        
    }
    
    //保存下属性
    firstCell = viewWithTag(1) as? WYClassBreakCell
    secondCell = viewWithTag(2) as? WYClassBreakCell
    thirdCell = viewWithTag(3) as? WYClassBreakCell
}

2.刷新卡片视图的方法
方法作用: 根据index下标设置模型数组中对应的数据,如果当前展示的卡片是第1张,他的模型数据在数组中的index = 0,参数就传0

fileprivate func refershUIWithIndex(index : Int)
{
    guard let classBraekList = classBraekList else{
        
        return
    }
    
    //设置页码
    numLable.numb.text = "\(index+1)"
    
    if index <= (classBraekList.count) - 3 //不是倒数三张
    {
        //1.初始化图形位置
        indentityTransFrom()
        
        //3.显示数据
        firstCell?.classBreakModel = (classBraekList[index])
        secondCell?.classBreakModel = (classBraekList[index+1])
        thirdCell?.classBreakModel = (classBraekList[index+2])

    }else{//倒数3张
        
        if index == (classBraekList.count) - 2 //还有2张
        {
            //初始化
            indentityTransFrom()
            
            //隐藏第3个Cell
            thirdCell?.isHidden = true
            
            //设置值
            firstCell?.classBreakModel = (classBraekList[index])
            secondCell?.classBreakModel = (classBraekList[index+1])
            
        }else if index == (classBraekList.count) - 1 //最后一张
        {
            //初始化
            indentityTransFrom()
            
            //隐藏第2,3个Cell
            thirdCell?.isHidden = true
            secondCell?.isHidden = true
            
            firstCell?.classBreakModel = (classBraekList[index])
        }
        
    }
//初始化图片位置
private func indentityTransFrom(){
    
    firstCell?.isHidden = false
    secondCell?.isHidden = false
    thirdCell?.isHidden = false
    
    if isFirst { //是否是第一张图片
        
        firstCell?.transform = CGAffineTransform.identity
        isFirst = false
    }else
    {
        firstCell?.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_4) * 0.1)
        
        UIView.animate(withDuration: 0.2){
            
            self.firstCell?.transform = CGAffineTransform.identity
        }
        secondCell?.transform = CGAffineTransform.identity
        thirdCell?.transform = CGAffineTransform.identity
    }
}

3.手势处理
手势处理中有两个部分需要进行处理

  • 滑动时候处理
    滑动分为左划和右划。
  • 右划时:先判断是否是第一张,如果是第一张往右划,会有一个小抖动,如果不是第一张,设置动画,做成由下往上转的动画
  • 左划时:获取手指的x偏移量,根据偏移量修改第一张卡片和第二张卡片的偏移量
  • 取消滑动或者手指抬起时候处理
    取消或结束手势时根据pan.view的transfrom.b来判断,这个数组是通过打印最后确定的,可以更改,也可以使用transform.a, .c, .d来确定。
  • 如果超过限定的值,就表示此次切换卡片有效,进行处理
  • 如果没有超过限定值,就表示此次切换卡片无效,设置第一张卡片和第二张卡片的transform = CGAffineTransform.identity。
 @objc fileprivate func pan(pan: UIPanGestureRecognizer)
  {
    //第二个视图
    let secondView = secondCell
    
    //判断手指是否抬起了,或者手势被取消了
    if pan.state == .ended || pan.state == .cancelled {
        
        if CGFloat((pan.view?.transform.b)!) < -0.25 //滑动比例超过0.25
        {
            UIView.animate(withDuration: 0.1, animations: {
                
                pan.view?.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2))
                
            }, completion: { (isFinished) in
                
                //刷新界面
                self.index += 1
                
                if self.index <= (self.classBraekList?.count)! - 1
                {
                    self.refershUIWithIndex(index: self.index)
                    
                }else //最后一张再滑动  从父视图上面移除
                {
                    self.removeFromSuperview()
                }

            })
            
        }else
        {
            pan.view?.transform = CGAffineTransform.identity
            secondView?.transform = CGAffineTransform.identity
        }
        
        if pan.translation(in: pan.view).x > 0 //右划
        {
            if index == 0
            {
                firstCell?.transform = CGAffineTransform(rotationAngle: CGFloat(M_PI_4) * 0.1)
                
                UIView.animate(withDuration: 0.2){
                    
                    self.firstCell?.transform = CGAffineTransform.identity
                }
            }else
            {
                //更新下成员变量index的值
                index = index - 1
                
                //先设置first的transform 是 90度
                self.firstCell?.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2))
                
                UIView.animate(withDuration: 0.5){
                    
                    self.firstCell?.transform = CGAffineTransform.identity
                    
                    self.refershUIWithIndex(index: self.index)
                }
            }
        }
    }else  //手指正在滑动的时候
    {
        //获取手指的x偏移值
        let offsetX = pan.translation(in: pan.view).x
        
        if offsetX < 0
        {
            //计算百分比
            let percent: CGFloat = offsetX / self.bounds.width
            
            //计算这次要旋转的度数
            let radians = CGFloat(M_PI_4) * percent
            
            pan.view?.transform = CGAffineTransform(rotationAngle: radians)
            secondView?.transform = CGAffineTransform(rotationAngle: radians/2)
        }
    }
    }

这个效果的主要核心代码就是这些。

最后

项目的Demo地址:https://github.com/WzhGoSky/CardDance
如果你感觉这个效果不错,请给个❤️,码字也辛苦,😁😁

相关文章

  • 一种卡片翻转效果

    最近业余写项目,实现了一种翻转卡片的效果,感觉效果还不错,记录下。首先来看下效果图: 实现思路:整个效果由一个背景...

  • vue封装翻转卡片效果

    方式一 edge兼容性不太好,翻转会卡住 组件 使用 方式二 从github找了个插件,可以兼容edge,有时间可...

  • android卡片的翻牌、翻转效果

    卡片翻牌效果 实现方法: 1.使用属性动画ObjectAnimator 2.使用Animator 3....

  • 实现翻转卡片的动画效果

    欢迎Follow我的GitHub, 关注我的简书. 其余参考Android目录. 在Android设计中, 经常会...

  • unity—卡牌翻转效果(2)

    上一篇的卡片翻转效果在应用中有一些问题,即当点击非卡牌区域,卡牌依旧会翻转。 这一篇的效果就是只有点击卡牌区域时才...

  • 小程序内实现卡片翻转效果

    卡片翻转 思路:一个view框内放两个view,分别存放卡片的正面和反面信息,这两个view重叠,并且反面卡片翻转...

  • 做一个简单好看的ViewPager翻转动画

    一直都很喜欢Instagram的快拍(Story)功能,也很喜欢他们的翻转效果,是一种简单的3D翻转效果。大致效果...

  • android卡片翻转动画

    先看效果 这个demo是仿照极客学院某个2D卡片翻转的效果做的。原来的demo是使用了补间动画, 我这里改用了属性...

  • CSS实现卡片3D翻转效果

    效果: 代码: html: css: javascript: -webkit-perspective:透视效果ba...

  • html + css 卡片3D翻转效果

    演示效果 实现思路 先将两个盒子通过3D旋转180度实现背靠背定位,接下来给父盒子添加鼠标经过事件实现翻转效果。为...

网友评论

  • Charles___:我这刚好有个oc版的 :flushed:
    Charles___:@小czy 恩恩是呢
    小czy: @Charles姚 你那个支持往回滑动吗,看你的简书是探探类型的
  • 小czy:哥,我项目正需要。这个类似网易公开课的是客户指定要的。用后我给你打赏
    小czy: @Hayder 嗯嗯,明天开始改
    Hayder:@小czy swift 的差不多的 自己翻译成OC就好了 思路是一样的
    小czy:只看图就评论了。没想到是swift。。。。
    懵逼了
  • 我_是你哥:正需要,谢谢
  • coderZQ:抢占楼层,沙发沙发沙发******
  • coderZQ:海哥牛逼!
    Hayder:666666
  • 亡灵诅咒:棒棒棒

本文标题:一种卡片翻转效果

本文链接:https://www.haomeiwen.com/subject/aymnvttx.html