2016-05-01 11:12:45 feng2qing 阅读数 8383
Swift2.3:
//创建旋转动画
let anim = CABasicAnimation(keyPath: "transform.rotation")
//旋转角度
anim.toValue = 1 * M_PI
//旋转指定角度需要的时间
anim.duration = 1
//旋转重复次数
anim.repeatCount = MAXFLOAT
//动画执行完后不移除
anim.removedOnCompletion = true
//将动画添加到视图的laye上
view.layer.addAnimation(anim, forKey: nil)
//取消动画
view.layer.removeAllAnimations()
//这个是旋转方向的动画        
UIView.animateWithDuration(0.2) { () -> Void in
    //指定旋转角度是180°
    view.transform = CGAffineTransformRotate(view.transform, CGFloat(M_PI))
}

Swift3.0:
let anim = CABasicAnimation(keyPath: "transform.rotation")
anim.toValue = 1 * M_PI
anim.duration = 1
anim.repeatCount = MAXFLOAT
anim.isRemovedOnCompletion = true
view1.layer.add(anim, forKey: nil)
view1.layer.removeAllAnimations()
UIView.animate(withDuration: 0.2) {
    view1.transform = view1.transform.rotated(by: CGFloat(M_PI))
}
2018-11-01 11:45:37 weixin_43566445 阅读数 44

效果图

实现效果:

静止时:子view对称排列,允许动态添加,0~24个都能较好的显示.

旋转时:中心view不动,子view随手势旋转,最下方子view变大突出.

实现思路:

所有的控件全部加到一个大的背景view上,本质上旋转的是这个背景view,在旋转背景view的同时,让它所有的子控件反向旋转,就实现了现在这种效果.

使用touchMoved方法获取手势,使用transform来实现动画.

最下方的view变大是循环判断子view.frame.x,当它处于一个范围,并且frame.y大于中心view.frame.y的时候.修改它的transform,来使其变大,并且修改它的tag来标记它已经属于变大状态,当它frame.x超出了预定范围,使其还原.

实现方式:

1.添加背景透明view,中心圆圈view.

2.添加周围旋转子view.

3.添加旋转方法.

4.交互优化.


1.添加背景透明view,中心圆圈view.

 /// 添加背景view,也是旋转的view
    private func setContentView() {
        setCircleView()
        contentView = UIView(frame: CGRect(x: 0, y: 0, width: ScreenInfo.Width, height: ScreenInfo.Width))
        contentView?.center = self.view.center
        self.view.addSubview(contentView!)
        contentView!.addSubview(circleView!)
    }
    /// 添加中间圆形view
    private func setCircleView(){
        let view = UIImageView(frame: CGRect(x: 0.5 * CGFloat(1 - PROPORTION) * ScreenInfo.Width + 10, y: 0.5 * CGFloat(1 - PROPORTION) * ScreenInfo.Width + 10, width: ScreenInfo.Width * CGFloat(PROPORTION) - 20, height: ScreenInfo.Width * CGFloat(PROPORTION) - 20))
        /// 为了适配保证size变化center不变
        let centerPoint = view.center
        view.frame.size = CGSize(width: ScreenInfo.Width * CGFloat(PROPORTION) - 40, height: ScreenInfo.Width * CGFloat(PROPORTION) - 40)
        view.center = centerPoint
        view.image = UIImage(named: "11")
        view.layer.cornerRadius = view.frame.width*0.5
        view.layer.masksToBounds = true
        view.isUserInteractionEnabled = true
        circleView = view
    }

