【翻译】 iOS 8 App Extension: Today Widget

By admin in mobile.365-838.com on 2019年2月13日

基佬撑起社交半边天

记得上次开拓直播软件或然在13上看旁人撸阿撸(真的撸,撸了又撸),今后无意身边长的赏心悦目和多少美观的小伙伴都去直播了呢,基哥也抱着【看素颜】的心怀去探望大家都在中间干些什么坏事,顺便看看那些人照片和真人差多少个美图秀秀,结果让基哥觉得

你们基佬真会玩

那些异性恋们都在直播些什么?生吃仙人掌,房顶后空翻,孕妇劈大叉,胸口碎榴莲。简直都以用生命在直播,而笔者辈基宝宝们就显示文艺的多,基本上就是宿舍抖胸肌,卖萌神回复,反串对口型,正装上手摸。隔壁班的kevin换上了新买的马甲,楼上的david也初步平常的哼着美女计,对门的Erik也新网购的一批眼线笔和唇膏……大家都尝试,把每一天的黄金时间变成下一个角马们迁徙的文艺盛会,大家以肉会友,大家以脱服人。

有句诗说的好,基佬四样宝:

半夜一点荒唐睡衣姐妹

晌午五点万人登山体操大会

六零年间亚洲前卫地下发行人琢磨会

九零时代偶像复出签名握手拥抱会

——屈原

上面各种字都足以让基佬们连连直播6个钟头,比春晚还要热闹,比大巴上壮男的轮廓更让您欲扒无法。这几个(可能)红的基佬们早已和回不到特别终于看开爱回不来的时候了。


老同志直播dramaNO.5

刷脸狂媛

别泄气,爱美观没有极限

一进屋子就足以看来各类小表情和礼金,画面中的美丽的女生用着星Buck标准的基佬腔说

【hello,你好,靴靴XXX送的花~上次直播的时候你也在厚~】

就好像此刻你就在宝岛西藏客车林夜市,劈面而来宝岛乡土的气味,冲走了隔间群租房的二手烟的馥郁。那种美女基一般颜值尚可,看到听众涨比来看股票涨还心旷神怡。直播内容多半没有怎么实质内容,以闲谈为主,所以话题涵盖了生存的全方位,从雪基精到SK2从一姐到好表嫂,恨不得将总体群都搬到直播上来,反正大家也是图个养眼,而这一个雅观的女生们也在卖力


同志直播dramaNO.4

体位男神

UPUP抬起头 UPUP扭一扭

一进屋子你会听到那熟习的歌曲,看到那熟识的妆容,还有那纯熟的裙摆。此刻仙女们化身成一个个被临幸过后的舞娘,为你旋转跳跃闭着眼。老汉推车,倒挂金钩,猴子撩桃,两基一杯,他们是孔雀之国爱爱健脾开胃的活体实验,也是嗑药自嗨的基佬再现。他们雌雌莫辨,他们前凸后翘前凸,他们叫你闭嘴。他们并未在演艺,他们出狱了特性,他们做回了和睦。

今夜大家都以舞娘!


阁下直播dramaNO.3

正装袜控

衣不在多,会脱则赢

点进去就是一个大写的污!肱三头肌,斜方肌,胸大肌,腹直肌,还有露耻骨肌的您如故人么,要不要大家这一个肉多的活了!聊天就拉扯,一言不合就捏奶,奶大铁汉啊!你直播母乳啊!更可气的是会打着调教的名字进去却发现是在洗衣裳,洗!衣!服!小编裤子都脱了您给小编看那么些?!


阁下直播dramaNO.2

夜店高手

你镶在前额的猫眼射出了精典

在各样夜店茶楼直播,在饭店里从点餐到和对面做饭的师傅侃大山,从菜价到发票,从服务员到卫生间偶遇抠脚的洗菜小哥。事无巨细,都这么活跃的变今后镜头后面,就如把他自身整个朋友圈都搬到了直播里。而走夜店路线的姊姊们,则是梦寐以求挨个把卡座里的二三线名媛的脸庞毛孔都要拍出来,你有考虑过您手上4S的感想么?你不细瞧突然被你Q到的淑女三嫂们一脸吃精的神色,恨不得马上飞离人间好么,你如此做和合照只P本人有何不一样?!


