有一个开锁的功能,具体的需求就类似于微信的“摇一摇”功能:摇动手机,手机震动,手机上的锁的图片摇动一下,然后发送开锁指令。需求简单,但用到了许多方面的知识。

1.摇一摇

  相对这是最简单的功能了。

  在viewController的viewDidLoad中加这两句代码,或者在你想开始监听“摇一摇”这个功能的时候,添加这两句代码:

         // 允许摇一摇功能
UIApplication.shared.applicationSupportsShakeToEdit = true
// 并让自己成为第一响应者
self.becomeFirstResponder()

  其中的 self 自然指的是需要监听“摇一摇”的视图控制器了。

  然后,重写下面三个方法,就可以了:

 // MARK: 摇一摇相关方法
override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) { super.motionBegan(motion, with: event) print("开始摇动")
} override func motionCancelled(_ motion: UIEventSubtype, with event: UIEvent?) { super.motionCancelled(motion, with: event) print("取消摇动")
} override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) { super.motionEnded(motion, with: event) // 判断是否摇动结束
if event?.subtype == UIEventSubtype.motionShake { print("摇动结束")
}
}

  实测:

  1.“开始摇动”方法最为灵敏,在“摇一摇”动作开始的一瞬间就会调用;

  2.“摇动结束”方法不一定灵敏,时灵时不灵,但是如果“开始摇动”方法已调用,那必须调用“摇动结束”方法后才可以调用下一次“开始摇动”方法。也就是说,方法的调用顺序是下面这样的(每个方法之调用一次):

  “开始摇动” -> “摇动结束” -> (第二次摇动)“开始摇动” -> ···

  3.“取消摇动”是在这样的情况下会被调用:当系统调用了“开始摇动”过后,并没有监测到摇动已经结束,也就是没有调用“摇动结束”的方法;但不能无限在这儿卡下去,系统就设置了几秒钟为超时时间。若过了这几秒仍然没有监听到调用“摇动结束”的时机,那么就会调用“取消摇动”方法并开启“开始摇动”的响应链。

  关闭自然就是关了监测就可以了:

 UIApplication.shared.applicationSupportsShakeToEdit = false

2.手机震动

  这个功能也比较简单,直接调用系统的震动函数就可以了。两步。

2.1 导入FrameWork

  如下位置,导入系统框架AudioToolbox.framework:

  这个框架的好多函数,负责手机震动与声音等等。

2.2 震动函数

  就一句话,参数也不用变,自动提供一个大概半秒到一秒的震动(复杂的震动也可以通过这个框架自定义,这里只提供一次性的短的震动的函数):

         // 震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)

3.摇动动画

  这个算是这里面最难实现的功能了。涉及到CoreAnimation框架下的CABasicAnimation这个类型。 

         // 开始动画
let momAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
// 从哪里开始
momAnimation.fromValue = NSNumber.init(value: -0.3)
momAnimation.toValue = NSNumber.init(value: 0.3)
// 动画持续时间(单次)
momAnimation.duration = 0.2
// 重复次数
momAnimation.repeatCount = // 这是重复时间,也就是无视重复次数,按照动画单次持续时间无限循环,直到到了repeatDuration规定的时间。与上面都是动画重复,一个规定次数一个规定时间,并且repeatDuration优先级高
// momAnimation.repeatDuration = 0.6 // 动画结束时是否执行逆动画
momAnimation.autoreverses = true
momAnimation.delegate = self
self.lockImageView.layer.add(momAnimation, forKey: "animateLayer") DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.6) { self.lockImageView.layer.removeAllAnimations()
}

  唯一可能需要解释的就是keyPath中的x、y、z三轴究竟是什么。它是手机的三个轴线。x表示水平,也就是左右方向;y表示竖直,也就是上下方向;z表示垂直手机屏幕的方向。具体最好自己试一试,非常直观。

  补充一些其他方面的功能。

4.生成二维码

  利用系统的CoreImage框架下的CIFilter类型,将字符串转换成二维码图片。需要一个参数,也就是想战士的信息 字符串:String

             // 1.创建过滤器