2.添加周围旋转子view.

   /// 布局旋转的子view
    private func rotationCircleCenter(contentOrgin: CGPoint,
                                      contentRadius: CGFloat,subnode: [String]){
        // 添加比例,实现当要添加的子view数量较多时候可以自适应大小.
        var scale: CGFloat = 1
        if subnode.count > 10 {
            scale = CGFloat(CGFloat(subnode.count) / 13.0)
        }

        for i in 0..<subnode.count {
            let x = contentRadius * CGFloat(sin(.pi * 2 / Double(subnode.count) * Double(i)))
            let y = contentRadius * CGFloat(cos(.pi * 2 / Double(subnode.count) * Double(i)))
            // 当子view数量大于10个,view.size变小,防止view偏移,要保证view.center不变.
            let view = EWSubView(frame: CGRect(x:contentRadius + 0.5 * CGFloat((1 + PROPORTION)) * x - 0.5 * CGFloat((1 - PROPORTION)) * contentRadius, y: contentRadius - 0.5 * CGFloat(1 + PROPORTION) * y - 0.5 * CGFloat(1 - PROPORTION) * contentRadius, width: CGFloat((1 - PROPORTION)) * contentRadius, height: CGFloat((1 - PROPORTION)) * contentRadius), imageName: subnode[i])
            let centerPoint = view.center
            view.frame.size = CGSize(width: CGFloat((1 - PROPORTION)) * contentRadius / scale , height: CGFloat((1 - PROPORTION)) * contentRadius / scale)
            view.center = centerPoint
            view.drawSubView()
            // 这个tag判断view是不是在最下方变大状态,非变大状态0,变大为1
            view.tag = 0
            // 获取子view在当前屏幕中的rect.来实现在最下方的那个变大
            let rect = view.convert(view.bounds, to: UIApplication.shared.keyWindow)
            let viewCenterX = rect.origin.x + (rect.width) / 2
            if viewCenterX > self.view.center.x - 20 && viewCenterX < self.view.center.x + 20 && rect.origin.y > (contentView?.center.y)! {
                view.transform = view.transform.scaledBy(x: 1.5, y: 1.5)
                view.tag = 1
            }
            contentView?.addSubview(view)
            viewArray.append(view)
        }
    }

3.添加旋转方法.

 /// 核心旋转方法,具体办法是背景view旋转,中心view和子view同角度反向旋转,实现动画效果
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let contentView = contentView else { return }
        guard let circleView = circleView else { return }
        orgin = CGPoint(x: 0.5 * ScreenInfo.Width, y: MENURADIUS + 0.17 * ScreenInfo.Height)
        let currentPoint = touches.first?.location(in: self.view)
        if self.touchPointInsideCircle(center: orgin!, radius: MENURADIUS*1.45, targetPoint: currentPoint!){
            b = DIST(pointA: beginPoint!, pointB: orgin!)
            c = DIST(pointA: currentPoint!, pointB: orgin!)
            a = DIST(pointA: beginPoint!, pointB: orgin!)
            let angleBegin = atan2(beginPoint!.y - orgin!.y, beginPoint!.x - orgin!.x)
            let angleAfter = atan2(currentPoint!.y - orgin!.y, currentPoint!.x - orgin!.x)
            let angle = angleAfter - angleBegin
            // 背景view旋转
            contentView.transform = contentView.transform.rotated(by: angle)
            // 中心view反向旋转
            circleView.transform = circleView.transform.rotated(by: -angle)
            for i in 0..<viewArray.count {
                // 子view反向旋转
                viewArray[i].transform = viewArray[i].transform.rotated(by: -angle)
                // 判断实现最下方的子view变大
                let rect = viewArray[i].convert(viewArray[i].bounds, to: UIApplication.shared.keyWindow)
                let viewCenterX = rect.origin.x + (rect.width) / 2
                if viewCenterX > self.view.center.x - 20 && viewCenterX < self.view.center.x + 20 && rect.origin.y > contentView.center.y {
                    if viewArray[i].tag == 0{
                        viewArray[i].transform = viewArray[i].transform.scaledBy(x: 1.5, y: 1.5)
                        viewArray[i].tag = 1
                        contentView.bringSubview(toFront: viewArray[i])
                    }
                }
                else {
                    if viewArray[i].tag == 1 {
                        viewArray[i].transform = viewArray[i].transform.scaledBy(x: 1/1.5, y: 1/1.5)
                        viewArray[i].tag = 0
                        contentView.sendSubview(toBack: viewArray[i])
                    }
                }
            }
            beginPoint = currentPoint
        }
    }

