├── QHShowTextDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── chen.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── chen.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── QHShowTextDemo ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── QHShowTextMan │ ├── QHTextConfig.swift │ ├── QHTextManager.swift │ ├── QHTextTestConfig.swift │ ├── QHTextView.swift │ └── QHTextViewAnimate.swift └── ViewController.swift ├── README.md └── screenshots └── QHTextShowDemo.gif /QHShowTextDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 747CBCD820F5FB8D00AAF5C0 /* QHTextTestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 747CBCD720F5FB8D00AAF5C0 /* QHTextTestConfig.swift */; }; 11 | 747CBCDA20F6120C00AAF5C0 /* QHTextViewAnimate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 747CBCD920F6120C00AAF5C0 /* QHTextViewAnimate.swift */; }; 12 | 74FF93D420F331F200B5A841 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FF93D320F331F200B5A841 /* AppDelegate.swift */; }; 13 | 74FF93D620F331F200B5A841 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FF93D520F331F200B5A841 /* ViewController.swift */; }; 14 | 74FF93D920F331F200B5A841 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74FF93D720F331F200B5A841 /* Main.storyboard */; }; 15 | 74FF93DB20F331F300B5A841 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74FF93DA20F331F300B5A841 /* Assets.xcassets */; }; 16 | 74FF93DE20F331F300B5A841 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74FF93DC20F331F300B5A841 /* LaunchScreen.storyboard */; }; 17 | 74FF93E720F3334600B5A841 /* QHTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FF93E620F3334600B5A841 /* QHTextView.swift */; }; 18 | 74FF93E920F3401200B5A841 /* QHTextManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FF93E820F3401200B5A841 /* QHTextManager.swift */; }; 19 | 74FF93EB20F4B8B800B5A841 /* QHTextConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FF93EA20F4B8B800B5A841 /* QHTextConfig.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 747CBCD720F5FB8D00AAF5C0 /* QHTextTestConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QHTextTestConfig.swift; sourceTree = ""; }; 24 | 747CBCD920F6120C00AAF5C0 /* QHTextViewAnimate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QHTextViewAnimate.swift; sourceTree = ""; }; 25 | 74FF93D020F331F200B5A841 /* QHShowTextDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QHShowTextDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 74FF93D320F331F200B5A841 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | 74FF93D520F331F200B5A841 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 28 | 74FF93D820F331F200B5A841 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 74FF93DA20F331F300B5A841 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 74FF93DD20F331F300B5A841 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 74FF93DF20F331F300B5A841 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 74FF93E620F3334600B5A841 /* QHTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QHTextView.swift; sourceTree = ""; }; 33 | 74FF93E820F3401200B5A841 /* QHTextManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QHTextManager.swift; sourceTree = ""; }; 34 | 74FF93EA20F4B8B800B5A841 /* QHTextConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QHTextConfig.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 74FF93CD20F331F200B5A841 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 74FF93C720F331F200B5A841 = { 49 | isa = PBXGroup; 50 | children = ( 51 | 74FF93D220F331F200B5A841 /* QHShowTextDemo */, 52 | 74FF93D120F331F200B5A841 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 74FF93D120F331F200B5A841 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 74FF93D020F331F200B5A841 /* QHShowTextDemo.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 74FF93D220F331F200B5A841 /* QHShowTextDemo */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 74FF93E520F332D300B5A841 /* QHShowTextMan */, 68 | 74FF93D320F331F200B5A841 /* AppDelegate.swift */, 69 | 74FF93D520F331F200B5A841 /* ViewController.swift */, 70 | 74FF93D720F331F200B5A841 /* Main.storyboard */, 71 | 74FF93DA20F331F300B5A841 /* Assets.xcassets */, 72 | 74FF93DC20F331F300B5A841 /* LaunchScreen.storyboard */, 73 | 74FF93DF20F331F300B5A841 /* Info.plist */, 74 | ); 75 | path = QHShowTextDemo; 76 | sourceTree = ""; 77 | }; 78 | 74FF93E520F332D300B5A841 /* QHShowTextMan */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 74FF93E620F3334600B5A841 /* QHTextView.swift */, 82 | 747CBCD920F6120C00AAF5C0 /* QHTextViewAnimate.swift */, 83 | 74FF93E820F3401200B5A841 /* QHTextManager.swift */, 84 | 74FF93EA20F4B8B800B5A841 /* QHTextConfig.swift */, 85 | 747CBCD720F5FB8D00AAF5C0 /* QHTextTestConfig.swift */, 86 | ); 87 | path = QHShowTextMan; 88 | sourceTree = ""; 89 | }; 90 | /* End PBXGroup section */ 91 | 92 | /* Begin PBXNativeTarget section */ 93 | 74FF93CF20F331F200B5A841 /* QHShowTextDemo */ = { 94 | isa = PBXNativeTarget; 95 | buildConfigurationList = 74FF93E220F331F300B5A841 /* Build configuration list for PBXNativeTarget "QHShowTextDemo" */; 96 | buildPhases = ( 97 | 74FF93CC20F331F200B5A841 /* Sources */, 98 | 74FF93CD20F331F200B5A841 /* Frameworks */, 99 | 74FF93CE20F331F200B5A841 /* Resources */, 100 | ); 101 | buildRules = ( 102 | ); 103 | dependencies = ( 104 | ); 105 | name = QHShowTextDemo; 106 | productName = QHShowTextDemo; 107 | productReference = 74FF93D020F331F200B5A841 /* QHShowTextDemo.app */; 108 | productType = "com.apple.product-type.application"; 109 | }; 110 | /* End PBXNativeTarget section */ 111 | 112 | /* Begin PBXProject section */ 113 | 74FF93C820F331F200B5A841 /* Project object */ = { 114 | isa = PBXProject; 115 | attributes = { 116 | LastSwiftUpdateCheck = 0940; 117 | LastUpgradeCheck = 0940; 118 | ORGANIZATIONNAME = "Chen Network Technology"; 119 | TargetAttributes = { 120 | 74FF93CF20F331F200B5A841 = { 121 | CreatedOnToolsVersion = 9.4.1; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = 74FF93CB20F331F200B5A841 /* Build configuration list for PBXProject "QHShowTextDemo" */; 126 | compatibilityVersion = "Xcode 9.3"; 127 | developmentRegion = en; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | en, 131 | Base, 132 | ); 133 | mainGroup = 74FF93C720F331F200B5A841; 134 | productRefGroup = 74FF93D120F331F200B5A841 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 74FF93CF20F331F200B5A841 /* QHShowTextDemo */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | 74FF93CE20F331F200B5A841 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | 74FF93DE20F331F300B5A841 /* LaunchScreen.storyboard in Resources */, 149 | 74FF93DB20F331F300B5A841 /* Assets.xcassets in Resources */, 150 | 74FF93D920F331F200B5A841 /* Main.storyboard in Resources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXResourcesBuildPhase section */ 155 | 156 | /* Begin PBXSourcesBuildPhase section */ 157 | 74FF93CC20F331F200B5A841 /* Sources */ = { 158 | isa = PBXSourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 74FF93D620F331F200B5A841 /* ViewController.swift in Sources */, 162 | 747CBCD820F5FB8D00AAF5C0 /* QHTextTestConfig.swift in Sources */, 163 | 74FF93D420F331F200B5A841 /* AppDelegate.swift in Sources */, 164 | 74FF93E720F3334600B5A841 /* QHTextView.swift in Sources */, 165 | 74FF93E920F3401200B5A841 /* QHTextManager.swift in Sources */, 166 | 74FF93EB20F4B8B800B5A841 /* QHTextConfig.swift in Sources */, 167 | 747CBCDA20F6120C00AAF5C0 /* QHTextViewAnimate.swift in Sources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXSourcesBuildPhase section */ 172 | 173 | /* Begin PBXVariantGroup section */ 174 | 74FF93D720F331F200B5A841 /* Main.storyboard */ = { 175 | isa = PBXVariantGroup; 176 | children = ( 177 | 74FF93D820F331F200B5A841 /* Base */, 178 | ); 179 | name = Main.storyboard; 180 | sourceTree = ""; 181 | }; 182 | 74FF93DC20F331F300B5A841 /* LaunchScreen.storyboard */ = { 183 | isa = PBXVariantGroup; 184 | children = ( 185 | 74FF93DD20F331F300B5A841 /* Base */, 186 | ); 187 | name = LaunchScreen.storyboard; 188 | sourceTree = ""; 189 | }; 190 | /* End PBXVariantGroup section */ 191 | 192 | /* Begin XCBuildConfiguration section */ 193 | 74FF93E020F331F300B5A841 /* Debug */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | ALWAYS_SEARCH_USER_PATHS = NO; 197 | CLANG_ANALYZER_NONNULL = YES; 198 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 200 | CLANG_CXX_LIBRARY = "libc++"; 201 | CLANG_ENABLE_MODULES = YES; 202 | CLANG_ENABLE_OBJC_ARC = YES; 203 | CLANG_ENABLE_OBJC_WEAK = YES; 204 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 205 | CLANG_WARN_BOOL_CONVERSION = YES; 206 | CLANG_WARN_COMMA = YES; 207 | CLANG_WARN_CONSTANT_CONVERSION = YES; 208 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 209 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 210 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INFINITE_RECURSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 216 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 217 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 223 | CLANG_WARN_UNREACHABLE_CODE = YES; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | CODE_SIGN_IDENTITY = "iPhone Developer"; 226 | COPY_PHASE_STRIP = NO; 227 | DEBUG_INFORMATION_FORMAT = dwarf; 228 | ENABLE_STRICT_OBJC_MSGSEND = YES; 229 | ENABLE_TESTABILITY = YES; 230 | GCC_C_LANGUAGE_STANDARD = gnu11; 231 | GCC_DYNAMIC_NO_PIC = NO; 232 | GCC_NO_COMMON_BLOCKS = YES; 233 | GCC_OPTIMIZATION_LEVEL = 0; 234 | GCC_PREPROCESSOR_DEFINITIONS = ( 235 | "DEBUG=1", 236 | "$(inherited)", 237 | ); 238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 240 | GCC_WARN_UNDECLARED_SELECTOR = YES; 241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_VARIABLE = YES; 244 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 245 | MTL_ENABLE_DEBUG_INFO = YES; 246 | ONLY_ACTIVE_ARCH = YES; 247 | SDKROOT = iphoneos; 248 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 249 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 250 | }; 251 | name = Debug; 252 | }; 253 | 74FF93E120F331F300B5A841 /* Release */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_ANALYZER_NONNULL = YES; 258 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_ENABLE_OBJC_WEAK = YES; 264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_COMMA = YES; 267 | CLANG_WARN_CONSTANT_CONVERSION = YES; 268 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 270 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 271 | CLANG_WARN_EMPTY_BODY = YES; 272 | CLANG_WARN_ENUM_CONVERSION = YES; 273 | CLANG_WARN_INFINITE_RECURSION = YES; 274 | CLANG_WARN_INT_CONVERSION = YES; 275 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 276 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 277 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 278 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 279 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 280 | CLANG_WARN_STRICT_PROTOTYPES = YES; 281 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 282 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 283 | CLANG_WARN_UNREACHABLE_CODE = YES; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | CODE_SIGN_IDENTITY = "iPhone Developer"; 286 | COPY_PHASE_STRIP = NO; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | ENABLE_NS_ASSERTIONS = NO; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu11; 291 | GCC_NO_COMMON_BLOCKS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 299 | MTL_ENABLE_DEBUG_INFO = NO; 300 | SDKROOT = iphoneos; 301 | SWIFT_COMPILATION_MODE = wholemodule; 302 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 303 | VALIDATE_PRODUCT = YES; 304 | }; 305 | name = Release; 306 | }; 307 | 74FF93E320F331F300B5A841 /* Debug */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 311 | CODE_SIGN_STYLE = Automatic; 312 | DEVELOPMENT_TEAM = JC9Y4K55DX; 313 | INFOPLIST_FILE = QHShowTextDemo/Info.plist; 314 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 315 | LD_RUNPATH_SEARCH_PATHS = ( 316 | "$(inherited)", 317 | "@executable_path/Frameworks", 318 | ); 319 | PRODUCT_BUNDLE_IDENTIFIER = com.chen.QHShowTextDemo; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SWIFT_VERSION = 4.0; 322 | TARGETED_DEVICE_FAMILY = "1,2"; 323 | }; 324 | name = Debug; 325 | }; 326 | 74FF93E420F331F300B5A841 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 330 | CODE_SIGN_STYLE = Automatic; 331 | DEVELOPMENT_TEAM = JC9Y4K55DX; 332 | INFOPLIST_FILE = QHShowTextDemo/Info.plist; 333 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 334 | LD_RUNPATH_SEARCH_PATHS = ( 335 | "$(inherited)", 336 | "@executable_path/Frameworks", 337 | ); 338 | PRODUCT_BUNDLE_IDENTIFIER = com.chen.QHShowTextDemo; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SWIFT_VERSION = 4.0; 341 | TARGETED_DEVICE_FAMILY = "1,2"; 342 | }; 343 | name = Release; 344 | }; 345 | /* End XCBuildConfiguration section */ 346 | 347 | /* Begin XCConfigurationList section */ 348 | 74FF93CB20F331F200B5A841 /* Build configuration list for PBXProject "QHShowTextDemo" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | 74FF93E020F331F300B5A841 /* Debug */, 352 | 74FF93E120F331F300B5A841 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | 74FF93E220F331F300B5A841 /* Build configuration list for PBXNativeTarget "QHShowTextDemo" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | 74FF93E320F331F300B5A841 /* Debug */, 361 | 74FF93E420F331F300B5A841 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = 74FF93C820F331F200B5A841 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /QHShowTextDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QHShowTextDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /QHShowTextDemo.xcodeproj/project.xcworkspace/xcuserdata/chen.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenqihui/QHShowTextDemo/ba9765ddcb19a974a520a54614317f978fbed2cc/QHShowTextDemo.xcodeproj/project.xcworkspace/xcuserdata/chen.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /QHShowTextDemo.xcodeproj/xcuserdata/chen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /QHShowTextDemo.xcodeproj/xcuserdata/chen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | QHShowTextDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /QHShowTextDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/9. 6 | // Copyright © 2018年 Chen Network Technology. 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: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /QHShowTextDemo/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 | -------------------------------------------------------------------------------- /QHShowTextDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /QHShowTextDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /QHShowTextDemo/QHShowTextMan/QHTextConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QHTextConfig.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/10. 6 | // Copyright © 2018年 Chen Network Technology. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // 总配置 13 | struct QHTextConfig { 14 | var id: Int = 0 15 | var text: String 16 | 17 | var font: QHTextFontConfig = QHTextFontConfig() 18 | var transition: QHTextTransitionConfig = QHTextTransitionConfig() 19 | var animate: QHTextAnimateConfig = QHTextAnimateConfig() 20 | 21 | init(id: Int, text: String) { 22 | self.id = id 23 | self.text = text 24 | } 25 | } 26 | 27 | // 文本配置 28 | struct QHTextFontConfig { 29 | var size: CGFloat = 0.0 30 | var color: UIColor = UIColor.white 31 | var font: UIFont? 32 | var other: Any? 33 | } 34 | 35 | // 转场配置 36 | struct QHTextTransitionConfig { 37 | var type: QHTransitionType = .up 38 | var interval: Double = 0 39 | var scale: CGFloat = 1 40 | var other: Any? 41 | } 42 | 43 | // 动画配置 44 | struct QHTextAnimateConfig { 45 | var type: QHTextAnimateType = .none 46 | var interval: Double = 1 47 | var other: Any? 48 | var value: UIViewAnimationTransition = .none 49 | var scale: CGFloat = 1 50 | var animationTransition: UIViewAnimationTransition = .curlUp 51 | } 52 | 53 | // 当前行的显示动画类型 54 | enum QHTextAnimateType: Int { 55 | case none = 1 56 | case typewriter // 打字机 57 | case scale // 缩放 58 | case animationTransition //转场 59 | } 60 | 61 | // 换行时的转场动画类型 62 | enum QHTransitionType: Int { 63 | case up = 1 64 | case upScale // 缩放 65 | case clockwise // 顺时针 66 | case anticlockwise // 逆时针 67 | } 68 | -------------------------------------------------------------------------------- /QHShowTextDemo/QHShowTextMan/QHTextManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QHTextManager.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/9. 6 | // Copyright © 2018年 Chen Network Technology. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class QHTextManager: NSObject, QHTextViewDelegate { 12 | 13 | var view = UIView(frame: CGRect.zero) 14 | var data: [QHTextConfig]? 15 | 16 | var rotationSuperViewArray = [UIView]() 17 | var currentSuperViewIndex: Int = -1 18 | 19 | private func remove() { 20 | let frame = view.frame 21 | view.removeFromSuperview() 22 | view = UIView(frame: frame) 23 | } 24 | 25 | private func addRotationSuperView(data: [QHTextConfig]) { 26 | var superView = view 27 | for _ in 0.. QHTextManager { 84 | let manager = QHTextManager() 85 | manager.view.frame = superView.bounds 86 | superView.addSubview(manager.view) 87 | 88 | return manager 89 | } 90 | 91 | func showIn(superView: UIView) { 92 | view.backgroundColor = UIColor.black 93 | view.frame = superView.bounds 94 | superView.addSubview(view) 95 | } 96 | 97 | func play(data: [QHTextConfig]) { 98 | self.data = data 99 | addRotationSuperView(data: data) 100 | 101 | if data.count > 0, let nextText = data.first { 102 | currentSuperViewIndex = rotationSuperViewArray.count - 1 103 | let nextSuperView = rotationSuperViewArray[currentSuperViewIndex] 104 | let nextTextView = QHTextView.create(text: nextText, superView: nextSuperView) 105 | nextTextView.delegate = self 106 | nextSuperView.addSubview(nextTextView) 107 | nextTextView.show() 108 | } 109 | } 110 | 111 | // MARK: QHTextViewDelegate 112 | 113 | func complete(view: QHTextView) { 114 | let id = view.textId + 1 115 | if let data = self.data, id <= data.count { 116 | let nextText = data[id - 1] 117 | showText(currentTextView: view, nextText: nextText) 118 | } 119 | else { 120 | DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: { 121 | self.remove() 122 | }) 123 | } 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /QHShowTextDemo/QHShowTextMan/QHTextTestConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QHTextTestConfig.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/11. 6 | // Copyright © 2018年 Chen Network Technology. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class QHTextTestConfig: NSObject { 12 | 13 | private class func testTextStringArray() -> [String] { 14 | let textString = "你碰上一个女孩。你不好意思。跟她表白。你怎么办。你问她。你说。你信不信。我能瞬间。环绕世界一周。她说不信。你围着她。你就绕一周。你就回来了。你说。你已经环绕了。世界一周。因为。你就是我的。全世界。" 15 | let textStringArray = textString.components(separatedBy: "。") 16 | 17 | return textStringArray 18 | } 19 | 20 | private class func textFontConfig() -> QHTextFontConfig { 21 | var font = QHTextFontConfig() 22 | font.size = (CGFloat(arc4random() % 32) + 18) 23 | font.color = UIColor.white 24 | return font 25 | } 26 | 27 | private class func textTransitionConfig() -> QHTextTransitionConfig { 28 | var transition = QHTextTransitionConfig() 29 | transition.type = QHTransitionType(rawValue: (Int(arc4random() % 4) + 1))! 30 | transition.interval = 0.4 31 | if transition.type == .upScale { 32 | transition.scale = 1.0 + (CGFloat(arc4random() % 6) + 1) * 0.1 * ((Int(arc4random() % 2) + 1) == 2 ? 1 : -1) 33 | } 34 | return transition 35 | } 36 | 37 | private class func textAnimateConfig() -> QHTextAnimateConfig { 38 | var animate = QHTextAnimateConfig() 39 | animate.type = QHTextAnimateType(rawValue: (Int(arc4random() % 4) + 1))! 40 | animate.interval = 1 41 | if animate.type == .typewriter { 42 | animate.interval = 0.2 43 | } 44 | else if animate.type == .scale { 45 | animate.scale = 1.0 + (CGFloat(arc4random() % 9) + 1) * 0.1 * ((Int(arc4random() % 2) + 1) == 2 ? 1 : -1) 46 | } 47 | else if animate.type == .animationTransition { 48 | animate.animationTransition = UIViewAnimationTransition(rawValue: (Int(arc4random() % 4) + 1))! 49 | } 50 | return animate 51 | } 52 | 53 | class func testTextConfig() -> [QHTextConfig] { 54 | 55 | let textStringArray = testTextStringArray() 56 | var textConfigData = [QHTextConfig]() 57 | 58 | var lastTransition: QHTransitionType = .up 59 | 60 | for textString in textStringArray { 61 | let id = textConfigData.count + 1 62 | var textConfig = QHTextConfig(id: id, text: textString) 63 | 64 | textConfig.font = textFontConfig() 65 | textConfig.transition = textTransitionConfig() 66 | textConfig.animate = textAnimateConfig() 67 | 68 | if lastTransition == .clockwise || lastTransition == .anticlockwise { 69 | if lastTransition == textConfig.transition.type { 70 | textConfig.transition.type = .up 71 | } 72 | } 73 | 74 | if id == textStringArray.count { 75 | textConfig.transition.type = .up 76 | } 77 | 78 | lastTransition = textConfig.transition.type 79 | 80 | textConfigData.append(textConfig) 81 | } 82 | 83 | return textConfigData 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /QHShowTextDemo/QHShowTextMan/QHTextView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QHTextView.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/9. 6 | // Copyright © 2018年 Chen Network Technology. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol QHTextViewDelegate: NSObjectProtocol { 12 | func complete(view: QHTextView) 13 | } 14 | 15 | class QHTextView: UIView { 16 | 17 | var text = "" 18 | var textId: Int = 0 19 | var textConfig: QHTextConfig? 20 | weak var delegate : QHTextViewDelegate? 21 | 22 | override func draw(_ rect: CGRect) { 23 | if let context = UIGraphicsGetCurrentContext() { 24 | context.clear(rect) 25 | } 26 | // 绘制文本属性 27 | let textStyle = NSMutableParagraphStyle() 28 | textStyle.alignment = .center 29 | var textAttributes = [NSAttributedStringKey : Any]() 30 | var fontSize: CGFloat = 10 31 | if let textC = textConfig { 32 | fontSize = textC.font.size 33 | } 34 | textAttributes[NSAttributedStringKey.font] = UIFont.systemFont(ofSize: fontSize) 35 | textAttributes[NSAttributedStringKey.foregroundColor] = UIColor.white 36 | textAttributes[NSAttributedStringKey.paragraphStyle] = textStyle 37 | 38 | let text = self.text 39 | 40 | let strSize = text.size(withAttributes: textAttributes) 41 | // 文本绘制 42 | let centerP = CGPoint(x: (rect.size.width - strSize.width)/2, y: (rect.size.height - strSize.height)/2) 43 | text.draw(at: centerP, withAttributes: textAttributes) 44 | } 45 | 46 | // MARK: Public 47 | 48 | class func create(text: QHTextConfig, superView: UIView) -> QHTextView { 49 | let size = text.text.sizeFor(fontSize: text.font.size) 50 | let textView = QHTextView(frame: CGRect(origin: .zero, size: size)) 51 | textView.center = superView.center 52 | textView.backgroundColor = UIColor.clear 53 | textView.textConfig = text 54 | textView.textId = text.id 55 | 56 | return textView 57 | } 58 | 59 | func show() { 60 | if let textConfig = self.textConfig { 61 | switch textConfig.animate.type { 62 | case .none: 63 | none(textConfig: textConfig) 64 | case .typewriter: 65 | typewriter(textConfig: textConfig) 66 | case .scale: 67 | scale(textConfig: textConfig) 68 | case .animationTransition: 69 | animationTransition(textConfig: textConfig) 70 | } 71 | } 72 | } 73 | } 74 | 75 | extension String { 76 | func subString(to: Int) -> String { 77 | let endIndex = String.Index.init(encodedOffset: to) 78 | let subStr = self[self.startIndex.. CGSize { 83 | let font = UIFont.systemFont(ofSize: fontSize) 84 | let size = NSString(string: self).size(withAttributes: [NSAttributedStringKey.font: font]) 85 | return size 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /QHShowTextDemo/QHShowTextMan/QHTextViewAnimate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QHTextViewAnimate.swift 3 | // QHShowTextDemo 4 | // 5 | // Created by Anakin chen on 2018/7/11. 6 | // Copyright © 2018年 Chen Network Technology. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension QHTextView { 13 | 14 | func none(textConfig text: QHTextConfig) { 15 | self.text = text.text 16 | self.setNeedsDisplay() 17 | 18 | DispatchQueue.main.asyncAfter(deadline: .now() + text.animate.interval, execute: { 19 | self.delegate?.complete(view: self) 20 | }) 21 | } 22 | 23 | func typewriter(textConfig text: QHTextConfig) { 24 | for i in 0..