阁下直播dramaNO.1

恩爱狂魔

与你相逢,好性欲

那类主播最喜爱的事就是和友爱的男票成双成对瞪着镜头,不时耳语一番,娇嗔的说几句:

矮油,讨厌啦,正直播呢,别摸啦。

您确实当不明真相的五毛党看不到么,大家只是想比比

你和你男票哪个人更可耻

然后再评价打上一句:你男票看起来好有钱的规范~(微笑)

秀恩爱,分的快,虐单身,扎你针。有时在直播的中前期阶段,还会突然三个人蜜汁微笑,起头舌吻,无视直播观众的技能指引,上演男男版活西宫。


如上五类基本囊括了基佬直播的特色,那么你要问基哥这个都要被吐槽那要直播什么才好啊?

我说作者会做乌黑料理给你看你信么?

(有图版请关怀微信公众号:基汤)

等你来弯哦~

前言:闲在小卖部混日子一段时间,就学习Swift,学学iOS8,碰巧遇上那篇小说,一个早晨做下去发现很易懂,就试试翻译并享受出来。顺便求推荐新德里的iOS工作~~~~

点那里看原稿
点那里看 onevcat
大神的学科

以下正文,表达一(Friso)下,并不是逐字翻译,同时流程与内容有涂改。

  • 如若看官太懒了直白看形成结果,可以点这里下载落成后的工程,存放在dropbox,记得自备VPN。
  • 再者那篇教程是swift
    1.0的时候写的,打开项目后会报语法错误,按提醒修改就足以。

Step 0:

在iOS
8中,苹果公司生产的应用程序增添Extension技术,可以让您的APP扩充原有功用到此外界面(布告栏,分享拦),或让差异APP间可以举办数据交互,同时不会距离当前页面。
iOS 8系统有6个辅助扩展的系统区域,分别是Today、Share、Action、Photo
Editing、Storage Provider、Custom
keyboard。接济扩展的系统区域也被称之为增加点。
下边是在IOS的延伸点的列表:

  • Today –
    对于赛事比分,股票、天气、快递那类须要实时获取同时又简约的消息,可以在通报宗旨的Today视图中开创一个Today扩充完结。Today增添又称之为Widget。

  • Share –
    在系统的享用拦中成立自定义分享,可以分享内容,分享网站或揭橥音讯。

  • Action –
    action在有着支持的扩大点中增添性最强的一个。它可以兑现转移另一个app上下文中的始末。苹果在WWDC大会上演示了一个Bing翻译动作伸张,它可以将在Safari中选中的文件翻译成差距的语言。

  • Photo Editing – 在iOS
    8以前,假若您想为你的相片添加一个特种的滤镜,你要求进入第三方app中,那一个历程是格外麻烦的。在iOS
    8中,你可以一贯在Photos中行使第三方app,如Instagram,VSCO
    cam、Aviary提供的Photo
    Editing扩充完毕对图片的编撰,而无需离开当前的app。

  • Document Provider – 也叫Storage
    Provider,可以让跨七个文件存储服务中间的管住变得更简明。类似Dropbox、谷歌(Google)Drive等储存提供商通过在iOS 8中提供一个Storage
    Provider扩张,app直接可以使用那么些扩张检索和储存文件而不再要求创制不须要的正片。

  • Custom Keyboard – 自定义键盘输入法可以让用户在总连串统范围内选择。

而那篇作品,将汇总授课 Today Extention 部分。

图片 1

Extention是怎么工作的?