4.交互优化.

     /// 获取手指触摸位置,超过范围不让旋转交互
    private func touchPointInsideCircle(center: CGPoint, radius: CGFloat, targetPoint: CGPoint) -> Bool{
        let dist = DIST(pointA: targetPoint, pointB: center)
        return (dist <= radius)
    }

    func DIST(pointA: CGPoint, pointB: CGPoint) -> CGFloat{
        let x = (pointA.x - pointB.x) * (pointA.x - pointB.x)
        let y = (pointA.y - pointB.y) * (pointA.y - pointB.y)
        return CGFloat(sqrtf(Float(x + y)))
   }

demo地址:CircleView

使用pop框架实现,长按中心按钮,周围子View旋转效果的项目:Swift.轮转动画+Pop框架

有问题欢迎探讨.

2014-10-22 11:27:28 ooppookid 阅读数 2781

6.添加View的动画效果

本章节主要来做明细页面点击后翻转的动画效果,该效果可以进行多种改变,以达到想要的效果。

1.首先我们需要进行翻转的正反两个view,前面我们已经做好了,分别是PKOElementDetailImageViewPKOElementDetailImageFlippedView,具体翻转动画在明细页面的控制其中进行,触发当然是PKOElementDetailImageView中的点击事件,前文已经提到。
2.PKOElementDetailImageView中的点击事件调用PKOElementDetailViewController中的flipImageView()方法,该方法具体实现翻转功能,注释中写的很详细。
代码如下。

//翻转动画
    func flipImageView() {
        UIView.beginAnimations(nil, context:nil)
        //平滑动画效果
        UIView.setAnimationCurve(UIViewAnimationCurve.Linear)
        UIView.setAnimationDuration(1)
        
        var reflectionHeight: CGFloat
        var reflectedImage: UIImage?
        
        //点击正面
        if(self.frontViewIsVisible == true){
            UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: self.subView!, cache: true)
            self.detailImage.removeFromSuperview()
            self.subView?.addSubview(self.detailImageFlipped)
        }
        //点击反面
        else{
            UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromRight, forView:self.subView!, cache:true)
            self.detailImageFlipped.removeFromSuperview()
            self.subView?.addSubview(self.detailImage)
        }
        //提交动画
        UIView.commitAnimations()
        //设置是否正面显示标识
        self.frontViewIsVisible = !self.frontViewIsVisible
    }

7.添加View的阴影

本章节主要来做明细页面图片的阴影效果,该效果可以进行高度设置,并且完全反射,包含所绘制的文字。

1.通过控制器PKOElementDetailViewController绘制明细图的同时,绘制图片的阴影,该阴影应该基于阴影的主图,所以放在PKOElementDetailImageView中处理。
reflectedImageWithHeight(height: UInt) ->UIImage该方法将返回对应阴影image。
具体做法请看注释,思路是:复制一个位图并裁剪成需要大小-翻转并绛色-填充渐变色
代码如下。

