建立流暢的交互(Fluid Interfaces)

轉(zhuǎn)自 Cocoa開發(fā)者社區(qū) 微信公眾號(hào)
https://mp.weixin.qq.com/s/qWLava8mv4HJFpepSGQBww

在WWDC2018上鸡捐,蘋果設(shè)計(jì)師提出了一個(gè)關(guān)于“流暢的交互設(shè)計(jì)”的話題像吻,解釋了iPhone X手勢(shì)交互(gestural interface)背后的設(shè)計(jì)理念

image

蘋果WWDC2018“流暢的交互設(shè)計(jì)”

這個(gè)話題提供了一些技術(shù)引導(dǎo)合呐,作為一個(gè)想法,這些發(fā)布的內(nèi)容有點(diǎn)讓人意外蝇裤。但只發(fā)布了偽代碼,還留下很多謎團(tuán)。

image

演講中一些類似Swift代碼

如果你想要嘗試這些想法拣凹,你也許就會(huì)意識(shí)到理想與現(xiàn)實(shí)的差距

而我的目標(biāo)就是為這些想法提供一些代碼示例,幫助跨過這個(gè)差距恨豁。

image

我們將創(chuàng)建8個(gè)交互

什么是流暢的交互

流暢的交互要做到:快速嚣镜,平滑,自然橘蜜。給人一種很流暢的體驗(yàn)菊匿。

WWDC演講把流暢的交互稱作“用戶意識(shí)的擴(kuò)展”和“自然世界的擴(kuò)展”。只有當(dāng)一個(gè)交互表現(xiàn)得符合人類感官计福,而不是機(jī)器理念時(shí)才能算是流暢跌捆。

如何使他們顯得流暢?

流暢的交互是可響應(yīng)象颖,可中斷佩厚,可反向的。下面是一個(gè)iPhone X的”滑動(dòng)返回”手勢(shì)

image

App可以在動(dòng)畫階段被關(guān)閉

這個(gè)交互能夠立即對(duì)用戶的輸入做出反應(yīng)力麸,可以在其過程中任意時(shí)刻停止可款,還可以在中途反向育韩。

我們?yōu)槭裁搓P(guān)注流暢的交互

  1. 流暢的交互提高了用戶體驗(yàn),讓每一個(gè)響應(yīng)更快捷闺鲸,輕量筋讨,意思明確。

  2. 它們給用戶一種便于掌控的感覺摸恍,從而會(huì)更加信任你的App悉罕。

  3. 但它們并不易創(chuàng)建,一個(gè)流暢的交互很難復(fù)制立镶。

交互

在本文下面部分壁袄,我會(huì)展示如何創(chuàng)建8種交互,它們涉及到了演講中的所有主要部分媚媒。

image.gif

8個(gè)圖標(biāo)代表我們要?jiǎng)?chuàng)建的8個(gè)交互

交互1:計(jì)算器按鈕

該按鈕模仿iOS計(jì)算器的按鈕動(dòng)作

image

主要特性

  • 點(diǎn)擊后馬上高亮

  • 即使在動(dòng)畫中也可以快速點(diǎn)擊

  • 用戶可以在按下后嗜逻,手指移動(dòng)出按鈕區(qū)來取消點(diǎn)擊

  • 用戶可以在按下后,手指移動(dòng)出按鈕區(qū)缭召,再移入栈顷,此時(shí)點(diǎn)擊有效。

設(shè)計(jì)理念

我們希望按鈕有良好響應(yīng)性嵌巷,讓用戶感到它們都在好好工作萄凤。另外,我們希望如果用戶在按下之后想取消動(dòng)作的話搪哪,能夠取消靡努。這會(huì)讓用戶更快操作,因?yàn)樗麄兙涂梢赃呄脒呅袆?dòng)了晓折。

WWDC的幻燈片展示了邊動(dòng)手邊思考惑朦,可以讓行動(dòng)更迅速。

image

關(guān)鍵代碼

創(chuàng)建這個(gè)按鍵第一步要使用UIControl子類已维,而不是UIButton子類行嗤。UIButton也許也可以用,但我們要定義互動(dòng)垛耳,所以這里不需要它。