在大家开始应用Today
Extensions从前,先让我们看看Extensions的一部分定义,以便精晓之后的课程。

  • 第一,Extensions不是独立的应用程序。Extensions必须依靠于一个host
    app,下边一律叫作宿主APP,同时他们的生命周期相互独立,并且可以相互接触事件。一个宿主APP可以包涵四个Extensions。

  • 当一个Extensions运行的时候,宿主APP不会同时运行。各种Extensions都有温馨的单独进程(约等于一个小的APP)。同时,可以多少个Extensions同时运行,互相间不受影响。每一趟运行Extensions都以重复开动的(重复的行使相同Extensions并不会选拔同样块内存)。

  • Extensions与宿主APP间无法向来通信,但足以尝尝通过OpenU哈弗L()来开辟宿主APP或使用NSUserDefaults存储和读取通用的数目。

The Today Extension

好了,未来我们准备开创一个widget,为了节约不须要的中期准备,
这里可以下载到原有状态的工程,记得使用VPN和修改swift
1.2 导致的语法错误。
本条原始工程是一个概括的气候数据突显应用,so……它是亟需互连网连接和一个天候数据得到的API。
而作者辈的天气数据将从
forecast.io以此网站取得,它提供天天1000条免费查询,所以在始发写代码前,最好先去挂号并得到属于您的API
key。
Oh,还有还有,要取得天气就必要所在城市的地理地点音信,所以我们还亟需若是CoreLocation来博取地理音讯。(原文略过了那步,并提供了一个教程
,但因为太简单所以笔者在那里就增加了 (.) )

Step 1:

一切准备好后,我们运行工程后应当会看到下边的界面:

图片 2

以此就是宿主APP以后的气象了,城市名跟坐标写死了 (=.=)。
下一场,开始首先步咯!

Embedded Frameworks and Code Reuse 嵌入式框架和代码重用

Extensions
的生命周期是独立于宿主APP的,同时Extensions的机能应是宿主的一些机能的延伸,Extensions与宿主应有相同的功效部分,即它们将会动用相似甚至同一的代码与逻辑。
之所以,制作Extensions的率先步,就是把通用的代码块放到一个宿主APP与Extensions都能“得到”的地点。
iOS 8的自制Framwork就可以帮到你!

以下是手续:

  1. 在Project
    Navigator中,点击project,然后在产出的面板左下方点击”+”按钮(或拔取Editor,然后AddTarget)。