//通过指定高度生成倒影图,方法完全照搬官方sample,
    func reflectedImageWithHeight(height: UInt) ->UIImage{
        //这里注意,swift不能直接在CG方法中用nil,需要声明一个变量
        var nilUnsafeMutablePointer: UnsafeMutablePointer<Void> = nil
        //rgb颜色容器,RGBA和CMYK的区别我会另开博文去说这个
        var colorSpace  = CGColorSpaceCreateDeviceRGB()
        var int32CGImageAlphaInfo = CGImageAlphaInfo.PremultipliedLast.toRaw()
        var bitmapInfo = CGBitmapInfo.fromRaw(int32CGImageAlphaInfo)
        
        //使用CG绘制位图上下文,以下是方法的用法,网上抓的,大家可以试一下具体用法。
        //参数data指向绘图操作被渲染的内存区域,这个内存区域大小应该为(bytesPerRow*height)个字节。如果对绘制操作被渲染的内存区域并无特别的要求,那么可以传递NULL给参数date。
        //参数width代表被渲染内存区域的宽度。
        //参数height代表被渲染内存区域的高度。
        //参数bitsPerComponent被渲染内存区域中组件在屏幕每个像素点上需要使用的bits位,举例来说,如果使用32-bit像素和RGB颜色格式,那么RGBA颜色格式中每个组件在屏幕每个像素点上需要使用的bits位就为32/4=8。
        //参数bytesPerRow代表被渲染内存区域中每行所使用的bytes位数。
        //参数colorspace用于被渲染内存区域的“位图上下文”。
        //参数bitmapInfo指定被渲染内存区域的“视图”是否包含一个alpha(透视)通道以及每个像素相应的位置,除此之外还可以指定组件式是浮点值还是整数值。
        var mainViewContentContext = CGBitmapContextCreate(nilUnsafeMutablePointer, UInt(self.bounds.size.width), height, UInt(8), UInt(0), colorSpace, bitmapInfo!)
        
        //注意,swift操作CG是不需要释放的,CG内部的GC已经处理了
        
        //调整位图位置,CGContextTranslateCTM为位移方法
        var translateVertical = CGFloat(self.bounds.size.height) - CGFloat(height)
        //这里相当于翻转
        CGContextTranslateCTM(mainViewContentContext, 0, -translateVertical)
        
        //将该位图渲染到layer层,layer层是view的根层,这里相当与copy一个self
        self.layer.renderInContext(mainViewContentContext)
        
        //根据位图上下文生成位图
        var mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext)
        
        //创建一个mask,确认刚才生成的位图那些是需要显示的,这里主要用它的渐变功能,image mask就像是用于表征色彩放在页面的哪一部分
        var gradientMaskImage = PKOElementDetailImageView.AEViewCreateGradientImage(UInt(1), pixelsHigh: UInt(height))
        
        //将位图需要显示的部分显示出来
        var reflectionImage = CGImageCreateWithMask(mainViewContentBitmapContext, gradientMaskImage)
        
        //通过image生成UIImage,并返回
        var theImage = UIImage(CGImage: reflectionImage)
        return theImage
    }
    
    class func AEViewCreateGradientImage ( pixelsWide: UInt, pixelsHigh: UInt) ->CGImageRef {
        var nilUnsafeMutablePointer: UnsafeMutablePointer<Void> = nil
        var colorSpace = CGColorSpaceCreateDeviceGray()
        var int32CGImageAlphaInfo = CGImageAlphaInfo.None.toRaw()
        var bitmapInfo = CGBitmapInfo.fromRaw(int32CGImageAlphaInfo)
        //使用CG绘制位图上下文,渐变色位图
        var gradientBitmapContext = CGBitmapContextCreate(nilUnsafeMutablePointer, pixelsWide, pixelsHigh,
            UInt(8), UInt(0), colorSpace, bitmapInfo!)
        
        //创建渐变对象,对于CG渐变我会在开博文详细解释
        var colors: [CGFloat] = [0.0, 1.0,1.0, 1.0]
        var nilUnsafePointer: UnsafePointer<CGFloat> = nil
        var grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, nilUnsafePointer, UInt(2))
        
        //渐变的开始点和结束点
        var gradientStartPoint = CGPointZero
        var gradientEndPoint = CGPointMake(0, CGFloat(pixelsHigh))
        
        //填充渐变色
        CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint, gradientEndPoint, CGGradientDrawingOptions())
        
        //通过image生成UIImage,并返回
        var theCGImage = CGBitmapContextCreateImage(gradientBitmapContext)
        return theCGImage
    }

2.在PKOElementDetailViewController中图像渲染时调用PKOElementDetailImageView中的reflectedImageWithHeight(height: UInt) ->UIImage返回image,将其添加在subview中。
代码如下。

