重力感应图片

使用方法

直接上代码

#import "DCGravityImageView.h"

DCGravityImageView *imageView = [[DCGravityImageView alloc]initWithFrame:CGRectMake(0, 100, 375, 200) ContentSize:CGSizeMake(600, 450)];
[self.view addSubview:imageView];
[imageView setupImage:[UIImage imageNamed:@"test"] placeholder:nil];

先引入DCGravityImageView,然后用提供的initWithFrame:ContentSize:方法创建一个实例,然后调用setupImage:placeholder:方法设置图片即可;

  • initWithFrame:ContentSize:第一个参数frame,就是控件DCGravityImageView的frame;第二个参数contentsize,是重力感应图片的大小(一般大小设为frame的1.5倍);
  • setupImage:placeholder:第一个参数image,展示的图片,为id类型,可以传UIImage类型,也可以传NSString(网络图片的url)类型;第二个参数placeholder,站位图,可以传nil;

还有一个管理类DCMotionManager,提供了两个方法;

@interface DCMotionManager : NSObject

+ (instancetype)shareManager;
@property (nonatomic, strong,readonly) CMMotionManager *motionManager;
///停止设备运动
- (void)stopDeviceMotionUpdates;
///开启陀螺仪
- (void)openDeviceMotionUpdates;
@end

因为开启陀螺仪会非常耗电,为了节省性能,一般会在页面消失的时候停止陀螺仪,在页面即将显示的时候开启陀螺仪,所以可以通过这个类来控制是否开启陀螺仪;

实现原理

核心类CMMotionManager,这个类可以获取设备陀螺仪的数据,然后根据陀螺仪的数据来改变view;

首先要注意尽可能在 app 中只创建一个 CMMotionManager 对象,多个 CMMotionManager 对象会影响从加速计和陀螺仪接受数据的速率。其次,在启动接收设备传感器信息前要检查传感器是否硬件可达,可以用
deviceMotionAvailable 检测硬件是否正常,用 deviceMotionActive检测当前 CMMotionManager 是否正在提供数据更新。

因此我创建了一个DCMotionManager来管理CMMotionManager,提供了一个单例方法shareManager;来保证只有一个CMMotionManager,然后提供了两个方法,stopDeviceMotionUpdates;停止设备运动openDeviceMotionUpdates;开启设备运动;

///停止设备运动
- (void)stopDeviceMotionUpdates{
    [self.motionManager stopDeviceMotionUpdates];
}
///开启陀螺仪
- (void)openDeviceMotionUpdates{
    //防止多次开启
    if(self.motionManager.deviceMotionActive) return;
    //没有陀螺仪,返回;
    if(!self.motionManager.deviceMotionAvailable) return;
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    [self.motionManager startDeviceMotionUpdatesToQueue:queue withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
        if(!error){
            [[NSNotificationCenter defaultCenter] postNotificationName:DCOpenDeviceMotionUpdatesNotification object:motion];   
        }
    }];
}

开启设备运动,并发送通知,把设备运动数据传出去;停止设备运动,直接调用CMMotionManagerstopDeviceMotionUpdates即可;

为什么不把这两个方法封装在view里面?因为封装在view里面不能保证只有一个CMMotionManager,而且在controller里面,你是很难拿到这个view,因此封装了它,你无论在哪里都能直接停止设备运动监听;

DCGravityImageView包含两个view,一个UIImageView,一个UIScrollView,把UIImageView放在UIScrollView里面,根据陀螺仪的数据,改变UIScrollViewContentOffset;

通知监听设备运动;在setupImage:placeholder:方法,设置好偏移量,把UIImageView放在UIScrollView的中间,然后调用DCMotionManageropenDeviceMotionUpdates,在dealloc方法停止设备运动,移除通知;

接收到设备运动数据的具体实现

- (void)openDeviceMotion:(NSNotification *)notification{
    if ([notification.object isKindOfClass:[CMDeviceMotion class]]) {
        CMDeviceMotion * motion = notification.object;
        CGFloat xRotationRate = motion.rotationRate.x;
        CGFloat yRotationRate = motion.rotationRate.y;
        static CGFloat kRotationMultiplier = 4.f;
        CGFloat invertedYRotationRate = yRotationRate * -1;
        CGFloat invertedXRotationRate = xRotationRate * -1;

        CGFloat zoomScaleX = (CGRectGetHeight(self.scrollView.bounds) / CGRectGetWidth(self.scrollView.bounds)) * (self.contentSize.width / self.contentSize.height);
        CGFloat zoomScaleY = (CGRectGetWidth(self.scrollView.bounds) / CGRectGetHeight(self.scrollView.bounds)) * (self.contentSize.height / self.contentSize.width);
        CGFloat interpretedXOffset = self.scrollView.contentOffset.x + (invertedYRotationRate * zoomScaleX * kRotationMultiplier);
        CGFloat interpretedYOffset = self.scrollView.contentOffset.y + (invertedXRotationRate * zoomScaleY * kRotationMultiplier);
        CGPoint contentOffset = [self __clampedContentOffsetForHorizontalOffset:interpretedXOffset verticalOffset:interpretedYOffset];
        static CGFloat kMovementSmoothing = 0.3f;
        [UIView animateWithDuration:kMovementSmoothing
                              delay:0.0f
                            options:UIViewAnimationOptionBeginFromCurrentState|
                                    UIViewAnimationOptionAllowUserInteraction|
                                    UIViewAnimationOptionCurveEaseOut
                         animations:^{
                             [self.scrollView setContentOffset:contentOffset animated:NO];
                         } completion:NULL];

    }

}

-(CGPoint)__clampedContentOffsetForHorizontalOffset:(CGFloat)horizontalOffset  verticalOffset:(CGFloat)VerticalOffset{
    CGFloat maximumXOffset = self.scrollView.contentSize.width - CGRectGetWidth(self.scrollView.bounds);
    CGFloat maximumYOffset = self.scrollView.contentSize.height - CGRectGetHeight(self.scrollView.bounds);
    CGFloat minimumXOffset = 0.f;
    CGFloat minimumYOffset = 0.f;
   
    CGFloat clampedXOffset = fmaxf(minimumXOffset, fmin(horizontalOffset, maximumXOffset));
    CGFloat clampedYOffset = fmaxf(minimumYOffset, fmin(VerticalOffset, maximumYOffset));

   return CGPointMake(clampedXOffset, clampedYOffset);
}

github地址:https://github.com/daichuan/DCGravityImage

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342