![](https://upload-images.jianshu.io/upload_images/6775-d0667493f8973805.png)

这里是已经完成了状态
  1. 在开拓的面板中,选用 iOS > Framework & Library > Cocoa Touch
    Framework,然后你会晤到:
![](http://www.appcoda.com/wp-content/uploads/2014/10/weather_data_kit.png)
App Extension - Weather Data Kit



名字叫 WeatherDataKit 不要搞错了,其他按项目填,然后点一下 Finish。

姣好地点的步骤后,你会意识多少个一个叫WeatherDataKit的folder和target。展开WeatherDataKit,会面到只有一个
WeatherDataKit.h 在这里,这几个 .h 文件的是在您的种类还要采用 Obj-C 和
斯威夫特的时候使用的,成效是桥接Obj-C的头文件,当然那几个体系里并非做其他操作。

在此处我们要专注,Extension并不是可以完全协理所有Cocoa Touch
APIs的,比如上面的几点:

  • 语音输入和视频头调用
  • 从AirDrop接收数据(但亦可发送数据)
  • 常驻后台(Extensions的可用内存是很低的,同时系统内存紧张的时候也首先拿Extensions开刀)
  • 不大概选择其余带有 NS_EXTENSION_UNAVAILABLE 或接近宏定义 的类, 或
    伊芙ntKit 和 HealthKit 那种不接济Extensions的 framework
  • Access a sharedApplication object, and so cannot use any of the
    methods on that object(不亮堂那句)

近日大家编译的时候假诺采用上述的API将会际遇一些警示,可以通过勾选”Allow
app extension API
only”来就可避防止那么些警告。(这里有个列表可以参见哪些无法用在Extension上)

图片 3

纪念勾上

好了,接下去要做的很粗略,把本来在 Weather folder 中的 “Weather Data”
移动到 WeatherDataKit folder
中,记得去改被挪动文件的target(七个都要)。

图片 4

App Extension – Weather Group

图片 5

就是那里

Extra Part!

还记得上边提过,要取得天气消息,首先要得到到地理地方音讯。原科目是用固定坐标的,那里吧,大家就融洽写一个。
或许在 WeatherDataKit folder,新建一个叫 WeatherLocation 的 swift
文件。然后,在 WeatherDataKit 的 target 里添加 CoreLocation framework。

图片 6

增进须求的 framework

从此以往就足以写代码啦:

  1. 在 WeatherLocation.swift 里,表明 WeatherLocation 的 class,它继续与
    NSObject,并且会有 CoreLocation 的 delegate(记得先 import
    CoreLocation)。
  2. 接下来表明 CLLocationManager 对象
    ‘manager’,它可以扶持大家一定同时得到到详细的地理消息。
  3. 进而补上 CLLocationManagerDelegate 的法门:
  • locationManager(manager: CLLocationManager!, didUpdateLocations
    locations: [AnyObject]!)
  • locationManager(manager: CLLocationManager!, didFailWithError error:
    NSError!)
    它们一个顶住更新当前的地理地方新闻,一个担负告诉您出错的内容。
  1. 最终在 init() 方法里让 manager 启动。(记得补上 manager 的装置和指定
    delegate 对象)

有那么粗略吗?
理所当然没有。Apple对于用户的心事格外爱惜,像地理地方这种时刻出卖你的消息,当然要收获用户许可才能运用!
那么大家先回到 Weather 那么些target,找到 info 面板(只怕在 Weather folder
下找到 info.plist)。
然后添加三个值:(在iOS 7
或事先只须求一个,假若急需协理旧版本则需求做系统版本判断来做不一样处理)

  • NSLocationAlwaysUsageDescription
  • NSLocationWhenInUseUsageDescription
    图片 7
    以 info.plist 为例
类型记得要为 String
,内容根据自己需要填。补充完这两项后,当项目启动并在第一次使用地理位置信息的时候,系统就会自动弹出
Alert 要求获取授权,这是上面你填的信息就会显示在这个 Alert
里。(关于这两个 String
的使用场景,可以参考[Develop](https://link.jianshu.com?t=https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html))

好了,接下去贴一下代码:

import Foundation
import CoreLocation

class WeatherLocation : NSObject, CLLocationManagerDelegate {

typealias WeatherLocationCompletionBlock = (latLong: String?, cityName: String?, error: NSError?) -> ()

let manager = CLLocationManager()
var latAndLong : String?
var city : String?
var block : WeatherLocationCompletionBlock?

class var sharedInstance: WeatherLocation {
    struct Singleton {
        static let instance = WeatherLocation()
    }
    return Singleton.instance
}

override init() {

    super.init()

    manager.delegate = self
    manager.desiredAccuracy = kCLLocationAccuracyBest
    manager.requestAlwaysAuthorization()
}

 // MARK: 看这里看这里
func updateLocation(completion: WeatherLocationCompletionBlock) {
    if CLLocationManager.locationServicesEnabled() {
        manager.startUpdatingLocation()
        block = completion
    }
}

// MARK: CoreLocation
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

    manager.stopUpdatingLocation()

    var location:CLLocation = locations[0] as! CLLocation
    latAndLong = "\(location.coordinate.latitude),\(location.coordinate.longitude)"

    CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
        if (error != nil) {
            self.block!(latLong: "", cityName: "", error: error)
            println("Reverse geocoder failed with error" + error.localizedDescription)
        } else {
            if placemarks.count > 0 {
                let pm:CLPlacemark = placemarks[0] as! CLPlacemark
                if (pm.locality != nil) {
                    self.city = pm.locality
                    self.block!(latLong: self.latAndLong, cityName: self.city, error: nil)
                }
            } else {
                var otherError : NSError?
                otherError = NSError(domain: "Problem with the data received from geocoder", code: -9999, userInfo: nil)
                self.block!(latLong: "", cityName: "", error: otherError)
                println("Problem with the data received from geocoder")
            }
        }
    })
}

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        println("\(error)")
    }
}

