在iOS8 下用Swift 创建自定义的键盘
本文翻译自How to make a custom keyboard in iOS 8 using Swift
我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一个莫斯码键盘。大概需要你花20多分钟来走完所有的步骤。 完整代码
综述
一个自定义的键盘会替换系统的键盘,来提供给用户一个新的文本输入方法,或者输入哪些iOS系统还不支持的语言。一个自定义键盘的基本功能很简单:响应点击,手势或者其它输入事件以及在当前的文本输入对象的文本插入点上提供非属性化的NSString对象的文本。
当用户选择了一个键盘,那么当用户打开一个app时,这个键盘会作为默认的键盘显示。因此这个键盘必须允许用户切换到另一个键盘。
对于每个自定义键盘,有两个开发要素:
信任 : 你的自定义键盘可以访问用户输入的每个字符,所以你和你用户之间的信任非常重要。
下一个键盘按键 : 能够让用户切换另一个键盘这种可见性的功能应该是一个键盘用户界面的一部分;你必须提供这个切换功能。
注意:如果你只需要添加几个按钮到系统的键盘,你应该查看 Custom Views for Data Input
一个自定义键盘不能够做什么
有一些特定的输入对象是你的自定义键盘没资格输入的:安全领域(例如密码输入框), 电话键盘对象(如在通讯录中的电话号码输入框)。
你的自定义键盘不能访问输入视图的层级结构,不能控制光标和选择文本。
另外,自定义键盘无法在顶行以上显示任何东西(如系统键盘,当你在顶行长按一个按键时)。
沙盒
默认情况下,一个键盘是没有网络访问权限的,而且也无法与键盘的容器app分享文件。为了获得这些权限,可以在Info.plist 文件中设置 RequestsOpenAccess
这个布尔类型的键的值为 YES。 做这些会扩展键盘的沙盒,如 Establishing and Maintaining User Trust.中描述的。
如何你这么做来申请开放权限,你的键盘会获得一下功能,每一个都伴随着责任:
访问位置服务和 Address BOOK 数据库,在第一次访问时会要求申请用户权限。
可以与包含键盘的app共享一个容器,例如这样可以允许在包含键盘的app里面提供一个自定义的词库管理界面。
能够发送键盘的点击和其它输入事件到服务端去处理。
访问iCloud,例如确保同一个用户的键盘的设置和你的自动更正词库在所有设备上同步。
通过包含键盘的app访问Game Center 和 应用内购买。
如果你设计你的键盘支持手机设备管理(MDM),那么还可以允许与管理的app一起工作。
确保你阅读了Designing for User Trust,它描述了在你申请开放权限的情况下,你尊重和保护用户数据的责任。
高层视图
下面的图片显示了在一个运行的键盘中一些重要的对象,并且显示了在一个典型的开发流程中这些对象来源于哪里。在一个最基本的形式中,我们有一个app包含了键盘扩展和一个控制这个键盘和响应用户事件的UIInputViewController
对象。
这个自定义的键盘模版包含一个 UIInputViewController
的子类,这是你的键盘的主视图控制器。让我们看看它的接口是怎么定义的:
class UIInputViewController : UIViewController, UITextInputDelegate, NSObjectProtocol {var inputView: UIInputView!var textDocumentProxy: NSObject! { get }func dismissKeyboard()func advanceToNextInputMode()// This will not provide a complete repository of a language's vocabulary.// It is solely intended to supplement existing lexicons.func requestSupplementaryLexiconWithCompletion(completionHandler: ((UILexicon!) -> Void)!)
}
inputView
是这个键盘的视图,与view
属性一样dismissKeyboard
方法可以被调用来关闭键盘视图advanceToNextInputMode
是用来切换键盘的textDocumentProxy
是你将用来与当前的文本输入进行交互的对象。
例如:
self.textDocumentProxy.insertText("We ❤ Swift") // inserts the string "We ❤ Swift" at the insertion pointself.textDocumentProxy.deleteBackward() // Deletes the character to the left of the insertion point
UIInputViewController
实现了UITextInputDelegate
协议,当文本或者选择的文本发生变化时,会使用selectionWillChange
,selectionDidChange
,textWillChange
和textDidChange
消息来通知你。
创建一个莫斯码键盘
我们将创建一个简单的键盘,可以输入点和破折号,切换键盘,删除一个字符以及关闭键盘。这个例子只通过代码来创建用户界面。我们也可以使用Nib 文件来创建界面-这个会在教程末尾涉及到。 加载Nibs 文件可能会对性能产生负面影响。
创建一个新的工程
打开Xcode 6, 创建一个新的“Single Page Application” 项目,选择 Swift作为开发语言。
添加一个text field 文本框
打开 Main.storyboard
,然后从 Component Library 中拖动一个文本框。我们将在后面使用这个来测试我们的键盘。
把这个文本框居中,添加必要的约束。
暗示: 如果你在 viewDidLoad
中调用 textField.becomeFirstResponder()
那么当你打开这个app时键盘就会打开。
添加键盘扩展
在navigator中选择项目文件,点击 + 号添加一个新target。
选择 Application Extension
,使用 Custom Keyboard
模版, 命名为MorseCodeKeyboard
。
这样就会创建一个新的组,名叫 MorseCodeKeyboard
,里面包含了两个文件 KeyboardViewController.swift
和 Info.plist
。
清理
打开 KeyboardViewController.swift
文件。这个模版键盘有一个已经创建好的按钮,用来进行切换键盘的。把这些代码从 viewDidLoad
中移到一个新的方法 addNextKeyboardButton
中。
func addNextKeyboardButton() {self.nextKeyboardButton = UIButton.buttonWithType(.System) as UIButton...var nextKeyboardButtonBottomConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: -10.0)self.view.addConstraints([nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint])
}
创建一个 addKeyboardButtons
方法,然后在 viewDidLoad
中调用它。这样会有助于组织代码。现在我们只是有了几个按钮,但是在实际的项目中会有更多的按钮。 在 addKeyboardButtons
中调用 addNextKeyboardButton
。
class KeyboardViewController: UIInputViewController {...override func viewDidLoad() {super.viewDidLoad()addKeyboardButtons()}func addKeyboardButtons() {addNextKeyboardButton()}...}
点
现在添加点按钮。 创建一个类型为 UIButton!
为的 dotButton
属性。
class KeyboardViewController: UIInputViewController {var nextKeyboardButton: UIButton!var dotButton: UIButton!...
}
添加一个 addDot
方法。 以一个系统类型的按钮来初始化这个 dotButton
属性。给 TouchUpInside
事件添加一个回调。 设置一个更大的字体和添加一个圆角。 添加约束来把这个按钮放在离水平中心位置左边 50个点,垂直居中的位置。 代码与 nextKeyboardButton
的类似。
func addDot() {// initialize the buttondotButton = UIButton.buttonWithType(.System) as UIButtondotButton.setTitle(".", forState: .Normal)dotButton.sizeToFit()dotButton.setTranslatesAutoresizingMaskIntoConstraints(false)// adding a callbackdotButton.addTarget(self, action: "didTapDot", forControlEvents: .TouchUpInside)// make the font biggerdotButton.titleLabel.font = UIFont.systemFontOfSize(32)// add rounded cornersdotButton.backgroundColor = UIColor(white: 0.9, alpha: 1)dotButton.layer.cornerRadius = 5view.addSubview(dotButton)// makes the vertical centers equa;var dotCenterYConstraint = NSLayoutConstraint(item: dotButton, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1.0, constant: 0)// set the button 50 points to the left (-) of the horizontal centervar dotCenterXConstraint = NSLayoutConstraint(item: dotButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1.0, constant: -50)view.addConstraints([dotCenterXConstraint, dotCenterYConstraint])
}
使用 textDocumentProxy
实现 dotButton
的回调。
func didTapDot() {var proxy = textDocumentProxy as UITextDocumentProxyproxy.insertText(".")
}
在 addKeyboardButtons
中调用 addDot
。
func addKeyboardButtons() {addDot()addNextKeyboardButton()
}
对于 dash
,delete
, hideKeyboard
按钮,过程类似。
破折号
代码类似于 dotButton
,为了把它对称地放在水平中心位置,只需要改变水平约束的常量即可:
func addDash() {...// set the button 50 points to the left (-) of the horizontal centervar dotCenterXConstraint = NSLayoutConstraint(item: dotButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1.0, constant: -50)view.addConstraints([dashCenterXConstraint, dashCenterYConstraint])
}func didTapDash() {var proxy = textDocumentProxy as UITextDocumentProxyproxy.insertText("_")
}
删除按钮
删除按钮会使用 deleteBackward
方法从 textDocumentProxy
中删除一个字符。 这个布局约束与 nextKeyboardButton
对称( .Left -> .Right, .Bottom-> .Top)。
func addDelete() {deleteButton = UIButton.buttonWithType(.System) as UIButtondeleteButton.setTitle(" Delete ", forState: .Normal)deleteButton.sizeToFit()deleteButton.setTranslatesAutoresizingMaskIntoConstraints(false)deleteButton.addTarget(self, action: "didTapDelete", forControlEvents: .TouchUpInside)deleteButton.backgroundColor = UIColor(white: 0.9, alpha: 1)deleteButton.layer.cornerRadius = 5view.addSubview(deleteButton)var rightSideConstraint = NSLayoutConstraint(item: deleteButton, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .Right, multiplier: 1.0, constant: -10.0)var topConstraint = NSLayoutConstraint(item: deleteButton, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .Top, multiplier: 1.0, constant: +10.0)view.addConstraints([rightSideConstraint, topConstraint])
}func didTapDelete() {var proxy = textDocumentProxy as UITextDocumentProxyproxy.deleteBackward()
}
隐藏键盘
hideKeyboardButton
会在点击时,调用 dismissKeyboard
来隐藏键盘:
func addHideKeyboardButton() {hideKeyboardButton = UIButton.buttonWithType(.System) as UIButtonhideKeyboardButton.setTitle("Hide Keyboard", forState: .Normal)hideKeyboardButton.sizeToFit()hideKeyboardButton.setTranslatesAutoresizingMaskIntoConstraints(false)hideKeyboardButton.addTarget(self, action: "dismissKeyboard", forControlEvents: .TouchUpInside)view.addSubview(hideKeyboardButton)var rightSideConstraint = NSLayoutConstraint(item: hideKeyboardButton, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .Right, multiplier: 1.0, constant: -10.0)var bottomConstraint = NSLayoutConstraint(item: hideKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .Bottom, multiplier: 1.0, constant: -10.0)view.addConstraints([rightSideConstraint, bottomConstraint])
}
使用 Nib 文件
为了不用手写这些布局约束,你可以创建一个界面文件,然后直接在上面添加约束。
创建一个界面文件
右击 MorseCodeKeyboard
组,然后选择 New File.
选择 User Interface 和 View 模版。 命名为 CustomKeyboardInterface
选择 File's Owner ,改变类名为 KeyboardViewController
在视图中添加一个按钮,设置标题为 We ❤ Swift
。 界面类似下面这样:
加载界面
在 init(nibName, bundle)
构造器中加载 CustomKeyboard
nib 文件
class KeyboardViewController: UIInputViewController {...var customInterface: UIView!init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)var nib = UINib(nibName: "CustomKeyBoardInterface", bundle: nil)let objects = nib.instantiateWithOwner(self, options: nil)customInterface = objects[0] as UIView}...}
添加到 inputView
在 viewDidLoad
方法中,添加自定义的界面到inputView中。
class KeyboardViewController: UIInputViewController {...override func viewDidLoad() {super.viewDidLoad()view.addSubview(customInterface)...}...
}
给按钮添加一个回调
class KeyboardViewController: UIInputViewController {...@IBAction func didTapWeheartSwift() {var proxy = textDocumentProxy as UITextDocumentProxyproxy.insertText("We ❤ Swift")}...
}
连接按钮的事件到这个回调上
右键这个按钮,然后点击 touchUpInside
并拖动到 didTapWeHeartSwift
这个 IBAction中
最后,代码应该是这样的。
在你的设备上安装这个容器app
在你的设备上运行这个app后,如下来添加你的自定义键盘:
选择键盘。
选择添加一个新键盘。找到我们的 MorseCode
键盘:
现在重新运行我们的应用,尽情享受我们的新键盘吧。
转载于:https://www.cnblogs.com/YungMing/p/4492869.html
在iOS8 下用Swift 创建自定义的键盘相关推荐
- [译] 用 Swift 创建自定义的键盘
本文翻译自 How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一 ...
- windows快捷键自定义_在Windows中创建自定义Windows键盘快捷键
windows快捷键自定义 Nearly everyone uses keyboard shortcuts of some sort on their Windows system but what ...
- Android创建自定义系统键盘
原文标题:Create A Custom Keyboard on Android 原文链接:http://code.tutsplus.com/tutorials/create-a-custom-key ...
- Swift之使用key paths创建自定义查询函数 | CSDN创作打卡
一.前言 作为一个相当严格,静态编译的语言,Swift 可能不会在语法自定义方面提供许多渠道,但这实际上确正好相反.通过如何在 Swift 中自定义操作符,Swift 中 key paths 的能力, ...
- Swift之使用KeyPaths创建自定义查询函数
一.前言 作为一个相当严格,静态编译的语言,Swift 可能不会在语法自定义方面提供许多渠道,但这实际上确正好相反.通过如何在 Swift 中自定义操作符,Swift 中 KeyPaths 的能力,函 ...
- java闪屏怎么制作,Java Swing创建自定义闪屏:在闪屏下画进度条(一)
Java Swing创建自定义闪屏:在闪屏上画进度条(一) 由于本人十分热爱Java Swing,所以平时闲暇之余总是喜欢极尽所能去搜藏一些自认为比较"酷"的Swing代码来研究揣 ...
- 在linux下创建自定义service服务
三个部分 这个脚本分为3个部分:[Unit] [Service] [Install]. Unit Unit表明该服务的描述,类型描述.我们称之为一个单元.比较典型的情况是单元A要求在单元B启动之后再启 ...
- Sharepoint SP1下创建自定义字段应注意的问题
Sharepoint SP1创建自定义字段下面有一个Bug,我不知道SP2解决了这个问题没有: 通过调用自定义字段类型父类的SetCustomProperty(string propertyName, ...
- Windows下创建自定义服务的正确姿势(InstrsrvSrvany)
总览 Windows NT工具包(Windows NT Resource Kit)提供了两个小工具,可以让我们创建自定义服务(适合于NT应用和一些16进制应用,批处理除外).两个工具包的下载地址:CS ...
最新文章
- 240个jquery插件
- 【 ML 】Newton – Raphson Iteration Procedure of TOA - Based Positioning Simulation
- Redis持久化实践及数据恢复
- rabbitmq 同步策略_RabbitMQ(三):消息持久化策略
- C++ 创建单级、多级目录
- iOS APP安全杂谈之三
- 【Java1】jdk安装/idea安装,关键字/数据类型/标识符,运算符,/包/类,运算符,if/switch,for/while
- Cus系统beta1.2发布
- .NetCore下使用Polly结合IHttpClientFactory实现聚合服务
- linux之用openssl命令Base64编码解码、md5/sha1摘要、AES/DES3加密解密
- Android9很多游戏玩不了,安卓狂野飙车9玩不了应该如何解决
- 又一北大系AI公司浮出水面,百炼智能宣布获千万元天使投资
- 计算机应用基础学科计划,《计算机应用基础》教学计划
- 北京科技大学计算机专业在哪个校区,北京科技大学有几个校区及校区地址
- Argo Rollouts 实现蓝绿/金丝雀发布
- AMD GPU模式设置(1):核心数据结构
- Guava中基础工具类Joiner的使用字符串拼接方法 joiner.on
- 密码算法原理与分析:RSA安全与秘钥基础设施
- 2021年黔江中学高考成绩查询,2020年高考渝东南市重点中学谁成绩最好?黔江中学还是秀山中学?...
- useSSL=false和true的区别
热门文章
- 用iframe transform: scale() 缩小后点不到按钮_“打分”或者“打多少分”用英文可以怎样去表达?...
- c3p0依赖导入失败问题(在使用到c3p0中的ComboPooledDataSource类的时候报错,依赖爆红)
- excel合并计算_【Excel】合并计算和模拟分析的应用
- 最长回文子串Python解法
- mysql获取多张表中的数据_mysql 之多表查询
- 福建省计算机学会 noip比赛,重磅!福州一三附学生领衔全省前九名!他们将代表福建参加全国比赛!...
- 查询mysql视图_MySQL数据库简介及常用命令
- ai边缘平滑_AI基础教程113:“效果”菜单之“画笔描边”(一)喷溅效果
- xp系统没有服务器时间,WinXP系统时间无法同步网络时间连时区也不显示的解决方法...
- oracle awr 数据删除,Oracle AWR 删除历史快照 说明【转自dave偶像大神】