let filter = CIFilter.init(name: "CIQRCodeGenerator")
// 2.恢复默认
filter?.setDefaults()
// 3.给过滤器添加数据
filter?.setValue(String.data(using: String.Encoding.utf8), forKeyPath: "inputMessage")
// 4.获取输出的二维码
8        UIImage.init(ciImage: filter?.outputImage)

  其中,filter?.outputImage返回的是CIImage类型的图片,需要转化成UIImage类型才可赋值到UIImageView上。

  但是这样其实存在问题,那就是生成的二维码过于模糊。于是需要这样的方式进行处理:

 /**
* 根据CIImage生成指定大小的UIImage
*
* @param image CIImage
* @param size 图片宽度
*/
+ (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat)size { CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
// 1.创建bitmap;
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, , , cs, (CGBitmapInfo)kCGImageAlphaNone);
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
// 2.保存bitmap到图片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
return [UIImage imageWithCGImage:scaledImage];
}

  参数与返回值类型都介绍的很详细。这样就能获得一张高清晰度的二维码UIImage了。

5.发送短信

  有两种实现方式。

5.1 跳转到系统的发送短信的界面发送短信 

         UIApplication.shared.openURL("sms://10000")

  类似于跳转拨打电话、打开网页等等,区别在于“冒号双斜线”之前的代号。

  不过区别很明显:能提供给外界的信息很少,只有一个电话号码。不能提供短信群发、短信内容等功能;不能再发送结束后返回App。

5.2 使用系统内部框架

  据说有审核被拒的危险。不过目前我没有遇到,我想苹果官方提供的框架应该也不至于太那啥。

5.2.1 添加MessageUI.framework

  不多描述。添加苹果官方提供的发短信的框架。

5.2.2 导入头文件

  导入头文件:

 // 发送短信
#import <MessageUI/MessageUI.h>

  注意不要导错。

5.2.3 发送短信

  遵守协议MFMessageComposeViewControllerDelegate,之后在需要发送短信的地方实现代码:

     func sharedButtonDidPress(sender: UIButton) {

         // 判断能否发短信(模拟器不可以发短信)
if MFMessageComposeViewController.canSendText() { // 创建发送短信控制器
let controller = MFMessageComposeViewController.init()
controller.messageComposeDelegate = self
controller.recipients = [] // 短信接收者
controller.body = self.dataArr[][] // 短信内容
self.present(controller, animated: true, completion: nil)
}
else { print("模拟器不可以发短信")
}
}

  实现协议内容:

     // MRAK: <MFMessageComposeViewControllerDelegate>
/// 协议方法,在信息界面处理完信息结果是调用(比如点击发送、取消发送、发送失败)
///
/// - Parameters:
/// - controller: 信息控制器
/// - result: 返回的信息发送成功与否
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) { // 发送完消息就回原程序
self.dismiss(animated: true, completion: nil) switch result {
case MessageComposeResult.sent:
HTTPRequest().showHUDMessage("发送成功")
break
case MessageComposeResult.failed:
HTTPRequest().showHUDMessage("发送失败")
break
case MessageComposeResult.cancelled:
HTTPRequest().showHUDMessage("取消发送")
break
}
}

6.播放网络音频

  这个没啥好解释的,就是给你个URL你放歌呗。URL一般是这个格式的:

  后面的 .mp3 标注了格式。就这样。

  接下来先来介绍一下 AVAudioPlayer 这个播放器。