//创建倒影图
        var reflectionRect = imageRect
        reflectionRect.size.height = CGFloat(CGRectGetHeight(reflectionRect)) * CGFloat(reflectionRadio)
        reflectionRect = CGRectOffset(reflectionRect, 0, CGRectGetHeight(imageRect))
        var reflectionView = UIImageView(frame: reflectionRect)
        self.reflectionImage = reflectionView
        var height = (self.detailImage?.bounds.height as CGFloat!) * CGFloat(reflectionRadio)
        self.reflectionImage.image = self.detailImage?.reflectedImageWithHeight(UInt(height))
        self.reflectionImage.alpha = 0.3
        //添加倒影
        self.subView?.addSubview(self.reflectionImage)

3.在翻转的同时需要更新倒影,使倒影应用于反面,再次翻转时需要再次更新,保证阴影跟随主图的变幻而变化,在控制器的翻转方法flipImageView()中进行处理即可 。
代码如下。

//翻转动画
    func flipImageView() {
        UIView.beginAnimations(nil, context:nil)
        //平滑动画效果
        UIView.setAnimationCurve(UIViewAnimationCurve.Linear)
        UIView.setAnimationDuration(1)
        
        var reflectionHeight: CGFloat
        var reflectedImage: UIImage?
        
        //点击正面
        if(self.frontViewIsVisible == true){
            UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: self.subView!, cache: true)
            self.detailImage?.removeFromSuperview()
            self.subView?.addSubview(self.detailImageFlipped)
            
            // 更新倒影
            reflectionHeight = (self.detailImageFlipped.bounds.height as CGFloat) * CGFloat(reflectionRadio)
            reflectedImage = self.detailImageFlipped.reflectedImageWithHeight(UInt(reflectionHeight))
            self.reflectionImage.image = reflectedImage
        }
        //点击反面
        else{
            UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromRight, forView:self.subView!, cache:true)
            self.detailImageFlipped.removeFromSuperview()
            self.subView?.addSubview(self.detailImage!)
            
            // 更新倒影
            reflectionHeight = (self.detailImage!.bounds.height as CGFloat) * CGFloat(reflectionRadio)
            reflectedImage = self.detailImage?.reflectedImageWithHeight(UInt(reflectionHeight))
            self.reflectionImage.image = reflectedImage
        }
        //提交动画
        UIView.commitAnimations()
        //设置是否正面显示标识
        self.frontViewIsVisible = !self.frontViewIsVisible
    }

至此全部改造完成,完整源代码请去第一篇下载

点击进入ooppookid的博客

2016-04-28 11:26:45 msyqmsyq 阅读数 1339

常用的3D动画类型同仿射变化一样有旋转平移缩放,如下:

 CATransform3DMakeScale(0.5, 0.5, 1.0);  //x,y,z放大缩小倍数

 CATransform3DMakeRotation(1.57, 1, 1, 0); //1.57表示所转角度的弧度 = 90Pi/180 = 90*3.14/180

CATransform3DMakeTranslation(0, 0, 0); //位置移动

我们想给tableview在cell即将出现的时间添加动画,用到的tableview代理方法如下:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;


//添加每个cell出现时的3D动画

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

    

    CATransform3D rotation;//3D旋转初始化对象

    rotation = CATransform3DMakeRotation( (90.0*M_PI)/180, 0.0, 0.7, 0.4);//角度控制

    

    //逆时针旋转

    rotation.m34 = 1.0/ -600;

    

    cell.layer.shadowColor = [[UIColor blackColor]CGColor];

    cell.layer.shadowOffset = CGSizeMake(10, 10);

    cell.alpha = 0;

    

    cell.layer.transform = rotation;

    

    [UIView beginAnimations:@"rotation"context:NULL];

    //旋转时间

    [UIView setAnimationDuration:0.8];

    cell.layer.transform = CATransform3DIdentity;

    cell.alpha = 1;

    cell.layer.shadowOffset = CGSizeMake(0, 0);

    [UIView commitAnimations];

}

另外一种写法稍有不同,UIView动画改用block来进行简化,


最后上一张效果图:






没有更多推荐了,返回首页