Swift、OC版水波动画

作者: LarkNan | 来源:发表于2017-07-23 19:35 被阅读147次

    项目需要,所以在网上找了一些资料做了Swift和OC两版。

    动画所用到的函数:
    正弦型函数解析式:y=Asin(ωx+φ)+h
    各常数值对函数图像的影响:
    φ(初相位):决定波形与X轴位置关系或横向移动距离
    ω:决定周期(最小正周期T=2π/|ω|)
    A:决定峰值
    h:表示波形在Y轴的位置关系或纵向移动距离

    <h4>效果图</h4>

    waterwave.gif

    <h4>OC版</h4>

    #import <UIKit/UIKit.h>
    
    @interface SXMWaterWaveView : UIView
    
    /** 波动速度 */
    @property (nonatomic, assign) CGFloat waveSpeed;
    /** 水波振幅 */
    @property (nonatomic, assign) CGFloat waveAmplitude;
    /** 水波颜色 */
    @property (nonatomic, strong) UIColor *waveColor;
    /** 水波的高度 */
    @property (nonatomic, assign) CGFloat waveHeight;
    
    - (void)destroy;
    @end
    
    #import "SXMWaterWaveView.h"
    
    @interface SXMWaterWaveView ()
    @property (nonatomic, strong) CAShapeLayer *firstShapeLayer;
    @property (nonatomic, strong) CAShapeLayer *sencondShapeLayer;
    @property (nonatomic, strong) CADisplayLink *waveDisplayLink;
    
    @property (nonatomic, assign) CGFloat offsetX;
    @property (nonatomic, assign) CGFloat waveWidth;
    @end
    
    @implementation SXMWaterWaveView
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            [self setupUI];
        }
        return self;
    }
    
    // 设置UI
    - (void)setupUI
    {
        // 初始化值
        self.waveSpeed = 0.1;
        self.waveAmplitude = 8;
        self.waveWidth =  2.5 * M_PI / self.bounds.size.width;
        self.waveHeight = self.frame.size.height / 2;
        
        self.firstShapeLayer = [CAShapeLayer layer];
        self.firstShapeLayer.fillColor = [UIColor colorWithRed:255 / 255 green:255 / 255 blue:255 / 255 alpha:0.5].CGColor;
        [self.layer addSublayer:self.firstShapeLayer];
        
        self.sencondShapeLayer = [CAShapeLayer layer];
        self.sencondShapeLayer.fillColor = [UIColor colorWithRed:255 / 255 green:255 / 255 blue:255 / 255 alpha:0.5].CGColor;
        [self.layer addSublayer:self.sencondShapeLayer];
        
        self.waveDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(getCurrentWave)];
        [self.waveDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    }
    
    - (void)getCurrentWave
    {
        self.offsetX += self.waveSpeed;
        
        // 第一条线
        CGMutablePathRef firstPath = CGPathCreateMutable();
        CGPathMoveToPoint(firstPath, nil, 0, self.waveHeight);
        CGFloat firstY = self.bounds.size.height / 2;
        
        for (float x = 0.f; x <= self.bounds.size.width ; x++) {
            firstY = self.waveAmplitude * sin(self.waveWidth * x + _offsetX) + self.waveHeight;
            CGPathAddLineToPoint(firstPath, nil, x, firstY);
        }
    
        CGPathAddLineToPoint(firstPath, nil, self.bounds.size.width, self.frame.size.height);
        CGPathAddLineToPoint(firstPath, nil, 0, self.frame.size.height);
        
        // 结束绘图信息
        CGPathCloseSubpath(firstPath);
        self.firstShapeLayer.path = firstPath;
        
        CGPathRelease(firstPath);
        
        // 第二条线
        CGMutablePathRef secondPath = CGPathCreateMutable();
        CGPathMoveToPoint(secondPath, nil, 0, self.waveHeight+100);
        CGFloat secondY = self.bounds.size.height / 2;
        
        for (float x = 0.f; x <= self.bounds.size.width ; x++) {
            secondY = self.waveAmplitude * sin(_waveWidth * x + _offsetX - self.bounds.size.width / 2) + self.waveHeight;
            CGPathAddLineToPoint(secondPath, nil, x, secondY);
        }
        
        CGPathAddLineToPoint(secondPath, nil, self.bounds.size.width, self.frame.size.height);
        CGPathAddLineToPoint(secondPath, nil, 0, self.frame.size.height);
        CGPathCloseSubpath(secondPath);
        self.sencondShapeLayer.path = secondPath;
        
        CGPathRelease(secondPath);
    }
    
    - (void)setWaveColor:(UIColor *)waveColor
    {
        _waveColor = waveColor;
        
        self.firstShapeLayer.fillColor = waveColor.CGColor;
        self.sencondShapeLayer.fillColor = waveColor.CGColor;
    }
    
    - (void)destroy
    {
        [self.waveDisplayLink invalidate];
        self.firstShapeLayer = nil;
        self.sencondShapeLayer = nil;
        self.waveDisplayLink = nil;
    }
    
    @end
    

    <h4>Swift版</h4>

    import UIKit
    
    class SXMWaterWaveView_swift: UIView {
    
        lazy private var firstShapeLayer = CAShapeLayer();
        lazy private var sencondShapeLayer = CAShapeLayer();
        lazy private var waveDisplayLink = CADisplayLink();
        
        /** 波动速度 */
        var waveSpeed : CGFloat = 0
        /** 水波振幅 */
        var waveAmplitude: CGFloat = 0
        /** 水波的高度 */
        var waveHeight : CGFloat = 0
        /** 水波颜色 */
        var waveColor : UIColor? {
            didSet {
                firstShapeLayer.fillColor = waveColor?.cgColor;
                sencondShapeLayer.fillColor = waveColor?.cgColor;
            }
        }
        
        private var waveWidth: CGFloat = 0
        private var offsetX: CGFloat = 0
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            setupUI()
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        private func setupUI() {
            // 初始化值
            self.waveSpeed = 0.1;
            self.waveAmplitude = 8;
            self.waveWidth =  2.5 * CGFloat(M_PI) / self.bounds.size.width;
            self.waveHeight = self.frame.size.height / 2;
            
            firstShapeLayer.fillColor = UIColor.init(colorLiteralRed: 255 / 255.0, green: 255 / 255.0, blue: 255 / 255.0, alpha: 0.5).cgColor
            sencondShapeLayer.fillColor = UIColor.init(colorLiteralRed: 255 / 255.0, green: 255 / 255.0, blue: 255 / 255.0, alpha: 0.5).cgColor
            layer.addSublayer(firstShapeLayer)
            layer.addSublayer(sencondShapeLayer)
            
            waveDisplayLink = CADisplayLink(target: self, selector: #selector(getCurrentWave))
            waveDisplayLink.add(to: RunLoop.current, forMode: .commonModes)
        }
        
        @objc private func getCurrentWave() {
            offsetX += waveSpeed
        
            // 第一条线
            let firstPath = CGMutablePath()
            var firstY = bounds.size.width / 2
            firstPath.move(to: CGPoint(x: 0, y: firstY))
            for i in 0...Int(bounds.size.width) {
                firstY = waveAmplitude * sin(waveWidth * CGFloat(i) + offsetX) + waveHeight
                firstPath.addLine(to: CGPoint(x: CGFloat(i), y: firstY))
            }
            
            firstPath.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
            firstPath.addLine(to: CGPoint(x: 0, y: bounds.size.height))
            firstPath.closeSubpath()
            firstShapeLayer.path = firstPath
            
            // 第二条线
            let secondPath = CGMutablePath()
            var secondY = bounds.size.width / 2
            secondPath.move(to: CGPoint(x: 0, y: secondY))
            
            for i in 0...Int(bounds.size.width) {
            secondY = waveAmplitude * sin(waveWidth * CGFloat(i) + offsetX - bounds.size.width / 2 ) + waveHeight
            secondPath.addLine(to: CGPoint(x: CGFloat(i), y: secondY))
            }
            secondPath.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
            secondPath.addLine(to: CGPoint(x: 0, y: bounds.size.height))
            secondPath.closeSubpath()
            sencondShapeLayer.path = secondPath
        }
        
        public func destroyView() {
            waveDisplayLink.invalidate()
        }
    
        deinit {
            print("SXMWaterWaveView_deinit")
        }
    }
    

    Demo地址:https://github.com/LarkNan/SXMWaterWaveDemo
    参考资料:http://www.jianshu.com/p/44c904291a2e

    全文完

    相关文章

      网友评论

        本文标题:Swift、OC版水波动画

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