iOS 动画iOS之绘图动画iOS之Swift绘图动画

Swift、OC版水波动画

2017-07-23  本文已影响147人  LarkNan

项目需要,所以在网上找了一些资料做了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

全文完

上一篇下一篇

猜你喜欢

热点阅读