├── .gitignore ├── Classes └── XXPlaceHolder.swift ├── LICENSE ├── README.md ├── XXPlaceHolder.podspec ├── XXPlaceHolder ├── XXPlaceHolder.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── XXPlaceHolder │ ├── 1.jpeg │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── ViewController.swift │ └── XXViewController.swift └── demo.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /Classes/XXPlaceHolder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XXPlaceHolder.swift 3 | // XXPlaceHolder 4 | // 5 | // Created by Ralph Li on 10/19/15. 6 | // Copyright © 2015 LJC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - XXPlaceHolderConfig 12 | 13 | public struct XXPlaceHolderConfig { 14 | 15 | public var backColor: UIColor = UIColor.clearColor() 16 | public var arrowSize: CGFloat = 3 17 | public var lineColor: UIColor = UIColor.whiteColor() 18 | public var lineWidth: CGFloat = 1 19 | public var frameColor: UIColor = UIColor.redColor() 20 | public var frameWidth: CGFloat = 0 21 | 22 | public var showArrow: Bool = true 23 | public var showText: Bool = true 24 | 25 | public var visible: Bool = true 26 | public var autoDisplay: Bool = false 27 | public var autoDisplaySystemView: Bool = false 28 | 29 | public var visibleMemberOfClasses: [AnyClass] = [AnyClass]() 30 | public var visibleKindOfClasses: [AnyClass] = [AnyClass]() 31 | 32 | private let defaultMemberOfClasses: [AnyClass] = [ 33 | UIImageView.self, 34 | UIButton.self, 35 | UILabel.self, 36 | UITextField.self, 37 | UITextView.self, 38 | UISwitch.self, 39 | UISlider.self, 40 | UIPageControl.self 41 | ]; 42 | } 43 | 44 | // MARK: - XXPlaceHolder 45 | 46 | public class XXPlaceHolder: UIView { 47 | 48 | public static var config: XXPlaceHolderConfig = XXPlaceHolderConfig() 49 | 50 | public var backColor: UIColor = XXPlaceHolder.config.backColor {didSet{self.setNeedsDisplay()}} 51 | public var arrowSize: CGFloat = XXPlaceHolder.config.arrowSize {didSet{self.setNeedsDisplay()}} 52 | public var lineColor: UIColor = XXPlaceHolder.config.lineColor {didSet{self.setNeedsDisplay()}} 53 | public var lineWidth: CGFloat = XXPlaceHolder.config.lineWidth {didSet{self.setNeedsDisplay()}} 54 | public var frameColor: UIColor = XXPlaceHolder.config.frameColor {didSet{self.setNeedsDisplay()}} 55 | public var frameWidth: CGFloat = XXPlaceHolder.config.frameWidth {didSet{self.setNeedsDisplay()}} 56 | 57 | public var showArrow: Bool = XXPlaceHolder.config.showArrow {didSet{self.setNeedsDisplay()}} 58 | public var showText: Bool = XXPlaceHolder.config.showText {didSet{self.setNeedsDisplay()}} 59 | 60 | override init(frame: CGRect) { 61 | super.init(frame: frame) 62 | 63 | self.setup() 64 | } 65 | 66 | required public init?(coder aDecoder: NSCoder) { 67 | super.init(coder: aDecoder) 68 | 69 | self.setup() 70 | } 71 | 72 | private func setup() { 73 | self.opaque = false 74 | self.contentMode = .Redraw 75 | self.backgroundColor = UIColor.clearColor() 76 | self.userInteractionEnabled = false 77 | self.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] 78 | } 79 | 80 | override public func drawRect(rect: CGRect) { 81 | 82 | let width = rect.size.width 83 | let height = rect.size.height 84 | 85 | let fontSize = 4 + min(width, height) / 20 86 | let arrowSize = CGFloat(self.arrowSize) 87 | let lineWidth = CGFloat(self.lineWidth) 88 | 89 | let font = UIFont.systemFontOfSize(fontSize) 90 | 91 | // fill the back 92 | let ctx = UIGraphicsGetCurrentContext() 93 | CGContextSetFillColorWithColor(ctx, self.backColor.CGColor); 94 | CGContextSetLineJoin(ctx, .Miter) 95 | CGContextSetLineCap(ctx, .Round) 96 | 97 | CGContextFillRect(ctx, rect); 98 | 99 | 100 | // strike frame 101 | if ( self.frameWidth > 0 ) { 102 | 103 | let radius = self.frameWidth/2; 104 | 105 | CGContextSetLineWidth(ctx, self.frameWidth); 106 | CGContextSetStrokeColorWithColor(ctx, self.frameColor.CGColor) 107 | 108 | CGContextMoveToPoint(ctx, radius, radius) 109 | CGContextAddLineToPoint(ctx, radius, height - radius) 110 | CGContextAddLineToPoint(ctx, width - radius, height - radius) 111 | CGContextAddLineToPoint(ctx, width - radius, radius) 112 | CGContextAddLineToPoint(ctx, radius, radius) 113 | CGContextClosePath(ctx) 114 | 115 | CGContextStrokePath(ctx) 116 | } 117 | 118 | // strike lines & arrows 119 | if ( self.showArrow ) { 120 | 121 | let radius = self.frameWidth/2*3 122 | 123 | CGContextSetLineWidth(ctx, lineWidth) 124 | CGContextSetStrokeColorWithColor(ctx, self.lineColor.CGColor) 125 | 126 | CGContextMoveToPoint(ctx, width/2, radius) 127 | CGContextAddLineToPoint(ctx, width/2, height-radius) 128 | CGContextMoveToPoint(ctx, width/2, radius) 129 | CGContextAddLineToPoint(ctx, width/2 - arrowSize, arrowSize + radius) 130 | CGContextMoveToPoint(ctx, width/2, radius) 131 | CGContextAddLineToPoint(ctx, width/2 + arrowSize, arrowSize + radius) 132 | CGContextMoveToPoint(ctx, width/2, height-radius) 133 | CGContextAddLineToPoint(ctx, width/2 - arrowSize, height - arrowSize - radius) 134 | CGContextMoveToPoint(ctx, width/2, height-radius) 135 | CGContextAddLineToPoint(ctx, width/2 + arrowSize, height - arrowSize - radius) 136 | 137 | CGContextMoveToPoint(ctx, radius, height/2) 138 | CGContextAddLineToPoint(ctx, width - radius, height/2) 139 | CGContextMoveToPoint(ctx, radius, height/2) 140 | CGContextAddLineToPoint(ctx, arrowSize + radius, height/2 - arrowSize) 141 | CGContextMoveToPoint(ctx, radius, height/2) 142 | CGContextAddLineToPoint(ctx, arrowSize + radius, height/2 + arrowSize) 143 | CGContextMoveToPoint(ctx, width - radius, height/2) 144 | CGContextAddLineToPoint(ctx, width - arrowSize - radius, height/2 - arrowSize) 145 | CGContextMoveToPoint(ctx, width - radius, height/2) 146 | CGContextAddLineToPoint(ctx, width - arrowSize - radius, height/2 + arrowSize) 147 | 148 | CGContextStrokePath(ctx); 149 | } 150 | 151 | // strike lines & arrows 152 | if ( self.showText && width >= 50 ) { 153 | // calculate the text area 154 | let text:NSString = "\(width) x \(height)" as NSString 155 | 156 | let textFontAttributes = [ 157 | NSFontAttributeName: font, 158 | NSForegroundColorAttributeName: self.lineColor 159 | ] 160 | let textSize = text.boundingRectWithSize(CGSizeMake(CGFloat.max, CGFloat.max), options: .UsesFontLeading, attributes: textFontAttributes, context: nil).size 161 | 162 | let rectWidth = ceil(textSize.width + 4.0) 163 | let rectHeight = ceil(textSize.height + 4.0) 164 | 165 | // clear the area behind the textz 166 | let strRect = CGRectMake(width/2 - rectWidth/2, height/2 - rectHeight/2, rectWidth, rectHeight) 167 | CGContextClearRect(ctx, strRect); 168 | CGContextSetLineWidth(ctx, 0); 169 | CGContextSetFillColorWithColor(ctx, self.backColor.CGColor); 170 | CGContextFillRect(ctx, strRect); 171 | 172 | // draw text 173 | CGContextSetFillColorWithColor(ctx, self.lineColor.CGColor); 174 | text.drawInRect(strRect, withAttributes: textFontAttributes) 175 | } 176 | 177 | } 178 | } 179 | 180 | // MARK: - UIView extension 181 | 182 | public extension UIView 183 | { 184 | public override class func initialize() { 185 | struct Static { 186 | static var token: dispatch_once_t = 0 187 | } 188 | 189 | if ( self == XXPlaceHolder.self ) { 190 | return; 191 | } 192 | 193 | func swizzleSelector(originalSelector:Selector, swizzledSelector:Selector) { 194 | let originalMethod = class_getInstanceMethod(self, originalSelector) 195 | let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) 196 | 197 | let didAddMethod = class_addMethod( 198 | self, 199 | originalSelector, 200 | method_getImplementation(swizzledMethod), 201 | method_getTypeEncoding(swizzledMethod)) 202 | 203 | if didAddMethod { 204 | class_replaceMethod( 205 | self, 206 | swizzledSelector, 207 | method_getImplementation(originalMethod), 208 | method_getTypeEncoding(originalMethod)) 209 | } else { 210 | method_exchangeImplementations(originalMethod, swizzledMethod); 211 | } 212 | } 213 | 214 | dispatch_once(&Static.token) { 215 | swizzleSelector(Selector("didMoveToSuperview"), swizzledSelector: Selector("xx_didMoveToSuperview")) 216 | } 217 | } 218 | 219 | private func xx_didMoveToSuperview() -> UIView { 220 | self.xx_didMoveToSuperview() 221 | 222 | self.checkAutoDisplay() 223 | 224 | return self 225 | } 226 | 227 | private func checkAutoDisplay() { 228 | let config = XXPlaceHolder.config 229 | 230 | if self.isKindOfClass(XXPlaceHolder.self) { 231 | return 232 | } 233 | 234 | if config.autoDisplay { 235 | 236 | if ( NSBundle(forClass: UIView.self).bundlePath == NSBundle(forClass: self.dynamicType).bundlePath ) { 237 | 238 | if ( !config.autoDisplaySystemView ) { 239 | var inWhiteList = false 240 | for cls: AnyClass in config.defaultMemberOfClasses { 241 | if self.isMemberOfClass(cls) { 242 | inWhiteList = true 243 | break; 244 | } 245 | } 246 | 247 | if ( !inWhiteList ) { 248 | return 249 | } 250 | } 251 | } 252 | 253 | if ( config.visibleMemberOfClasses.count > 0 ) { 254 | for cls: AnyClass in config.visibleMemberOfClasses { 255 | if self.isMemberOfClass(cls) { 256 | self.showPlaceHolder() 257 | return 258 | } 259 | } 260 | } 261 | else if ( config.visibleKindOfClasses.count > 0 ) { 262 | for cls: AnyClass in config.visibleKindOfClasses { 263 | if self.isKindOfClass(cls) { 264 | self.showPlaceHolder() 265 | return 266 | } 267 | } 268 | } 269 | else { 270 | self.showPlaceHolder() 271 | } 272 | } 273 | } 274 | 275 | public func getPlaceHolder() -> XXPlaceHolder? { 276 | return self.viewWithTag(XXPlaceHolder.self.hash() + self.hashValue) as? XXPlaceHolder 277 | } 278 | 279 | public func showPlaceHolder() { 280 | self.showPlaceHolderWith(XXPlaceHolder.config.lineColor) 281 | } 282 | 283 | public func showPlaceHolderWith(lineColor: UIColor) { 284 | self.showPlaceHolderWith(lineColor, backColor: XXPlaceHolder.config.backColor) 285 | } 286 | 287 | public func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor) { 288 | let config = XXPlaceHolder.config 289 | self.showPlaceHolderWith(lineColor, backColor: backColor, arrowSize: config.arrowSize) 290 | } 291 | 292 | public func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat) { 293 | self.showPlaceHolderWith( 294 | lineColor, 295 | backColor: backColor, 296 | arrowSize: arrowSize, 297 | lineWidth: XXPlaceHolder.config.lineWidth) 298 | } 299 | 300 | public func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat, lineWidth: CGFloat) { 301 | self.showPlaceHolderWith( 302 | lineColor, 303 | backColor: backColor, 304 | arrowSize: arrowSize, 305 | lineWidth: lineWidth, 306 | frameWidth: XXPlaceHolder.config.frameWidth, 307 | frameColor: XXPlaceHolder.config.frameColor) 308 | } 309 | 310 | public func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat, lineWidth: CGFloat, frameWidth: CGFloat, frameColor: UIColor) { 311 | #if RELEASE 312 | // do nothing 313 | #else 314 | 315 | var placeholder:XXPlaceHolder? = self.getPlaceHolder() 316 | 317 | if ( placeholder == nil) { 318 | let ph = XXPlaceHolder.init(frame: self.bounds) 319 | self.addSubview(ph) 320 | ph.tag = XXPlaceHolder.self.hash() + self.hashValue 321 | 322 | placeholder = ph 323 | } 324 | 325 | let ph = placeholder as XXPlaceHolder! 326 | 327 | ph.lineColor = lineColor 328 | ph.backColor = backColor 329 | ph.arrowSize = arrowSize 330 | ph.lineWidth = lineWidth 331 | ph.frameColor = frameColor 332 | ph.frameWidth = frameWidth 333 | ph.hidden = !XXPlaceHolder.config.visible 334 | 335 | #endif 336 | } 337 | 338 | public func showPlaceHolderWithAllSubviews() { 339 | print("showPlaceholderWithAllSubviews") 340 | self.showPlaceHolderWithAllSubviewsWith(UInt.max) 341 | } 342 | 343 | public func showPlaceHolderWithAllSubviewsWith(maxPath: UInt) { 344 | if ( maxPath > 0 ) { 345 | for v: UIView in self.subviews { 346 | v.showPlaceHolderWithAllSubviewsWith(maxPath - 1) 347 | } 348 | } 349 | self.showPlaceHolder() 350 | } 351 | 352 | public func hidePlaceHolder() { 353 | if let placeholder = self.getPlaceHolder() { 354 | placeholder.hidden = true 355 | } 356 | } 357 | 358 | public func hidePlaceHolderWithAllSubviews() { 359 | for v: UIView in self.subviews { 360 | v.hidePlaceHolderWithAllSubviews() 361 | } 362 | self.hidePlaceHolder() 363 | } 364 | 365 | public func removePlaceHolder() { 366 | if let placeholder = self.getPlaceHolder() { 367 | placeholder.removeFromSuperview() 368 | } 369 | } 370 | 371 | public func removePlaceHolderWithAllSubviews() { 372 | for v: UIView in self.subviews { 373 | v.removePlaceHolderWithAllSubviews() 374 | } 375 | self.removePlaceHolder() 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ralph li 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | XXPlaceHolder 2 | ============= 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/XXPlaceHolder.svg)]() 4 | [![CocoaPods](https://img.shields.io/cocoapods/p/XXPlaceHolder.svg)]() 5 | [![CocoaPods](https://img.shields.io/cocoapods/l/XXPlaceHolder.svg)]() 6 | 7 | A drop in solution to set a placeholder or show UIView's size, A Swift version of [MMPlaceHolder](https://github.com/adad184/MMPlaceHolder) 8 | 9 | ![demo](https://raw.githubusercontent.com/adad184/XXPlaceHolder/master/demo.png) 10 | 11 | Installation 12 | ============ 13 | 14 | The preferred way of installation is via [CocoaPods](http://cocoapods.org). Just add 15 | 16 | ```ruby 17 | pod 'XXPlaceHolder' 18 | ``` 19 | 20 | and run `pod install`. It will install the most recent version of MMPlaceHolder. 21 | 22 | If you would like to use the latest code of MMPlaceHolder use: 23 | 24 | ```ruby 25 | pod 'XXPlaceHolder', :head 26 | ``` 27 | 28 | Usage 29 | =============== 30 | 31 | simply, you only need one line code. 32 | 33 | ```swift 34 | yourView.showPlaceHolder() 35 | ``` 36 | 37 | 38 | or you can customize youself. 39 | 40 | ```swift 41 | func showPlaceHolder() 42 | func showPlaceHolderWith(lineColor: UIColor) 43 | func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor) 44 | func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat) 45 | func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat, lineWidth: CGFloat) 46 | func showPlaceHolderWith(lineColor: UIColor, backColor: UIColor, arrowSize: CGFloat, lineWidth: CGFloat, frameWidth: CGFloat, frameColor: UIColor) 47 | 48 | func showPlaceHolderWithAllSubviews() 49 | func showPlaceHolderWithAllSubviewsWith(maxPath: UInt) 50 | 51 | 52 | func hidePlaceHolder() 53 | func hidePlaceHolderWithAllSubviews() 54 | func removePlaceHolder() 55 | func removePlaceHolderWithAllSubviews() 56 | 57 | func getPlaceHolder() -> XXPlaceHolder? 58 | ``` 59 | 60 | 61 | and you can use the global configuration 62 | 63 | ```swift 64 | struct XXPlaceHolderConfig { 65 | 66 | var backColor: UIColor 67 | var arrowSize: CGFloat 68 | var lineColor: UIColor 69 | var lineWidth: CGFloat 70 | var frameColor: UIColor 71 | var frameWidth: CGFloat 72 | 73 | var showArrow: Bool 74 | var showText: Bool 75 | 76 | var visible: Bool 77 | var autoDisplay: Bool 78 | var autoDisplaySystemView: Bool 79 | 80 | var visibleMemberOfClasses: [AnyClass] = [AnyClass]() 81 | var visibleKindOfClasses: [AnyClass] = [AnyClass]() 82 | } 83 | ``` 84 | 85 | 86 | Changelog 87 | =============== 88 | 89 | 1.1 Fix Access Control under using framework 90 | 91 | 1.0 Migrate code from Objective-C into Swift, fully compatible with MMPlaceHolder 92 | 93 | 94 | -------------------------------------------------------------------------------- /XXPlaceHolder.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | # 1 4 | s.platform = :ios 5 | s.ios.deployment_target = '8.0' 6 | s.name = "XXPlaceHolder" 7 | s.summary = "A drop in solution to show UIView's size. Only one line code to use it. Swift version of MMPlaceHolder" 8 | s.requires_arc = true 9 | 10 | # 2 11 | s.version = "1.1" 12 | 13 | # 3 14 | s.license = { :type => "MIT", :file => "LICENSE" } 15 | 16 | # 4 - Replace with your name and e-mail address 17 | s.author = { "adad184" => "adad184@gmail.com" } 18 | 19 | # 5 - Replace this URL with your own Github page's URL (from the address bar) 20 | s.homepage = "https://github.com/adad184/XXPlaceHolder" 21 | 22 | # 6 - Replace this URL with your own Git URL from "Quick Setup" 23 | s.source = { :git => "https://github.com/adad184/XXPlaceHolder.git", :tag => "1.1"} 24 | 25 | # 7 26 | s.framework = "UIKit" 27 | 28 | # 8 29 | s.source_files = "Classes/*.{swift}" 30 | 31 | # 9 32 | # s.resources = "RWPickFlavor/**/*.{png,jpeg,jpg,storyboard,xib}" 33 | end 34 | 35 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | ED28B2891BD487C500AED1CF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED28B2881BD487C500AED1CF /* AppDelegate.swift */; }; 11 | ED28B28B1BD487C500AED1CF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED28B28A1BD487C500AED1CF /* ViewController.swift */; }; 12 | ED28B2901BD487C500AED1CF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ED28B28F1BD487C500AED1CF /* Assets.xcassets */; }; 13 | ED28B2931BD487C500AED1CF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED28B2911BD487C500AED1CF /* LaunchScreen.storyboard */; }; 14 | ED28B29B1BD4891200AED1CF /* XXViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED28B29A1BD4891200AED1CF /* XXViewController.swift */; settings = {ASSET_TAGS = (); }; }; 15 | ED28B2A21BD4E7AE00AED1CF /* 1.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = ED28B2A11BD4E7AE00AED1CF /* 1.jpeg */; settings = {ASSET_TAGS = (); }; }; 16 | ED28B2A61BD4F0C500AED1CF /* XXPlaceHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED28B2A51BD4F0C500AED1CF /* XXPlaceHolder.swift */; settings = {ASSET_TAGS = (); }; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | ED28B2851BD487C500AED1CF /* XXPlaceHolder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XXPlaceHolder.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | ED28B2881BD487C500AED1CF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | ED28B28A1BD487C500AED1CF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 23 | ED28B28F1BD487C500AED1CF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | ED28B2921BD487C500AED1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | ED28B2941BD487C500AED1CF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | ED28B29A1BD4891200AED1CF /* XXViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XXViewController.swift; sourceTree = ""; }; 27 | ED28B2A11BD4E7AE00AED1CF /* 1.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 1.jpeg; sourceTree = ""; }; 28 | ED28B2A51BD4F0C500AED1CF /* XXPlaceHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = XXPlaceHolder.swift; path = ../Classes/XXPlaceHolder.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | ED28B2821BD487C500AED1CF /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | ED28B27C1BD487C500AED1CF = { 43 | isa = PBXGroup; 44 | children = ( 45 | ED28B29E1BD4893E00AED1CF /* Classes */, 46 | ED28B2871BD487C500AED1CF /* XXPlaceHolder */, 47 | ED28B2861BD487C500AED1CF /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | ED28B2861BD487C500AED1CF /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | ED28B2851BD487C500AED1CF /* XXPlaceHolder.app */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | ED28B2871BD487C500AED1CF /* XXPlaceHolder */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | ED28B2881BD487C500AED1CF /* AppDelegate.swift */, 63 | ED28B28A1BD487C500AED1CF /* ViewController.swift */, 64 | ED28B28F1BD487C500AED1CF /* Assets.xcassets */, 65 | ED28B2911BD487C500AED1CF /* LaunchScreen.storyboard */, 66 | ED28B2941BD487C500AED1CF /* Info.plist */, 67 | ED28B29A1BD4891200AED1CF /* XXViewController.swift */, 68 | ED28B2A11BD4E7AE00AED1CF /* 1.jpeg */, 69 | ); 70 | path = XXPlaceHolder; 71 | sourceTree = ""; 72 | }; 73 | ED28B29E1BD4893E00AED1CF /* Classes */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | ED28B2A51BD4F0C500AED1CF /* XXPlaceHolder.swift */, 77 | ); 78 | name = Classes; 79 | sourceTree = ""; 80 | }; 81 | /* End PBXGroup section */ 82 | 83 | /* Begin PBXNativeTarget section */ 84 | ED28B2841BD487C500AED1CF /* XXPlaceHolder */ = { 85 | isa = PBXNativeTarget; 86 | buildConfigurationList = ED28B2971BD487C500AED1CF /* Build configuration list for PBXNativeTarget "XXPlaceHolder" */; 87 | buildPhases = ( 88 | ED28B2811BD487C500AED1CF /* Sources */, 89 | ED28B2821BD487C500AED1CF /* Frameworks */, 90 | ED28B2831BD487C500AED1CF /* Resources */, 91 | ); 92 | buildRules = ( 93 | ); 94 | dependencies = ( 95 | ); 96 | name = XXPlaceHolder; 97 | productName = XXPlaceHolder; 98 | productReference = ED28B2851BD487C500AED1CF /* XXPlaceHolder.app */; 99 | productType = "com.apple.product-type.application"; 100 | }; 101 | /* End PBXNativeTarget section */ 102 | 103 | /* Begin PBXProject section */ 104 | ED28B27D1BD487C500AED1CF /* Project object */ = { 105 | isa = PBXProject; 106 | attributes = { 107 | LastUpgradeCheck = 0700; 108 | ORGANIZATIONNAME = LJC; 109 | TargetAttributes = { 110 | ED28B2841BD487C500AED1CF = { 111 | CreatedOnToolsVersion = 7.0.1; 112 | DevelopmentTeam = GTLNQ9B2G7; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = ED28B2801BD487C500AED1CF /* Build configuration list for PBXProject "XXPlaceHolder" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = ED28B27C1BD487C500AED1CF; 125 | productRefGroup = ED28B2861BD487C500AED1CF /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | ED28B2841BD487C500AED1CF /* XXPlaceHolder */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | ED28B2831BD487C500AED1CF /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | ED28B2931BD487C500AED1CF /* LaunchScreen.storyboard in Resources */, 140 | ED28B2A21BD4E7AE00AED1CF /* 1.jpeg in Resources */, 141 | ED28B2901BD487C500AED1CF /* Assets.xcassets in Resources */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXResourcesBuildPhase section */ 146 | 147 | /* Begin PBXSourcesBuildPhase section */ 148 | ED28B2811BD487C500AED1CF /* Sources */ = { 149 | isa = PBXSourcesBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | ED28B29B1BD4891200AED1CF /* XXViewController.swift in Sources */, 153 | ED28B2A61BD4F0C500AED1CF /* XXPlaceHolder.swift in Sources */, 154 | ED28B28B1BD487C500AED1CF /* ViewController.swift in Sources */, 155 | ED28B2891BD487C500AED1CF /* AppDelegate.swift in Sources */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXSourcesBuildPhase section */ 160 | 161 | /* Begin PBXVariantGroup section */ 162 | ED28B2911BD487C500AED1CF /* LaunchScreen.storyboard */ = { 163 | isa = PBXVariantGroup; 164 | children = ( 165 | ED28B2921BD487C500AED1CF /* Base */, 166 | ); 167 | name = LaunchScreen.storyboard; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXVariantGroup section */ 171 | 172 | /* Begin XCBuildConfiguration section */ 173 | ED28B2951BD487C500AED1CF /* Debug */ = { 174 | isa = XCBuildConfiguration; 175 | buildSettings = { 176 | ALWAYS_SEARCH_USER_PATHS = NO; 177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 178 | CLANG_CXX_LIBRARY = "libc++"; 179 | CLANG_ENABLE_MODULES = YES; 180 | CLANG_ENABLE_OBJC_ARC = YES; 181 | CLANG_WARN_BOOL_CONVERSION = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 184 | CLANG_WARN_EMPTY_BODY = YES; 185 | CLANG_WARN_ENUM_CONVERSION = YES; 186 | CLANG_WARN_INT_CONVERSION = YES; 187 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 188 | CLANG_WARN_UNREACHABLE_CODE = YES; 189 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 190 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 191 | COPY_PHASE_STRIP = NO; 192 | DEBUG_INFORMATION_FORMAT = dwarf; 193 | ENABLE_STRICT_OBJC_MSGSEND = YES; 194 | ENABLE_TESTABILITY = YES; 195 | GCC_C_LANGUAGE_STANDARD = gnu99; 196 | GCC_DYNAMIC_NO_PIC = NO; 197 | GCC_NO_COMMON_BLOCKS = YES; 198 | GCC_OPTIMIZATION_LEVEL = 0; 199 | GCC_PREPROCESSOR_DEFINITIONS = ( 200 | "DEBUG=1", 201 | "$(inherited)", 202 | ); 203 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 204 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 205 | GCC_WARN_UNDECLARED_SELECTOR = YES; 206 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 207 | GCC_WARN_UNUSED_FUNCTION = YES; 208 | GCC_WARN_UNUSED_VARIABLE = YES; 209 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 210 | MTL_ENABLE_DEBUG_INFO = YES; 211 | ONLY_ACTIVE_ARCH = YES; 212 | SDKROOT = iphoneos; 213 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 214 | TARGETED_DEVICE_FAMILY = "1,2"; 215 | }; 216 | name = Debug; 217 | }; 218 | ED28B2961BD487C500AED1CF /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BOOL_CONVERSION = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 236 | COPY_PHASE_STRIP = NO; 237 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 238 | ENABLE_NS_ASSERTIONS = NO; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | GCC_C_LANGUAGE_STANDARD = gnu99; 241 | GCC_NO_COMMON_BLOCKS = YES; 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 249 | MTL_ENABLE_DEBUG_INFO = NO; 250 | SDKROOT = iphoneos; 251 | TARGETED_DEVICE_FAMILY = "1,2"; 252 | VALIDATE_PRODUCT = YES; 253 | }; 254 | name = Release; 255 | }; 256 | ED28B2981BD487C500AED1CF /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 260 | CODE_SIGN_IDENTITY = "iPhone Developer"; 261 | INFOPLIST_FILE = XXPlaceHolder/Info.plist; 262 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 263 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 264 | PRODUCT_BUNDLE_IDENTIFIER = com.adad184.XXPlaceHolder; 265 | PRODUCT_NAME = "$(TARGET_NAME)"; 266 | }; 267 | name = Debug; 268 | }; 269 | ED28B2991BD487C500AED1CF /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 273 | CODE_SIGN_IDENTITY = "iPhone Developer"; 274 | INFOPLIST_FILE = XXPlaceHolder/Info.plist; 275 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 276 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 277 | PRODUCT_BUNDLE_IDENTIFIER = com.adad184.XXPlaceHolder; 278 | PRODUCT_NAME = "$(TARGET_NAME)"; 279 | }; 280 | name = Release; 281 | }; 282 | /* End XCBuildConfiguration section */ 283 | 284 | /* Begin XCConfigurationList section */ 285 | ED28B2801BD487C500AED1CF /* Build configuration list for PBXProject "XXPlaceHolder" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | ED28B2951BD487C500AED1CF /* Debug */, 289 | ED28B2961BD487C500AED1CF /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | ED28B2971BD487C500AED1CF /* Build configuration list for PBXNativeTarget "XXPlaceHolder" */ = { 295 | isa = XCConfigurationList; 296 | buildConfigurations = ( 297 | ED28B2981BD487C500AED1CF /* Debug */, 298 | ED28B2991BD487C500AED1CF /* Release */, 299 | ); 300 | defaultConfigurationIsVisible = 0; 301 | defaultConfigurationName = Release; 302 | }; 303 | /* End XCConfigurationList section */ 304 | }; 305 | rootObject = ED28B27D1BD487C500AED1CF /* Project object */; 306 | } 307 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adad184/XXPlaceHolder/a74c8b927f76951e48c939e9ef82d709ce7398ac/XXPlaceHolder/XXPlaceHolder/1.jpeg -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // XXPlaceHolder 4 | // 5 | // Created by Ralph Li on 10/19/15. 6 | // Copyright © 2015 LJC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | 20 | XXPlaceHolder.config.lineColor = UIColor.blackColor(); 21 | XXPlaceHolder.config.lineWidth = 1; 22 | XXPlaceHolder.config.arrowSize = 5; 23 | XXPlaceHolder.config.backColor = UIColor.clearColor(); 24 | XXPlaceHolder.config.frameWidth = 0; 25 | XXPlaceHolder.config.visibleKindOfClasses = [UIImageView.self] 26 | XXPlaceHolder.config.autoDisplay = true 27 | 28 | let v1 = XXViewController() 29 | let v2 = UIViewController() 30 | let v3 = UIViewController() 31 | let v4 = UIViewController() 32 | 33 | v1.tabBarItem = UITabBarItem.init(tabBarSystemItem: .Featured, tag: 0) 34 | v2.tabBarItem = UITabBarItem.init(tabBarSystemItem: .Search, tag: 0) 35 | v3.tabBarItem = UITabBarItem.init(tabBarSystemItem: .Contacts, tag: 0) 36 | v4.tabBarItem = UITabBarItem.init(tabBarSystemItem: .History, tag: 0) 37 | 38 | v1.navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: UIButton.init(type: .InfoDark)) 39 | v1.navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: UIButton.init(type: .ContactAdd)) 40 | 41 | v1.title = "XXPlaceHolder"; 42 | 43 | let tab = UITabBarController.init() 44 | tab.setViewControllers([ 45 | UINavigationController.init(rootViewController: v1), 46 | UINavigationController.init(rootViewController: v2), 47 | UINavigationController.init(rootViewController: v3), 48 | UINavigationController.init(rootViewController: v4)], 49 | animated: false) 50 | 51 | self.window = UIWindow.init(frame: UIScreen.mainScreen().bounds) 52 | self.window?.backgroundColor = UIColor.whiteColor() 53 | self.window?.rootViewController = tab; 54 | self.window?.makeKeyAndVisible() 55 | 56 | 57 | return true 58 | } 59 | 60 | func applicationWillResignActive(application: UIApplication) { 61 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 62 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 63 | } 64 | 65 | func applicationDidEnterBackground(application: UIApplication) { 66 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 67 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 68 | } 69 | 70 | func applicationWillEnterForeground(application: UIApplication) { 71 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 72 | } 73 | 74 | func applicationDidBecomeActive(application: UIApplication) { 75 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 76 | } 77 | 78 | func applicationWillTerminate(application: UIApplication) { 79 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 80 | } 81 | 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // XXPlaceHolder 4 | // 5 | // Created by Ralph Li on 10/19/15. 6 | // Copyright © 2015 LJC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /XXPlaceHolder/XXPlaceHolder/XXViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XXViewController.swift 3 | // XXPlaceHolder 4 | // 5 | // Created by Ralph Li on 10/19/15. 6 | // Copyright © 2015 LJC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class XXViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | 18 | let iv1 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 19 | let iv2 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 20 | let iv3 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 21 | let iv4 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 22 | let iv5 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 23 | let iv6 = UIImageView.init(image: UIImage.init(named: "1.jpeg")) 24 | 25 | self.view.addSubview(iv1) 26 | self.view.addSubview(iv2) 27 | self.view.addSubview(iv3) 28 | self.view.addSubview(iv4) 29 | self.view.addSubview(iv5) 30 | self.view.addSubview(iv6) 31 | 32 | iv2.showPlaceHolder() 33 | iv3.showPlaceHolderWith(UIColor.greenColor()) 34 | iv4.showPlaceHolderWith(UIColor.yellowColor(), backColor: UIColor.init(red: 0.1, green: 0.1, blue: 0.1, alpha: 0.5)) 35 | iv5.showPlaceHolderWith(UIColor.whiteColor(), backColor: UIColor.init(red: 1.0, green: 0.5, blue: 0, alpha: 0.8), arrowSize: 12) 36 | iv6.showPlaceHolderWith(UIColor.whiteColor(), backColor: UIColor.blackColor(), arrowSize: 25, lineWidth: 3, frameWidth: 5, frameColor: UIColor.redColor()) 37 | 38 | let imgSize = CGSizeMake(130, 130) 39 | let windowWidth = UIScreen.mainScreen().bounds.width 40 | let padding = imgSize.height+20; 41 | 42 | iv1.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 43 | iv2.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 44 | iv3.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 45 | iv4.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 46 | iv5.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 47 | iv6.frame = CGRectMake(0,0, imgSize.width, imgSize.height) 48 | 49 | iv1.center = CGPointMake(windowWidth*0.25, 64+padding*0.5) 50 | iv2.center = CGPointMake(windowWidth*0.75, 64+padding*0.5) 51 | iv3.center = CGPointMake(windowWidth*0.25, 64+padding*1.5) 52 | iv4.center = CGPointMake(windowWidth*0.75, 64+padding*1.5) 53 | iv5.center = CGPointMake(windowWidth*0.25, 64+padding*2.5) 54 | iv6.center = CGPointMake(windowWidth*0.75, 64+padding*2.5) 55 | } 56 | 57 | override func didReceiveMemoryWarning() { 58 | super.didReceiveMemoryWarning() 59 | // Dispose of any resources that can be recreated. 60 | } 61 | 62 | 63 | /* 64 | // MARK: - Navigation 65 | 66 | // In a storyboard-based application, you will often want to do a little preparation before navigation 67 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 68 | // Get the new view controller using segue.destinationViewController. 69 | // Pass the selected object to the new view controller. 70 | } 71 | */ 72 | 73 | } 74 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adad184/XXPlaceHolder/a74c8b927f76951e48c939e9ef82d709ce7398ac/demo.png --------------------------------------------------------------------------------