CalculatorButton: UIControl {    
  public var value: Int = 0 {        
    didSet {
       label.text = “\(value)”
    }    
  }    
  private lazy var label: UILabel = { ... }()
}

之后飘千,我們會(huì)用UIControlEvents來為各種接觸反應(yīng)設(shè)計(jì)函數(shù)堂鲜。

addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragEnter])
addTarget(self, action: #selector(touchUp), for: [.touchUpInside, .touchDragExit, .touchCancel])

我們把touchDown和touchDragEnter事件分組到一個(gè)事件中,取名為touchDown护奈,并把touchUpInside缔莲,touchDragExit,touchCancel事件分組到一個(gè)事件中霉旗,取名為touchUp

這樣我們可以用2個(gè)函數(shù)來處理動(dòng)畫

private var animator = UIViewPropertyAnimator()
@objc private func touchDown() {    
  animator.stopAnimation(true)    
  backgroundColor = highlightedColor
}
@objc private func touchUp() {    
  animator = UIViewPropertyAnimator(duration: 0.5, curve: .easeOut, animations: {        
     self.backgroundColor = self.normalColor    
  })    
  animator.startAnimation()
}

在touchDown中痴奏,我們會(huì)取消播放中的動(dòng)畫(如果有的話)蛀骇,并立即把按鍵設(shè)為高亮 (本例中設(shè)為亮灰色)

在touchUp中,我們會(huì)創(chuàng)建并播放一個(gè)新動(dòng)畫读拆,使用UIViewPropertyAnimator來更方便的取消高亮動(dòng)畫

(備注:這和iOS計(jì)算器的按鍵表現(xiàn)不完全一樣擅憔,但大致上已經(jīng)很類似)

交互2:彈性動(dòng)畫(Spring Animations)

這個(gè)交互展示如何創(chuàng)建一個(gè)彈性動(dòng)畫,其中需要指定阻尼(反彈)與響應(yīng)(速度)參數(shù)

image

主要特性:

  • 使用“設(shè)計(jì)友好”的參數(shù)

  • 不設(shè)置動(dòng)畫持續(xù)時(shí)間

  • 易于中斷

設(shè)計(jì)理念

因?yàn)樗鼈兊乃俣扰c自然表現(xiàn)檐晕,彈性能讓動(dòng)畫模型變得好看暑诸。一個(gè)彈性動(dòng)畫啟動(dòng)時(shí)非常快速辟灰,并漸漸接近最終狀態(tài)个榕。這非常適合創(chuàng)建一個(gè)給人響應(yīng)感的交互,讓人感到生動(dòng)芥喇!

創(chuàng)建彈性動(dòng)畫時(shí)的一些注意事項(xiàng):

  1. 彈性不一定要有反彈西采。把阻尼值設(shè)為1會(huì)讓動(dòng)畫慢慢接近終點(diǎn),而沒有反彈继控。大部分動(dòng)畫都需要把阻尼設(shè)為1苛让。

  2. 不要去想著持續(xù)時(shí)間。理論上一個(gè)彈性模型永遠(yuǎn)無法走完全程湿诊,如果強(qiáng)制設(shè)置一個(gè)持續(xù)時(shí)間會(huì)給人不自然的感覺狱杰。取而代之,通過設(shè)置阻尼與響應(yīng)來調(diào)整好彈性模型厅须。

  3. 中斷很關(guān)鍵仿畸,因?yàn)閺椥阅P蜁?huì)花費(fèi)很多時(shí)間來接近最終狀態(tài),用戶也許會(huì)覺得動(dòng)畫已經(jīng)完成朗和,并開始操作错沽。

關(guān)鍵代碼

在UIKit中,我們可以用UIViewPropertyAnimator和UISpringTimingParameters對(duì)象創(chuàng)建彈性動(dòng)畫眶拉∏О#可惜的是我們找不到一個(gè)帶有阻尼和響應(yīng)的初始化。最接近的是UISpringTimingParameters初始化忆植,它帶有質(zhì)量放可,剛度,阻尼和初速度朝刊。

