zoukankan      html  css  js  c++  java
  • 震动效果

    震动效果

    效果

    源码

    https://github.com/rFlex/SCViewShaker

    https://github.com/YouXianMing/Animations

    //
    //  UIView+Shake.h
    //  Animations
    //
    //  Created by YouXianMing on 16/2/25.
    //  Copyright © 2016年 YouXianMing. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    // https://github.com/rFlex/SCViewShaker
    
    #define kDefaultShakeOptions  (SCShakeOptionsDirectionHorizontal | SCShakeOptionsForceInterpolationExpDown | SCShakeOptionsAtEndComplete)
    #define kDefaultShakeForce    (0.075)
    #define kDefaultShakeDuration (0.5)
    #define kDefaultShakeIterationDuration (0.03)
    
    typedef enum : NSUInteger {
        
        SCShakeOptionsDirectionRotate                = 0,
        SCShakeOptionsDirectionHorizontal            = 1,
        SCShakeOptionsDirectionVertical              = 2,
        SCShakeOptionsDirectionHorizontalAndVertical = 3,
        SCShakeOptionsForceInterpolationNone         = 4,
        SCShakeOptionsForceInterpolationLinearUp     = 8,
        SCShakeOptionsForceInterpolationLinearDown   = 16,
        SCShakeOptionsForceInterpolationExpUp        = 32,
        SCShakeOptionsForceInterpolationExpDown      = 64,
        SCShakeOptionsForceInterpolationRandom       = 128,
        SCShakeOptionsAtEndRestart                   = 256,
        SCShakeOptionsAtEndComplete                  = 512,
        SCShakeOptionsAtEndContinue                  = 1024,
        SCShakeOptionsAutoreverse                    = 2048
        
    } SCShakeOptions;
    
    typedef void(^ShakeCompletionHandler)();
    
    @interface UIView (Shake)
    
    /**
     *  Returns whether the view is currently shaking or not.
     */
    @property (readonly, nonatomic) BOOL isShaking;
    
    /**
     *  Shake the view using the default options. The view will be shaken for a short amount of time.
     */
    - (void)shake;
    
    /*
     Shake the view using the specified options.
     |shakeOptions| is an enum of options that can be activated by using the OR operator (like SCShakeOptionsDirectionRotate | SCShakeOptionsForceInterpolationNone).
     
     |force| is the coefficient of force to apply on each shake iteration (typically between 0 and 1 even though nothing prevents you for setting a higher value if you want).
     
     |duration| is the total duration of the shaking motion. This may be ignored depending of the options you set.
     iterationDuration is how long each shake iteration will last. You may want to set a very low value (like 0.02) if you want a proper shake effect.
     
     |completionHandler|, if not null, is the block that will be invoked when the shake finishes.
     */
    - (void)shakeWithOptions:(SCShakeOptions)shakeOptions
                       force:(CGFloat)force duration:(CGFloat)duration
           iterationDuration:(CGFloat)iterationDuration
           completionHandler:(ShakeCompletionHandler)completionHandler;
    
    /**
     *  End the current shaking action, if any
     */
    - (void)endShake;
    
    @end
    //
    //  UIView+Shake.m
    //  Animations
    //
    //  Created by YouXianMing on 16/2/25.
    //  Copyright © 2016年 YouXianMing. All rights reserved.
    //
    
    #import "UIView+Shake.h"
    #import <objc/runtime.h>
    
    #define HAS_OPT(options, option) ((options & option) == option)
    
    @interface SCShakeInfo : NSObject
    
    @property (assign, nonatomic)   CGAffineTransform baseTransform;
    @property (assign, nonatomic)   BOOL shaking;
    @property (assign, nonatomic)   SCShakeOptions options;
    @property (assign, nonatomic)   CGFloat force;
    @property (assign, nonatomic)   CGFloat duration;
    @property (assign, nonatomic)   CGFloat iterationDuration;
    @property (assign, nonatomic)   CFTimeInterval startTime;
    @property (strong, nonatomic)   ShakeCompletionHandler completionHandler;
    @property (assign, nonatomic)   BOOL reversed;
    @property (readonly, nonatomic) CGFloat completionRatio;
    
    @end
    
    @implementation SCShakeInfo
    
    - (CGFloat)completionRatio {
        
        return (CACurrentMediaTime() - self.startTime) / self.duration;
    }
    
    @end
    
    @implementation UIView (Shake)
    
    static const char *ShakeInfoKey = "ShakeInfo";
    
    - (void)shake {
        
        [self shakeWithOptions:kDefaultShakeOptions
                         force:kDefaultShakeForce
                      duration:kDefaultShakeDuration
             iterationDuration:kDefaultShakeIterationDuration
             completionHandler:nil];
    }
    
    - (void)shakeWithOptions:(SCShakeOptions)shakeOptions
                       force:(CGFloat)force
                    duration:(CGFloat)duration
           iterationDuration:(CGFloat)iterationDuration
           completionHandler:(ShakeCompletionHandler)completionHandler {
        
        SCShakeInfo *shakeInfo = [self shakeInfo];
        
        shakeInfo.options           = shakeOptions;
        shakeInfo.force             = force;
        shakeInfo.startTime         = CACurrentMediaTime();
        shakeInfo.duration          = duration;
        shakeInfo.iterationDuration = iterationDuration;
        shakeInfo.completionHandler = completionHandler;
        
        if (!shakeInfo.shaking) {
            
            shakeInfo.baseTransform = self.transform;
            shakeInfo.shaking       = YES;
            
            [self _doAnimation:1];
        }
    }
    
    - (CGFloat)_getInterpolationRatio:(CGFloat)completionRatio options:(SCShakeOptions)options {
        
        CGFloat (*interpFunc)(CGFloat) = nil;
        
        if (HAS_OPT(options, SCShakeOptionsForceInterpolationRandom)) {
            
            interpFunc =& InterpolateRandom;
            
        } else if (HAS_OPT(options, SCShakeOptionsForceInterpolationExpDown)) {
            
            interpFunc =& InterpolateExpDown;
            
        } else if (HAS_OPT(options, SCShakeOptionsForceInterpolationExpUp)) {
            
            interpFunc =& InterpolateExpUp;
            
        } else if (HAS_OPT(options, SCShakeOptionsForceInterpolationLinearDown)) {
            
            interpFunc =& InterpolateLinearDown;
            
        } else if (HAS_OPT(options, SCShakeOptionsForceInterpolationLinearUp)) {
            
            interpFunc =& InterpolateLinearUp;
            
        } else {
            
            interpFunc =& InterpolateNone;
        }
        
        return interpFunc(completionRatio);
    }
    
    - (void)_animate:(CGFloat)force shakeInfo:(SCShakeInfo *)shakeInfo {
        
        CGAffineTransform baseTransform = shakeInfo.baseTransform;
        SCShakeOptions    options       = shakeInfo.options;
        
        if (HAS_OPT(options, SCShakeOptionsDirectionHorizontalAndVertical)) {
            
            if (arc4random_uniform(2) == 1) {
                
                self.transform = CGAffineTransformTranslate(baseTransform, 0, force * self.bounds.size.height);
                
            } else {
                
                self.transform = CGAffineTransformTranslate(baseTransform, force * self.bounds.size.width, 0);
            }
            
        } else if (HAS_OPT(options, SCShakeOptionsDirectionVertical)) {
            
            self.transform = CGAffineTransformTranslate(baseTransform, 0, force * self.bounds.size.height);
            
        } else if (HAS_OPT(options, SCShakeOptionsDirectionHorizontal)) {
            
            self.transform = CGAffineTransformTranslate(baseTransform, force * self.bounds.size.width, 0);
            
        } else {
            
            self.transform = CGAffineTransformRotate(baseTransform, force * M_PI_2);
        }
    }
    
    - (void)_doAnimation:(CGFloat)direction {
        
        SCShakeInfo *shakeInfo  = [self shakeInfo];
        SCShakeOptions options  = shakeInfo.options;
        CGFloat completionRatio = shakeInfo.completionRatio;
        
        if (completionRatio > 1) {
            
            completionRatio = 1;
        }
        
        if (shakeInfo.reversed) {
            
            completionRatio = 1 - completionRatio;
        }
        
        CGFloat interpolationRatio = [self _getInterpolationRatio:completionRatio options:options];
        CGFloat force              = shakeInfo.force * interpolationRatio * direction;
        CGFloat iterationDuration  = shakeInfo.iterationDuration;
        
        [UIView animateWithDuration:iterationDuration animations:^{
            
            [self _animate:force shakeInfo:shakeInfo];
            
        } completion:^(BOOL finished) {
            
            if (shakeInfo.shaking) {
                
                BOOL shouldRecurse = YES;
                if (shakeInfo.completionRatio > 1) {
                    
                    if (HAS_OPT(shakeInfo.options, SCShakeOptionsAutoreverse)) {
                        
                        shakeInfo.reversed = !shakeInfo.reversed;
                    }
                    
                    if (shakeInfo.reversed || HAS_OPT(shakeInfo.options, SCShakeOptionsAtEndRestart)) {
                        
                        shakeInfo.startTime = CACurrentMediaTime();
                        
                    } else if (!HAS_OPT(shakeInfo.options, SCShakeOptionsAtEndContinue)) {
                        
                        shouldRecurse = NO;
                        [self endShake];
                    }
                }
                
                if (shouldRecurse) {
                    
                    [self _doAnimation:direction * -1];
                }
            }
        }];
    }
    
    - (void)endShake {
        
        SCShakeInfo *shakeInfo = [self shakeInfo];
        
        if (shakeInfo.shaking) {
            
            shakeInfo.shaking                        = NO;
            self.transform                           = shakeInfo.baseTransform;
            ShakeCompletionHandler completionHandler = shakeInfo.completionHandler;
            shakeInfo.completionHandler              = nil;
            
            if (completionHandler != nil) {
                
                completionHandler();
            }
        }
    }
    
    - (BOOL)isShaking {
        
        return [self shakeInfo].shaking;
    }
    
    - (SCShakeInfo *)shakeInfo {
        
        SCShakeInfo *shakeInfo = objc_getAssociatedObject(self, ShakeInfoKey);
        
        if (shakeInfo == nil) {
            
            shakeInfo = [SCShakeInfo new];
            objc_setAssociatedObject(self, ShakeInfoKey, shakeInfo, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        
        return shakeInfo;
    }
    
    #pragma Interpolations functions
    
    static CGFloat InterpolateLinearUp(CGFloat input) {
        
        return input;
    }
    
    static CGFloat InterpolateLinearDown(CGFloat input) {
        
        return 1 - input;
    }
    
    static CGFloat Exp(CGFloat a, int power) {
        
        if (a < 0.5f) {
            
            return (float)pow(a * 2, power) / 2;
            
        } else {
        
            return (float)pow((a - 1) * 2, power) / (power % 2 == 0 ? -2 : 2) + 1;
        }
    }
    
    static CGFloat InterpolateExpUp(CGFloat input) {
        
        return Exp(input, 4);
    }
    
    static CGFloat InterpolateExpDown(CGFloat input) {
        
        return Exp(1 - input, 4);
    }
    
    static CGFloat InterpolateNone(CGFloat input) {
        
        return 1;
    }
    
    static CGFloat InterpolateRandom(CGFloat input) {
        
        CGFloat randNb = arc4random_uniform(10000);
        return randNb / 10000.0;
    }
    
    @end
  • 相关阅读:
    full gc
    C#调用C++编写的DLL
    用C#调用C++DLL提示找不到DLL解决方法【转】
    VS2015 编写C++的DLL,并防止DLL导出的函数名出现乱码(以串口通信为例,实现串口通信)
    VS2015 C++ 获取 Edit Control 控件的文本内容,以及把获取到的CString类型的内容转换为 int 型
    VS2015 建立一个C++的MFC简易窗体程序项目
    C# 实现串口发送数据(不用串口控件版)
    STM32 HAL库的定时器中断回调函数跟串口中断回调函数
    把 Python 脚本打包成可以直接双击运行的 .exe 文件 【转】
    Python 实现把 .cvs 文件保存为 Excel 文件
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/5218416.html
Copyright © 2011-2022 走看看