Slide 1

Slide 1 text

ߦ໦ ઍय़ʢͳΊ͖ ͪ͸Δʣ גࣜձࣾαΠόʔΤʔδΣϯτ ϚελϦϯά CGAffineTransform iOSDC Japan 2018 Sep. 1 Twitter, Qiita, GitHub @Ridwy

Slide 2

Slide 2 text

͜Μͳܦݧɺ͋Γ·ͤΜ͔ʁ ࣸਅ΍ಈըΛճస͠Α͏ͱͨ͠Β
 Ͳ͔͜΁ߦͬͯ͠·ͬͨ UIViewΛΞχϝʔγϣϯ͍ͤͨ͞Μ͚ͩͲ
 transform͕Α͘Θ͔Βͳ͍

Slide 3

Slide 3 text

CGAffineTransform 2࣍ݩͷΞϑΟϯม׵ @ Core Graphics framework

Slide 4

Slide 4 text

ΞϑΟϯม׵ͬͯʁ ࠲ඪม׵ͷҰछ ฏߦҠಈΛ൐͏ઢܗม׵

Slide 5

Slide 5 text

਺ֶతʹ͸ɺ͜Μͳߦྻ q p T q = pT ఺pΛม׵TͰqʹҠ͢

Slide 6

Slide 6 text

SwiftͰͷఆٛ public struct CGAffineTransform { public var a: CGFloat public var b: CGFloat public var c: CGFloat public var d: CGFloat public var tx: CGFloat public var ty: CGFloat }

Slide 7

Slide 7 text

࢖͍ํ

Slide 8

Slide 8 text

ੜ੒ static var identity: CGAffineTransform init(a: CGFloat, b: CGFloat, c: CGFloat, d: CGFloat, tx: CGFloat, ty: CGFloat) init(translationX tx: CGFloat, y ty: CGFloat) init(scaleX sx: CGFloat, y sy: CGFloat) init(rotationAngle angle: CGFloat) ฏߦҠಈ ֦େɾॖখ ճస

Slide 9

Slide 9 text

ద༻ let q = p.applying(transform) CGPoint
 
 ఺ CGSize
 
 αΠζ CGRect
 
 ྖҬ pʹtransformΛద༻ͯ͠qʹҠ͢ (x, y) (x, y) width height width height

Slide 10

Slide 10 text

q = pABC let q = p.applying(a).applying(b).applying(c) let q = p.applying(a.concatenating(b).concatenating(c)) ࿈ଓͯ͠ద༻ concatenating Ͱ1ͭͷม׵ʹ·ͱΊΒΕΔ ͜ΕΒ͸਺ֶతʹ͸ɺ͜͏ ίʔυͱ਺ࣜͰॻ͘ॱ൪͕Ұॹʂ

Slide 11

Slide 11 text

ͪΐͬͽΓ਺ֶͷิ଍ ڭՊॻͰΑ͘ݟ͔͚ΔΞϑΟϯม׵ ߦͱྻΛೖΕସ͑Δʢ=సஔʣͱੵͷॱ൪͕ٯʹͳΔ q = T p T T T

Slide 12

Slide 12 text

۩ମྫ αʔόαΠυΤϯδχΞ “iOS͔ΒૹΒΕͯདྷΔࣸਅͷαΠζ͕େ͖͗͢·͢ ਅΜத͔͍͠Βͳ͍ͷͰਖ਼ํܗʹΫϩοϓͯ͠ ྑ͍ײ͡ʹͯ͠ૹͬͯ໯͑·ͤΜ͔ʁ”

Slide 13

Slide 13 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ཁٻΛ͢΂ͯຬͨ͢ɺUIImageΛม׵͢Δίʔυʢશจʣ

Slide 14

Slide 14 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 15

Slide 15 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 16

Slide 16 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 17

Slide 17 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 18

Slide 18 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 19

Slide 19 text

let length: CGFloat = 512 let squareSize = CGSize(width: length, height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻

Slide 20

Slide 20 text

͞Βʹɺ࢖͍ํ

Slide 21

Slide 21 text

ΞϑΟϯม׵Λ͞Βʹม׵͢Δ func translatedBy(x tx: CGFloat, y ty: CGFloat) -> CGAffineTransform func scaledBy(x sx: CGFloat, y sy: CGFloat) -> CGAffineTransform func rotated(by angle: CGFloat) -> CGAffineTransform

Slide 22

Slide 22 text

ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2) .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y

Slide 23

Slide 23 text

ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2) .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y

Slide 24

Slide 24 text

ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2) .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y

Slide 25

Slide 25 text

ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2) .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y

Slide 26

Slide 26 text

ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2) .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y

Slide 27

Slide 27 text

਺ֶతʹ͸ɺ͜͏ concatenating()΍CGRectͳͲͷapplying()ͱ͸൓ରଆ͔Βֻ͚Δ let transform = CGAffineTransform.identity .translatedBy(x: 10, y: 0) // A .rotated(by: .pi/2) // B .scaledBy(x: 1.4, y: 1.4) // C .translatedBy(x: 5, y: 0) // D let q = p.applying(transform) q = pDCBA

Slide 28

Slide 28 text

۩ମྫ ϓϥϯφʔ “ࣸਅʹελϯϓΛ͚͍ͭͨͰ͢ ࢦͰҠಈͰ͖ͯɺ֦େͨ͠Γճͨ͠Γ”

Slide 29

Slide 29 text

@objc func handlePan(_ recognizer: UIPanGestureRecognizer) { let t = recognizer.translation(in: stamp.superview) stamp.center = stamp.center.applying(.init(translationX: t.x, y: t.y)) recognizer.setTranslation(.zero, in: stamp.superview) } @objc func handlePinch(_ recognizer: UIPinchGestureRecognizer) { let scale = recognizer.scale stamp.transform = stamp.transform.scaledBy(x: scale, y: scale) recognizer.scale = 1 } @objc func handleRotation(_ recognizer: UIRotationGestureRecognizer){ let rotation = recognizer.rotation stamp.transform = stamp.transform.rotated(by: rotation) recognizer.rotation = 0 } ֦େॖখͱճస → transform Ҡಈ → center ελϯϓͷUIViewͷϓϩύςΟΛมߋ࣮ͯ͠ݱ

Slide 30

Slide 30 text

·ͱΊʢߟ͑ํͷίπʣ • CGPoint, CGSize, CGRectͷ applying() ͸
 superviewͷ࠲ඪܥͷதͰద༻͞ΕΔ • ΞϑΟϯม׵Λ͞Βʹม׵͢Δϝιου
 translatedBy(x:y:), scaledBy(x:y:), rotated(by:) ͸
 ϩʔΧϧͳ࠲ඪܥΛม׵͢Δ

Slide 31

Slide 31 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