UISpringTimingParameters(mass: CGFloat, stiffness: CGFloat, damping: CGFloat, initialVelocity: CGVector)

我們想要?jiǎng)?chuàng)建一個(gè)帶有阻尼和響應(yīng)的初始化耀里,并把它映射到所需的質(zhì)量,剛度與阻尼拾氓。

通過一些物理推導(dǎo)冯挎,我們可以得到所需的公式

image

求解彈性常數(shù)和阻尼系數(shù)

根據(jù)結(jié)果,我們可以根據(jù)所需的參數(shù)創(chuàng)建UISpringTimingParameters了

extension UISpringTimingParameters {    
  convenience init(damping: CGFloat, response: CGFloat, initialVelocity: CGVector = .zero) {        
    let stiffness = pow(2 * .pi / response, 2)        
    let damp = 4 * .pi * damping / response        
    self.init(mass: 1, stiffness: stiffness, damping: damp, initialVelocity: initialVelocity)    
  }
}

這就是我們?yōu)樗衅渌换ブ贫◤椥詣?dòng)畫的方法咙鞍。

交互3:閃光按鈕

它的表現(xiàn)很不一樣房官,模仿了iPhone X鎖屏上的閃光按鈕趾徽。

image.gif

主要特性:

  • 需要3D touch的特別手勢(shì)

  • 對(duì)所需手勢(shì)有反響提示

  • 有觸覺反饋確認(rèn)激活

設(shè)計(jì)理念

蘋果希望設(shè)計(jì)一個(gè)能簡(jiǎn)單快捷點(diǎn)擊,但又不會(huì)意外觸發(fā)的按鈕翰守。那么需要一定壓力來激活閃光就是個(gè)好辦法孵奶,但缺少功能可見性,也缺乏反饋潦俺。

為了解決這些問題拒课,這個(gè)按鈕要有彈力,并隨著用戶手指壓力而擴(kuò)大事示,對(duì)所需手勢(shì)能給出提示早像。此外,有2個(gè)獨(dú)立的震動(dòng)反饋肖爵,一個(gè)是當(dāng)施加壓力達(dá)到所需壓力時(shí)卢鹦,另一個(gè)是當(dāng)按鈕激活壓力減小時(shí)。這些觸覺是模仿一個(gè)實(shí)際按鈕的特征劝堪。

關(guān)鍵代碼

要測(cè)量施加到按鈕的壓力大小冀自,我們可以用UITouch對(duì)象提供一個(gè)觸摸事件。

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {    
  super.touchesMoved(touches, with: event)    
  guard let touch = touches.first else { 
    return 
  }    
  let force = touch.force / touch.maximumPossibleForce    
  let scale = 1 + (maxWidth / minWidth - 1) * force    
  transform = CGAffineTransform(scaleX: scale, y: scale)
}

我們根據(jù)當(dāng)前壓力秒啦,計(jì)算外形變化熬粗,當(dāng)施加壓力時(shí)按鈕會(huì)變大。

因?yàn)榘粹o被輕輕按壓時(shí)不會(huì)觸發(fā)余境,我們需要一直追蹤按鈕的狀態(tài)驻呐。

enum ForceState {    
  case reset, activated, confirmed
  }
private let resetForce: CGFloat = 0.4private 
let activationForce: CGFloat = 0.5private 
let confirmationForce: CGFloat = 0.49

通過讓confirmationForce略低于activationForce,防止用戶在跨越壓力閾值時(shí)快速反復(fù)觸發(fā)芳来。

我們用UIKit的反饋生成器來產(chǎn)生觸摸反饋

private let activationFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
private let confirmationFeedbackGenerator = UIImpactFeedbackGenerator(style: .medium)

最后含末,我們用UIViewPropertyAnimator和前面創(chuàng)建的UISpringTimingParameters初始化,來制作彈性的動(dòng)畫即舌。

let params = UISpringTimingParameters(damping: 0.4, response: 0.2)
let animator = UIViewPropertyAnimator(duration: 0, timingParameters: params)animator.addAnimations {    
  self.transform = CGAffineTransform(scaleX: 1, y: 1)    
  self.backgroundColor = self.isOn ? self.onColor : self.offColor
}animator.startAnimation()