好了,大家应该发现,除了在地点列出必须求落到实处的点子和对象之外,作者还添加了一个新的主意
updateLocation(completion:blockName) 和一个 block
,它的效益是询问地理地点并且经过 block 的方式再次来到结果给调用者。
亟需小心的是 updateLocation
方法并不审慎,它并没有处理结果的情形再次回到给调用者,那在骨子里开发少校会遇上标题(比如你不大概担保用户机器可以每便都询问到结果)。

然后,在 WeatherDataViewController.swift 文件中添加一个措施

func loadLocation(completionLocdLocation:(city: NSString?)->()) {
    WeatherLocation.sharedInstance.updateLocation { (latLong, cityName, error) -> () in
        weak var weakSelf = self as WeatherDataViewController
    WeatherLocation.sharedInstance.updateLocation { (latLong, cityName, error) -> () in
        WeatherService.sharedInstance.fetchWeatherData(latLong!, completion: { (data, error) -> () in
            dispatch_async(dispatch_get_main_queue()) {
                weakSelf?.weatherData = data
                weakSelf?.updateData()
                completionLocdLocation(city: cityName)
            }
        })
    }
}

loadLocation
方法里首先查询地理地方,拿到结果后查询天气音讯,拿到气象详情后更新数据并把方今都会名称再次来到给调用者,因为嵌套了
block 的关联,记得使用 weak 来吧 self 变成弱引用,防止 retain cycle
难点。

末尾,大家在 ViewController.swift 里测试一下,import WeatherDataKit(WeatherDataViewController 的 target 改变了,要求从外表引入,记得加上
framework),在 viewDidAppear 方法里增进:

weak var weakSelf = self
loadLocation { (city) -> () in
        weakSelf?.locationLabel.text = city as? String
}

运转,等 API 再次回到结果,UI
更新!(假使模拟器上边世错误,记得调整模拟器地理地点的选项,或许指定一个地理地方)

图片 8

呵呵呵呵

Step 2:

Creating the Widget

主演登场~~~继续丰硕 target,然后命名为 Weather Widget 。

图片 9

就是那么些

创制达成后,大家会发觉多了一个 Weather Widget 的 floder 和多了一个
Scheme:

图片 10

连logo都不同

前些天我们来看望一个新成立的 Today widget 会有啥样事物:

  • TodayViewController.swift
  • MainInterface.storyboard

跟一般的 ViewController 没什不同嘛~~~~但其实 TodayViewController
里已经添加了 NCWidgetProviding 那些protocol,乖乖的按须求补充完就好。还有久违的 didReceiveMemoryWarning
方法,看来 widget 是个天天惨死的命,我们想做的花俏的话记得做懒加载和在
didReceiveMemoryWarning 里做释放,不然因为 widget 体验不好就把 APP
删掉就得不尝试了。

摸索运行一下,弹出来的面板直接选 Today 就可以了,然后会看出上面的功力:

图片 11

它曾经帮您写好 Hello World 了

因为 Extension 和 宿主APP 都亟需选拔同样的代码,所以它同样要添加
framework:

图片 12

App Extension – 添加 Framework

添加完后就足以在 TodayViewController 里继承的 ViewController 改为
WeatherDataViewController ,这样就可以选取 WeatherDataViewController
的主意了。
接下去,大家要修改 MainInterface.storyboard 里的UI,使 widget
看到的消息可见跟 宿主APP 的一律。

图片 13

把原本的 Hello World 界面改成这么

根据 Apple Extensions
Guide

的指出,widget最好是比较小的,对于详细音讯要有个可适配的中度去显得或躲藏。
为此土黑字体的片段会依照用户的急需来浮现会隐藏,那有些在 stroyboard
里被一个透明的 view 所蕴藏,大家把它定义为 MoreDetailsContainer
,等下会用到。
接下来回来 TodayViewController ……

非正常,漏了一步,大家在此起彼伏写代码前,须求对 storyboard 或 xib 里的 UI
做适配。大家以此项目只扶助 iOS 8,所以可以放心的拔取 AutoLayout 跟
SizeClass。

  1. 点开 MainInterface.storyboard ,点击
    MoreDetailsContainer,大家需求它维持一定的中度并且连接在底层的地方,大家得以如此设置:
![](https://upload-images.jianshu.io/upload_images/6775-f5bedeace434ac47.png)

点点这里



![](http://www.appcoda.com/wp-content/uploads/2014/10/container_view_constraints.png)
注意不要勾选 Contrain to margins
  1. 选择 Cupertino, CA
![](http://www.appcoda.com/wp-content/uploads/2014/10/cupertino_constraints.png)
改成这样
  1. 选择 100
![](http://www.appcoda.com/wp-content/uploads/2014/10/temperature_constraint.png)
改成这样
  1. 慎选小箭头按钮
![](http://www.appcoda.com/wp-content/uploads/2014/10/caret_constraints.png)
改成这样
  1. 对此 Mostly Cloudy 那种不确定长度的
    label,大家要求让它自动依照文字改变长度,同时要跟 Summy 对齐。
    右键按住 Summy ,然后拖动到 Mostly Cloudy,选用 Horizontal Spacing。
![](http://www.appcoda.com/wp-content/uploads/2014/10/modify_option_a.png)
这样配置



或者在 Mostly Coudy 的 constraint 面板中,找到 Leading Space to
SUMMARY 的 contraint ,修改为 20。



![](http://www.appcoda.com/wp-content/uploads/2014/10/modify_option_b.png)
modify\_option\_b
  1. 任何一些参考第5步。

好,运行一下。

图片 14

那是假数据

想必您会发觉左边会有一段空白空间,大家得以用上边的代码把它填满:

func widgetMarginInsetsForProposedMarginInsets
    (defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
    return UIEdgeInsetsZero
}

切切实实效果要好试试看。

接着我们要实例化 UI 上边的要素:

  1. 回到 TodayViewController,添加一个按钮和按钮方法:
    @IBOutlet weak var showMoreButton: UIButton!
    @IBAction func showMore(sender: UIButton) {
    }
  2. 丰裕一个可变的 contraint:
    @IBOutlet weak var moreDetailsContainerHeightConstraint :
    NSLayoutConstraint!
  3. 末段定义一个 BOOL 变量,标记 moreDetailsContainer 是或不是出示:
    var widgetExpanded = false

概念完事后,伊始写相关逻辑:

  1. Widget 早先化的时候是未曾数据的,所以一开始 moreDetailsContainer
    应该是潜伏的意况:
    moreDetailsContainerHeightConstraint.constant = 0

  2. 在 showMore 方法里添加代码:
    @IBAction func showMore(sender: UIButton) {
    if widgetExpanded {
    moreDetailsContainerHeightConstraint.constant = 0
    showMoreButton.transform = CGAffineTransformMakeRotation(0)
    widgetExpanded = false
    } else {
    moreDetailsContainerHeightConstraint.constant = 220
    showMoreButton.transform =
    CGAffineTransformMakeRotation(CGFloat(180.0 * M_PI/180.0))
    widgetExpanded = true
    }
    }
    纪念在 sotryboar 里把小箭头按钮跟代码连接起来。

  3. 末段在 ViewDidLoad 方法里拉长:
    temperatureLabel.text = “–“
    summaryLabel.text = “–“
    timeLabel.text = “–“
    humidityLabel.text = “–“
    precipitationLabel.text = “–“

     loadLocation { (city) -> () in
         self.locationLabel.text = city as? String
     }
    

诸如此类widget启动的时候就会活动获取新闻。

运行吧!

图片 15

原谅那些箭头

后续

首先次翻译还有写教程呢(基本上就在胡说了),没悟出要考虑的事物依旧挺多的。
这篇教程最后还有跟 宿主APP 通过 UserDefault
来展开多少交互的部分,可是它都以用写死的数目,那里就不摆了,看看后续能无法添加更实用的不二法门来做。

相当多谢能看出最后。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 mobile.365-838.com 版权所有