6.1  AVAudioPlayer

  6.1.1 简单的使用

  AVAudioPlayer 是 AVFoudation 框架中的一个类,主要功能就是播放音频。

  首先,我们需要先导入 AVFoudation 框架:

 #import <AVFoundation/AVFoundation.h>

  然后初始化 AVAudioPlayer 实例。这里有两种方法初始化:

    /** 0.NSError
这里可以传一个 NSError 类型的指针地址进去。如果解析音频过程中出现了错误,那么这个 NSError * 类型的实例指针就会指向一个 NSError 类型的对象,从而实现多返回值的效果。
这里利用的是指针技术。
*/
NSError *error = nil; /** 1.通过 NSData 初始化 AVAudioPlayer */
AVAudioPlayer *player1 = [[AVAudioPlayer alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://wvoice.spriteapp.cn/voice/2017/0119/5880af3c1ea81.mp3"]] error:&error]; /**
2.通过 NSURL 初始化 AVAudioPlayer
这个URL只能是本地的文件,例如
*/
AVAudioPlayer *player2 = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"123.mp3"] error:&error];

  两种初始化方式是这样的。第二种通过本地文件生成的 NSURL 初始化 AVAudioPlayer 没什么好说的,主要讲一下第一种方式。我在代码中直接使用 NSData的 dataWithContentsOfURL: 方法请求网络数据并且赋值给 player1。这样做是有问题的。问题很明显,网络请求是耗时操作,应该放在子线程中进行。我们先不考虑线程问题,先看下能否实现我们的需求。

  我通过第一种方式初始化了player,那么怎么让它播放暂停呢?

     /** 1.播放 */
[player1 play]; /** 2.暂停 */
[player1 pause]; /** 3.停止 */
[player1 stop];

  就是字面意思。可以看下官方介绍,不过其实绕来绕去也还就是 播放 暂停 停止。

  这样,最基本的功能我们就实现了。

  但是,这样虽然可以播放了(先不考虑先成问题),但是控制台却在不停的打印这条消息:

 [aqme] : AQDefaultDevice (): skipping input stream   0x0

  这其实是Xcode8之后出现的问题。原因不明,解决方法:

  解决。

  6.1.2 AVAudioPlayer的一些属性和代理方法

  值得留意的属性有这些:

 // 1.音量
player1.volume =0.8;//0.0-1.0之间 // 2.循环次数
player1.numberOfLoops =;//默认只播放一次 // 3.播放位置
player1.currentTime =15.0;//可以指定从任意位置开始播放 // 4.声道数
NSUInteger channels = player1.numberOfChannels; // 只读属性 // 5.持续时间
NSTimeInterval duration = player1.duration; // 获取持续时间 // 6.仪表计数
player1.meteringEnabled =YES; // 开启仪表计数功能
[player1 updateMeters]; // 更新仪表计数

  需要遵守的协议是这个:<AVAudioPlayerDelegate>

  协议方法:

 #pragma mark - <AVAudioPlayerDelegate>
/** 1.播放结束 */
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { NSLog(@"播放音频结束了");
} /** 2.解析音频出错 */
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error { NSLog(@"解析音频出错");
} /** 3.播放(开始)被中断
原因:例如接电话等导致播放被中断
*/
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player { NSLog(@"播放音频中断");
} /** 4.播放中断结束
*/
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player { [self.player play];
}

  其中3和4被废弃了:

6.2 AVPlayer