交互4:橡皮筋

當(dāng)一個(gè)視圖對(duì)抗運(yùn)動(dòng)時(shí)佣盒,就產(chǎn)生了橡皮筋動(dòng)畫。一個(gè)例子就是一個(gè)滑動(dòng)視圖滑到了它的末尾顽聂。

image

主要特性:

  • 即使一個(gè)動(dòng)作無效肥惭,交互也始終可響應(yīng)

  • 通過不同步的接觸追蹤表示邊界

  • 通過一些運(yùn)動(dòng)來遠(yuǎn)離邊界

設(shè)計(jì)理念

橡皮筋可以告知一個(gè)無效運(yùn)動(dòng),同時(shí)依舊讓用戶有一種自己可控的感覺芜飘。它展示出邊界务豺,并把視圖拖回到有效狀態(tài)。

關(guān)鍵代碼

橡皮筋可以直接實(shí)現(xiàn)

offset = pow(offset, 0.7)

使用一個(gè)0-1之間的參數(shù)嗦明,這樣視圖會(huì)偏移其靜止位置,反向移動(dòng)一些蚪燕。參數(shù)越大移動(dòng)距離越小娶牌,參數(shù)小則移動(dòng)距離大奔浅。

進(jìn)一步講,當(dāng)拖動(dòng)時(shí)诗良,代碼經(jīng)常包含一個(gè)UIPanGestureRecognizer回叫信號(hào)汹桦。偏移量會(huì)根據(jù)初始和當(dāng)前接觸位置的差來計(jì)算,這個(gè)偏移量可以被轉(zhuǎn)換鉴裹。

var offset = touchPoint.y - originalTouchPoint.yoffset = offset > 0 ? pow(offset, 0.7) : -pow(-offset, 0.7)
view.transform = CGAffineTransform(translationX: 0, y: offset)

注意:這并不是蘋果在滑動(dòng)視圖時(shí)候的橡皮筋動(dòng)作舞骆。這個(gè)方法更加簡(jiǎn)易,但要實(shí)現(xiàn)不同的動(dòng)作會(huì)需要更多的函數(shù)径荔。

交互5:加速停頓

來看iPhone X上的app切換督禽,用戶從屏幕底部上滑,在中間停頓总处。這個(gè)交互就重現(xiàn)了這個(gè)動(dòng)作狈惫。

image

主要特性:

  • 根據(jù)手勢(shì)加速來計(jì)算停頓

  • 更快的停止代表更快的響應(yīng)

  • 不用計(jì)時(shí)器

設(shè)計(jì)理念

流暢交互需要迅速,計(jì)時(shí)器帶來的延遲鹦马,即使很短胧谈,也會(huì)使交互顯得遲鈍。

這個(gè)交互之所以很酷荸频,就是因?yàn)樗姆磻?yīng)時(shí)間是根據(jù)用戶動(dòng)作菱肖。如果他們快速停頓,交互就快速響應(yīng)旭从,慢速停頓則慢速響應(yīng)稳强。

關(guān)鍵代碼

為了測(cè)量加速度,我們可以追蹤手勢(shì)速度遇绞。

private var velocities = [CGFloat]()
private func track(velocity: CGFloat) {    
  if velocities.count < numberOfVelocities {        
    velocities.append(velocity)    
  } else {        
    velocities = Array(velocities.dropFirst())        
    velocities.append(velocity)    
  }
}

這個(gè)代碼更新velocities數(shù)組键袱,隨時(shí)獲得最新的7個(gè)速度,用于計(jì)算加速度摹闽。

為了確定加速度是否足夠大蹄咖,我們可以測(cè)量數(shù)組中第一個(gè)速度與當(dāng)前速度的差值。

if abs(velocity) > 100 || abs(offset) < 50 { 
  return 
  }
let ratio = abs(firstRecordedVelocity - velocity) / abs(firstRecordedVelocity)if ratio > 0.9 {    
  pauseLabel.alpha = 1    
  feedbackGenerator.impactOccurred()    
  hasPaused = true
}

