하앍하앍 드디어!!!!!! 굿캘린더의 IOS 버전을 리뷰에 올렸다. 현재 심사 대기 중. 아아 심장이 바운스 바운스!!!!!! 리뷰 통과했드아아아~~ 아하하하하하
from. giphy.com
주말에는 나와서 튜토리얼/미리보기 영상과 스냅샷들을 준비하느라 분주했음. 튜토리얼 영상을 만드느라 앱 동작 위에 터치를 보여주는 라이브러리를 찾아놨는데, Objective-C로 되어 있는 라이브러리인지라 swift로 옮겨서 사용했다. 앞으로도 계속 swift로 뭔가를 만들 텐데 매 번 설정 바꿔주고 하는게 귀찮을 듯 하여...혹시 필요한 사람이 있을런지 몰라 올려둠. 원본 라이브러리의 라이센스는 BSD-3-Clause. 음. 카피라이트를 명시하고 배포하라는데, swift로 바꾼 경우에는 어떻게 되는거지??? -_-;;; 일단 Objective-C 라이브러리의 카피라이트는 다음과 같음.
원본 Objective-C 라이브러리 사이트 : GitHub_link
Copyright (c) 2011-2017 Mapbox, Inc.
라이센스 문제는 너무나 복잡하므로 문제가 생긴다면 내리는 것으로...아래쪽 3개 swift 파일을 프로젝트에 포함 시킨 뒤, AppDelegate에서 아래와 같이 window를 바꿔 준다. 그러면 이후로 앱 동작 시 터치 포인트가 흰색 동그라미로 표현됨.
1 2 3 4 5 | @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { var window: UIWindow? = FingerTips(frame: UIScreen.main.bounds) | cs |
FingerTipView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import UIKit class FingerTipView: UIImageView { var timestamp:TimeInterval = Date().timeIntervalSince1970 var shouldAutomaticallyRemoveAfterTimeout:Bool = false var fadingOut:Bool = false override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override init(image: UIImage?) { super.init(image: image) } } | cs |
FingerTipOverlayWindow.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import UIKit class FingerTipOverlayWindow: UIWindow { var _rootViewController:UIViewController { for window in UIApplication.shared.windows { if self == window { continue } let realRootViewController = window.rootViewController if realRootViewController != nil { return realRootViewController! } } return super.rootViewController! } } | cs |
FingerTips.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | import UIKit class FingerTips: UIWindow { var _touchImage:UIImage? = nil var touchAlpha:CGFloat = 0.5 var fadeDuration:TimeInterval = 0.3 var strokeColor:UIColor = UIColor.black var fillColor:UIColor = UIColor.white var alwaysShowTouches:Bool = true var _overlayWindow:UIWindow? = nil var active:Bool = false var fingerTipRemovalScheduled:Bool = false required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) myInit() } override init(frame: CGRect) { super.init(frame: frame) myInit() } deinit { NotificationCenter.default.removeObserver(self) } func myInit() { NotificationCenter.default.addObserver(self, selector: #selector(self.screenConnect(notification:)), name: NSNotification.Name.UIScreenDidConnect, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.screenDisConnect(notification:)), name: NSNotification.Name.UIScreenDidDisconnect, object: nil) updateFingertipsAreActive() } func screenConnect(notification:NSNotification) { updateFingertipsAreActive() } func screenDisConnect(notification:NSNotification) { updateFingertipsAreActive() } func anyScreenIsMirrored() -> Bool { if UIScreen.instancesRespond(to:#selector(getter: UIScreen.mirrored)) == false { return false } for screen in UIScreen.screens { if screen.mirrored != nil { return true } } return false } func updateFingertipsAreActive() { if alwaysShowTouches { self.active = true } else { self.active = self.anyScreenIsMirrored() } } func setAlwaysShowTouches(flag:Bool) { if alwaysShowTouches != flag { alwaysShowTouches = flag; updateFingertipsAreActive() } } override func sendEvent(_ event: UIEvent) { if self.active { let allTouches = event.allTouches for touch in allTouches!{ switch (touch.phase) { case UITouchPhase.began, UITouchPhase.moved, UITouchPhase.stationary: var touchView = self.overlayWindow.viewWithTag(touch.hash) as? FingerTipView if (touch.phase != UITouchPhase.stationary && touchView != nil && (touchView?.fadingOut)!) { touchView?.removeFromSuperview() touchView = nil } if (touchView == nil && touch.phase != UITouchPhase.stationary) { touchView = FingerTipView(image: self.touchImage) self.overlayWindow.addSubview(touchView!) } if touchView?.fadingOut == false { touchView?.alpha = self.touchAlpha; touchView?.center = touch.location(in: self.overlayWindow) touchView?.tag = touch.hash; touchView?.timestamp = touch.timestamp; touchView?.shouldAutomaticallyRemoveAfterTimeout = shouldAutomaticallyRemoveFingerTipForTouch(touch: touch) } break case UITouchPhase.ended, UITouchPhase.cancelled: removeFingerTipWithHash(hash: touch.hash, animated: true) break } } } super.sendEvent(event) scheduleFingerTipRemoval() } func scheduleFingerTipRemoval() { if self.fingerTipRemovalScheduled { return } self.fingerTipRemovalScheduled = true self.perform( #selector(self.removeInactiveFingerTips), with: nil, afterDelay: 0.1) } func cancelScheduledFingerTipRemoval() { self.fingerTipRemovalScheduled = true NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.removeInactiveFingerTips), object: nil) } func removeInactiveFingerTips() { self.fingerTipRemovalScheduled = false let now = ProcessInfo().systemUptime let REMOVAL_DELAY = 0.2 for touchView in self.overlayWindow.subviews { if touchView.isKind(of: FingerTipView.self) == false{ continue } let thisView = touchView as! FingerTipView if thisView.shouldAutomaticallyRemoveAfterTimeout && now > (thisView.timestamp + REMOVAL_DELAY) { removeFingerTipWithHash(hash: thisView.tag, animated: true) } } if self.overlayWindow.subviews.count > 0 { scheduleFingerTipRemoval() } } func removeFingerTipWithHash(hash:NSInteger, animated:Bool) { let touchView = self.overlayWindow.viewWithTag(hash) if touchView == nil || touchView?.isKind(of: FingerTipView.self) == false { return } let thisView = touchView as! FingerTipView if thisView.fadingOut { return } let animationsWereEnabled = UIView.areAnimationsEnabled if animated { UIView.setAnimationsEnabled(true) UIView.beginAnimations(nil, context: nil) UIView.setAnimationDuration(self.fadeDuration) } thisView.frame = CGRect(x: thisView.center.x - thisView.frame.size.width, y: thisView.center.y - thisView.frame.size.height, width: thisView.frame.size.width * 2, height: thisView.frame.size.height * 2) thisView.alpha = 0.0 if animated { UIView.commitAnimations() UIView.setAnimationsEnabled(animationsWereEnabled) } thisView.fadingOut = true thisView.perform(#selector(self.removeFromSuperview), with: nil, afterDelay: self.fadeDuration) } func shouldAutomaticallyRemoveFingerTipForTouch(touch:UITouch) -> Bool { var view = touch.view view = view?.hitTest(touch.location(in: view), with: nil) while (view != nil) { if (view?.isKind(of: UITableViewCell.self))! { for recognizer in touch.gestureRecognizers! { if recognizer.isKind(of: UISwipeGestureRecognizer.self) { return true } } } if (view?.isKind(of: UITableView.self))! { if touch.gestureRecognizers?.count == 0{ return true } } view = view?.superview } return false } var overlayWindow:UIWindow { if _overlayWindow != nil { return _overlayWindow! } _overlayWindow = FingerTipOverlayWindow(frame: self.frame) _overlayWindow?.rootViewController = (_overlayWindow as! FingerTipOverlayWindow)._rootViewController _overlayWindow?.isUserInteractionEnabled = false _overlayWindow?.windowLevel = UIWindowLevelStatusBar _overlayWindow?.backgroundColor = UIColor.clear _overlayWindow?.isHidden = false return _overlayWindow! } var touchImage:UIImage { if _touchImage != nil { return _touchImage! } let clipPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50)) UIGraphicsBeginImageContextWithOptions(clipPath.bounds.size, false, 0) let drawPath = UIBezierPath(arcCenter: CGPoint(x: 25, y: 25), radius: 22.0, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true) drawPath.lineWidth = 2.0; strokeColor.setStroke() fillColor.setFill() drawPath.stroke() drawPath.fill() clipPath.addClip() _touchImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return _touchImage! } } | cs |
리뷰... 빨리 통과 되기를... 비나이다 비나이다
'관계, Networking 그리고 Programming' 카테고리의 다른 글
Big Sur에서 svnX 사용하기 (0) | 2021.06.17 |
---|---|
나는 현재 몹시 화가 나쒀 (0) | 2020.09.17 |
iPhone X 변경 사항 체크 - UI (0) | 2017.09.26 |
다시 살펴보는 매니페스트 속성들 (0) | 2015.10.22 |
Calendar millitime에 대한 나의 편견(?) (0) | 2015.03.31 |