iOS摇一摇功能、震动功能、简单的摇动动画、生成二维码图片与发送短信等几个功能的更多相关文章

  1. iOS几个功能:1.摇一摇;2.震动;3.简单的摇动动画;4.生成二维码图片;5.发送短信;6.播放网络音频等

    有一个开锁的功能,具体的需求就类似于微信的“摇一摇”功能:摇动手机,手机震动,手机上的锁的图片摇动一下,然后发送开锁指令.需求简单,但用到了许多方面的知识. 1.摇一摇 相对这是最简单的功能了. 在v ...

  2. java生成二维码扫码网页自动登录功能

    找了很多资料,七七八八都试了一遍,最终写出来了这个功能. 菜鸟一枚,此文只为做笔记. 简单的一个生成二维码,通过网页确认登录,实现二维码页面跳转到主页面. 有三个servlet: CodeServle ...

  3. iOS 根据url生成二维码贴到底图上

    根据url 生成指定尺寸的二维码图片 UIImage * createBinaryCodeImg(const char * url ,CGFloat size) { //create binary c ...

  4. iOS开发——生成二维码——工具类

    啥也不说,直接上源码,拷过去就能用.生成二维码的工具类使用方法在ProduceQRCode.h里有示例说明 分别将下面的ProduceQRCode.h和ProduceQRCode.m对应的代码考到自己 ...

  5. 简单的 自动生成 二维码 PHP 方法

    方法一:<style type="text/css">.eweima{    width:200px; height:200px; margin:auto;}</ ...

  6. 使用jquery.qrcode生成二维码实现微信分享功能

    前言: 最近有个这样的需求,在pc端的商品详情页增加分享功能. 微博分享.QQ好友分享.QQ空间分享这些都很常见.但是微信分享我还没有手动写过(以前改过). 最终效果如下图: 解决方案:使用jquer ...

  7. iOS 简单易用的二维码扫描及生成二维码三方控件LFQRCode,可灵活自定义UI

    一.扫码 扫描的控件是一个view,使用者只需贴在自己的控制器内即可.其他UI用户可在自己控制器随便添加.代码如下 - (void)viewDidLoad { [super viewDidLoad]; ...

  8. IOS开发技巧快速生成二维码

    随着移动互联网的发展,二维码应用非常普遍,各大商场,饭店,水果店 基本都有二维码的身影,那么ios中怎么生成二维码呢? 下面的的程序演示了快速生成二维码的方法: 在ios里面要生成二维码,需要借助一个 ...

  9. iOS开发之生成二维码

    一.二维码的生成 从iOS7开始集成了二维码的生成和读取功能 此前被广泛使用的zbarsdk目前不支持64位处理器   1.二维码的内容(传统的条形码只能放数字) 纯文本 名片 URL   2.生成二 ...

随机推荐

  1. Dispose模式

    Dispose模式 Dispose模式是.NET中很基础也很重要的一个模式,今天重新复习一下相关的东西并记录下来. 什么是Dispose模式? 什么时候我们该为一个类型实现Dispose模式 使用Di ...

  2. 实战 ASP.NET MVC Web API

    实战 ASP.NET MVC Web API Web API 框架基于 ASP.NET MVC 框架开发,是一个面向 Http 协议的通信框架.相对于 WCF 而言,Web API 只面向于 Http ...

  3. 去除scons构建动态库的前缀lib

    如何使用scons构建工程,请参考快速构建C++项目工具Scons,结合Editplus搭建开发环境. 编译SharedLibrary项目的时候,生产的so文件时自动加上lib, 例如: env = ...

  4. UVa1003-Cutting sticks

    试题描述 将一段木棒按要求切割,每次切割都要付出与木棒长度相同的代价,求最小代价切割. (多组数据) 输入描述 长度L. 切割点数n(n<=50). n个切割点. 输出描述 "The ...

  5. 排序算法用C++的基本算法实现十个数排序

    本文个人在青岛喝咖啡的时候突然想到的...近期就有想写几篇关于排序算法的文章,所以回家到之后就奋笔疾书的写出来发布了 冒泡排序法 道理: 它重复地访问过要排序的数列,一次比较两个元素,如果他们的顺序错 ...

  6. 本地通过Eclipse链接Hadoop操作Mysql数据库问题小结

    前一段时间,在上一篇博文中描述了自己抽时间在构建的完全分布式Hadoop环境过程中遇到的一些问题以及构建成功后,通过Eclipse操作HDFS的时候遇到的一些问题,最近又想进一步学习学习Hadoop操 ...

  7. JSP引擎的工作原理

    JSP运行环境: 执行JSP代码需要在服务器上安装JSP引擎,比较常见的引擎有WebLogic和Tomcat.把这些支持JSP的web服务器配置好后.就可以再客户端通过浏览器来访问JSP页面了.默认端 ...

  8. 在html页面中展示JSON

    背景: 有时候我们需要将json数据直接显示在页面上(比如在做一个接口测试的项目,需要将接口返回的结果直接展示),但是如果直接显示字符串,不方便查看.需要格式化一下. 解决方案: 其实JSON.str ...

  9. delphi 程序输出文件夹存放位置

  10. aforge通过角点匹配图片相似度

    我不知道什么原因,人品不好还是啥的 ExhaustiveTemplateMatching这个类无法高精确度的匹配图片 ........... 换一种方式,就好得多 /// <summary> ...