我們同樣要檢驗(yàn)該移動(dòng)有一個(gè)最小距離與速度付鹿。如果一個(gè)手勢(shì)降低了90%的速度澜汤,我們就認(rèn)為它停頓了。

我的實(shí)現(xiàn)并不理想舵匾,測(cè)試中它運(yùn)行的很好俊抵,但應(yīng)該有更好的測(cè)量加速的方法。

交互6:條件動(dòng)量(Rewarding Momentum)

一個(gè)包含開關(guān)狀態(tài)的滑動(dòng)頁(drawer)坐梯,根據(jù)手勢(shì)的速度決定是否有反彈徽诲,

image

主要特性:

  • 點(diǎn)擊滑動(dòng)頁打開,但不啟動(dòng)反彈

  • 拖動(dòng)滑動(dòng)頁打開,啟動(dòng)反彈

  • 可交互谎替,可中斷偷溺,可反向

設(shè)計(jì)理念

滑動(dòng)頁展示了條件動(dòng)量的概念。當(dāng)用戶用一定速度拖動(dòng)滑動(dòng)頁時(shí)候钱贯,會(huì)更希望看到反彈效果挫掏。這使得交互更生動(dòng)有趣。

當(dāng)點(diǎn)擊滑動(dòng)頁時(shí)秩命,不會(huì)有反彈尉共,因?yàn)辄c(diǎn)擊不帶有某個(gè)方向的動(dòng)量,這樣表現(xiàn)更合適弃锐。

當(dāng)設(shè)計(jì)自定交互時(shí)袄友,要記住針對(duì)不同的交互應(yīng)該有不同的動(dòng)畫。

關(guān)鍵代碼

為了簡(jiǎn)化點(diǎn)擊的邏輯拿愧,我們使用一個(gè)自定的手勢(shì)識(shí)別器子類杠河,在按下時(shí)立即進(jìn)入began狀態(tài)。

class InstantPanGestureRecognizer: UIPanGestureRecognizer {    
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {        
    super.touchesBegan(touches, with: event)        
    self.state = .began    
  }
}

他同樣允許用戶在滑條運(yùn)動(dòng)時(shí)點(diǎn)擊停止浇辜,就像點(diǎn)擊滾動(dòng)中的滾動(dòng)視圖一樣券敌。要處理點(diǎn)擊,我們要檢查手勢(shì)結(jié)束時(shí)速度是否為0柳洋,并繼續(xù)動(dòng)畫待诅。

if yVelocity == 0 {    
  animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)
}

要處理一個(gè)帶速度的手勢(shì),我們首先要計(jì)算其速度相對(duì)整個(gè)剩余位移量的大小熊镣。

let fractionRemaining = 1 - animator.fractionCompletelet distanceRemaining = fractionRemaining * closedTransform.tyif distanceRemaining == 0 {    
  animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)    break
}
let relativeVelocity = abs(yVelocity) / distanceRemaining

我們使用相對(duì)速度和包含反彈的時(shí)間參數(shù)來讓動(dòng)畫繼續(xù)進(jìn)行卑雁。

let timingParameters = UISpringTimingParameters(damping: 0.8, response: 0.3, initialVelocity: CGVector(dx: relativeVelocity, dy: relativeVelocity))
let newDuration = UIViewPropertyAnimator(duration: 0, timingParameters: timingParameters).durationlet durationFactor = CGFloat(newDuration / animator.duration)animator.continueAnimation(withTimingParameters: timingParameters, durationFactor: durationFactor)

這里我們創(chuàng)建一個(gè)新的UIViewPropertyAnimator來計(jì)算動(dòng)畫花費(fèi)的時(shí)間,這樣當(dāng)動(dòng)畫繼續(xù)時(shí)我們可以提供正確的durationFactor參數(shù)绪囱。

交互7:FaceTime畫中畫(PiP)

重建iOS FaceTime中的畫中畫UI

image

主要特性

  • 輕量测蹲,空中交互(airy interaction)

  • 根據(jù)UIScrollView的減速度(deceleration rate)規(guī)劃位置

  • 根據(jù)手勢(shì)初速度進(jìn)行持續(xù)動(dòng)畫

關(guān)鍵代碼

我們最終目標(biāo)是寫下面這樣的代碼

let params = UISpringTimingParameters(damping: 1, response: 0.4, initialVelocity: relativeInitialVelocity)
let animator = UIViewPropertyAnimator(duration: 0, timingParameters: params)animator.addAnimations {    
  self.pipView.center = nearestCornerPosition
}animator.startAnimation()

我們想要?jiǎng)?chuàng)建一個(gè)帶有初速度的動(dòng)畫,它能匹配拖動(dòng)手勢(shì)(pan gesture)的速度鬼吵,并把畫中畫運(yùn)動(dòng)向最近的角

首先計(jì)算初始速度

我們要根據(jù)當(dāng)前速度扣甲,當(dāng)前位置,和目標(biāo)位置計(jì)算出相對(duì)速度齿椅。

let relativeInitialVelocity = CGVector(    dx: relativeVelocity(forVelocity: velocity.x, from: pipView.center.x, to: nearestCornerPosition.x),    dy: relativeVelocity(forVelocity: velocity.y, from: pipView.center.y, to: nearestCornerPosition.y))
func relativeVelocity(forVelocity velocity: CGFloat, from currentValue: CGFloat, to targetValue: CGFloat) -> CGFloat {    
  guard currentValue - targetValue != 0 
  else { 
    return 0 
  }    
  return velocity / (targetValue - currentValue)
}

我們可以把速度分為x和y方向琉挖,分別確定每個(gè)的大小

之后計(jì)算畫中畫應(yīng)該運(yùn)動(dòng)到的角落

為了讓我們的交互看起來自然輕量,我們會(huì)根據(jù)畫中畫的當(dāng)前運(yùn)動(dòng)情況規(guī)劃最終位置涣脚。

let decelerationRate = UIScrollView.DecelerationRate.normal.rawValuelet velocity = recognizer.velocity(in: view)
let projectedPosition = CGPoint(    x: pipView.center.x + project(initialVelocity: velocity.x, decelerationRate: decelerationRate),    y: pipView.center.y + project(initialVelocity: velocity.y, decelerationRate: decelerationRate))
let nearestCornerPosition = nearestCorner(to: projectedPosition)

我們用UIScrollView的減速度來計(jì)算他的靜止位置示辈。這個(gè)很重要,它會(huì)參考用戶的滑動(dòng)動(dòng)作遣蚀。如果一個(gè)用戶知道視圖能滑動(dòng)多遠(yuǎn)矾麻,他就可以根據(jù)這個(gè)來直觀估計(jì)需要多少力量才能把畫中畫移動(dòng)到想要的位置纱耻。

減速度可以讓交互變得輕量——只需要一個(gè)拖動(dòng)就可以把畫中畫移動(dòng)到屏幕各個(gè)地方。

我們可以使用前面提供的規(guī)劃函數(shù)來計(jì)算最終規(guī)劃位置

/// 勻減速到0時(shí)射富,運(yùn)動(dòng)的距離
func project(initialVelocity: CGFloat, decelerationRate: CGFloat) -> CGFloat {    
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate)
}

現(xiàn)在所需的最后一步就是根據(jù)規(guī)劃位置計(jì)算出最近的角膝迎。我們可以遍歷所有的角粥帚,找到距離最近的一個(gè)胰耗。

func nearestCorner(to point: CGPoint) -> CGPoint {    
  var minDistance = CGFloat.greatestFiniteMagnitude    
  var closestPosition = CGPoint.zero    
  for position in pipPositions {        
    let distance = point.distance(to: position)        
    if distance < minDistance {            
      closestPosition = position            
      minDistance = distance        
    }    
  }    
  return closestPosition
}

總結(jié):我們使用UIScrollView的減速度來規(guī)劃畫中畫運(yùn)動(dòng)到其靜止位置,并使用計(jì)算出相對(duì)速度芒涡,來放入U(xiǎn)ISpringTimingParameters中

交互8:旋轉(zhuǎn)

把畫中畫交互的概念應(yīng)用到旋轉(zhuǎn)動(dòng)畫中

image

主要特性

  • 使用規(guī)劃反映出手勢(shì)速度

  • 總是在一個(gè)有效的方向結(jié)束

關(guān)鍵代碼

這里的代碼和前面的畫中畫交互很像柴灯,我們使用同樣的構(gòu)建區(qū)塊,只是把nearestCorner函數(shù)換成了closestAngle函數(shù)

func project(...) {
   ... 
}
func relativeVelocity(...) {
   ... 
}
func closestAngle(...) {
   ... 
}

當(dāng)要最終創(chuàng)建UISpringTimingParameters時(shí)费尽,即使我們的轉(zhuǎn)動(dòng)是一維的赠群,也需要使用CGVector賦予初速度。在一維動(dòng)畫的情況下旱幼,把dx參數(shù)設(shè)為所需速度查描,而把dy設(shè)為0.

let timingParameters = UISpringTimingParameters(    
  damping: 0.8,    
  response: 0.4,    
  initialVelocity: CGVector(dx: relativeInitialVelocity, dy: 0)
)

動(dòng)畫會(huì)忽視dy,使用dx創(chuàng)建時(shí)間曲線

親手嘗試柏卤!

在實(shí)機(jī)上這些交互會(huì)更有趣冬三。Demo app可在GitHub上找到。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缘缚,一起剝皮案震驚了整個(gè)濱河市勾笆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桥滨,老刑警劉巖窝爪,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異齐媒,居然都是意外死亡蒲每,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門喻括,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邀杏,“玉大人,你說我怎么就攤上這事双妨』床” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵刁品,是天一觀的道長(zhǎng)泣特。 經(jīng)常有香客問我,道長(zhǎng)挑随,這世上最難降的妖魔是什么状您? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上膏孟,老公的妹妹穿的比我還像新娘眯分。我一直安慰自己,他們只是感情好柒桑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布弊决。 她就那樣靜靜地躺著,像睡著了一般魁淳。 火紅的嫁衣襯著肌膚如雪飘诗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天界逛,我揣著相機(jī)與錄音昆稿,去河邊找鬼。 笑死息拜,一個(gè)胖子當(dāng)著我的面吹牛溉潭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播少欺,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喳瓣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了狈茉?” 一聲冷哼從身側(cè)響起夫椭,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氯庆,沒想到半個(gè)月后蹭秋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堤撵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年仁讨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片实昨。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洞豁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荒给,到底是詐尸還是另有隱情丈挟,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布志电,位于F島的核電站曙咽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏挑辆。R本人自食惡果不足惜例朱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一孝情、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洒嗤,春花似錦箫荡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至派撕,卻和暖如春婉弹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背终吼。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氯哮,地道東北人际跪。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喉钢,于是被迫代替她去往敵國(guó)和親姆打。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 凌晨一點(diǎn)醒來做作業(yè)闲延,比預(yù)想快一點(diǎn),用了一個(gè)半小時(shí)韩玩,感覺哪里怪怪的……求老師指點(diǎn)
    fable花兒閱讀 158評(píng)論 2 1
  • 2018年4月19日 500字又來了 前天垒玲,500字來了一次,今天500字又來了找颓。 這次的500字的原因是合愈,我們班...
    amber_dou閱讀 172評(píng)論 0 0
  • 你們可曾想過 對(duì)于女人來講 墮胎是件多么可怕的事彪蓬! 美國(guó)一位名叫Anthony Levatino的婦產(chǎn)科醫(yī)生 從獲...
    心羽暖姐姐閱讀 1,002評(píng)論 7 1
  • 5月8號(hào)裝了簡(jiǎn)書APP寸莫,一直沒來得急寫下些什么東西。最近學(xué)業(yè)太忙寞焙,總有搞不完的活動(dòng)储狭,寫不完的論文互婿。 我是一個(gè)...
    Duckweed閱讀 240評(píng)論 1 1