├── CommentDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── appleboyaug.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── appleboyaug.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── CommentDemo.xcscheme │ └── xcschememanagement.plist ├── CommentDemo ├── 1111.png ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Bullet │ ├── BulletBackgroudView.h │ ├── BulletBackgroudView.m │ ├── BulletManager.h │ ├── BulletManager.m │ ├── BulletView.h │ └── BulletView.m ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m └── README.md /CommentDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C30D0FAC1C78662C008C7F4F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C30D0FAB1C78662C008C7F4F /* main.m */; }; 11 | C30D0FAF1C78662C008C7F4F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C30D0FAE1C78662C008C7F4F /* AppDelegate.m */; }; 12 | C30D0FB21C78662C008C7F4F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C30D0FB11C78662C008C7F4F /* ViewController.m */; }; 13 | C30D0FB51C78662C008C7F4F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C30D0FB31C78662C008C7F4F /* Main.storyboard */; }; 14 | C30D0FB71C78662C008C7F4F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C30D0FB61C78662C008C7F4F /* Assets.xcassets */; }; 15 | C30D0FBA1C78662C008C7F4F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C30D0FB81C78662C008C7F4F /* LaunchScreen.storyboard */; }; 16 | C30D0FC41C786792008C7F4F /* BulletView.m in Sources */ = {isa = PBXBuildFile; fileRef = C30D0FC31C786792008C7F4F /* BulletView.m */; }; 17 | C30D0FC71C786AC8008C7F4F /* BulletManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C30D0FC61C786AC8008C7F4F /* BulletManager.m */; }; 18 | C455FB751E0E1E530061FE93 /* BulletBackgroudView.m in Sources */ = {isa = PBXBuildFile; fileRef = C455FB741E0E1E530061FE93 /* BulletBackgroudView.m */; }; 19 | C455FB771E0E2D120061FE93 /* 1111.png in Resources */ = {isa = PBXBuildFile; fileRef = C455FB761E0E2D120061FE93 /* 1111.png */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | C30D0FA71C78662C008C7F4F /* CommentDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CommentDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | C30D0FAB1C78662C008C7F4F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 25 | C30D0FAD1C78662C008C7F4F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 26 | C30D0FAE1C78662C008C7F4F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 27 | C30D0FB01C78662C008C7F4F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 28 | C30D0FB11C78662C008C7F4F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 29 | C30D0FB41C78662C008C7F4F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | C30D0FB61C78662C008C7F4F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | C30D0FB91C78662C008C7F4F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | C30D0FBB1C78662C008C7F4F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | C30D0FC21C786792008C7F4F /* BulletView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletView.h; sourceTree = ""; }; 34 | C30D0FC31C786792008C7F4F /* BulletView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BulletView.m; sourceTree = ""; }; 35 | C30D0FC51C786AC8008C7F4F /* BulletManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletManager.h; sourceTree = ""; }; 36 | C30D0FC61C786AC8008C7F4F /* BulletManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BulletManager.m; sourceTree = ""; }; 37 | C455FB731E0E1E530061FE93 /* BulletBackgroudView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BulletBackgroudView.h; sourceTree = ""; }; 38 | C455FB741E0E1E530061FE93 /* BulletBackgroudView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BulletBackgroudView.m; sourceTree = ""; }; 39 | C455FB761E0E2D120061FE93 /* 1111.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 1111.png; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | C30D0FA41C78662C008C7F4F /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | C30D0F9E1C78662B008C7F4F = { 54 | isa = PBXGroup; 55 | children = ( 56 | C30D0FA91C78662C008C7F4F /* CommentDemo */, 57 | C30D0FA81C78662C008C7F4F /* Products */, 58 | ); 59 | sourceTree = ""; 60 | }; 61 | C30D0FA81C78662C008C7F4F /* Products */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | C30D0FA71C78662C008C7F4F /* CommentDemo.app */, 65 | ); 66 | name = Products; 67 | sourceTree = ""; 68 | }; 69 | C30D0FA91C78662C008C7F4F /* CommentDemo */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | C30D0FC11C786775008C7F4F /* Bullet */, 73 | C30D0FAD1C78662C008C7F4F /* AppDelegate.h */, 74 | C30D0FAE1C78662C008C7F4F /* AppDelegate.m */, 75 | C30D0FB01C78662C008C7F4F /* ViewController.h */, 76 | C30D0FB11C78662C008C7F4F /* ViewController.m */, 77 | C30D0FB31C78662C008C7F4F /* Main.storyboard */, 78 | C455FB761E0E2D120061FE93 /* 1111.png */, 79 | C30D0FB61C78662C008C7F4F /* Assets.xcassets */, 80 | C30D0FB81C78662C008C7F4F /* LaunchScreen.storyboard */, 81 | C30D0FBB1C78662C008C7F4F /* Info.plist */, 82 | C30D0FAA1C78662C008C7F4F /* Supporting Files */, 83 | ); 84 | path = CommentDemo; 85 | sourceTree = ""; 86 | }; 87 | C30D0FAA1C78662C008C7F4F /* Supporting Files */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | C30D0FAB1C78662C008C7F4F /* main.m */, 91 | ); 92 | name = "Supporting Files"; 93 | sourceTree = ""; 94 | }; 95 | C30D0FC11C786775008C7F4F /* Bullet */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | C30D0FC21C786792008C7F4F /* BulletView.h */, 99 | C30D0FC31C786792008C7F4F /* BulletView.m */, 100 | C30D0FC51C786AC8008C7F4F /* BulletManager.h */, 101 | C30D0FC61C786AC8008C7F4F /* BulletManager.m */, 102 | C455FB731E0E1E530061FE93 /* BulletBackgroudView.h */, 103 | C455FB741E0E1E530061FE93 /* BulletBackgroudView.m */, 104 | ); 105 | path = Bullet; 106 | sourceTree = ""; 107 | }; 108 | /* End PBXGroup section */ 109 | 110 | /* Begin PBXNativeTarget section */ 111 | C30D0FA61C78662C008C7F4F /* CommentDemo */ = { 112 | isa = PBXNativeTarget; 113 | buildConfigurationList = C30D0FBE1C78662C008C7F4F /* Build configuration list for PBXNativeTarget "CommentDemo" */; 114 | buildPhases = ( 115 | C30D0FA31C78662C008C7F4F /* Sources */, 116 | C30D0FA41C78662C008C7F4F /* Frameworks */, 117 | C30D0FA51C78662C008C7F4F /* Resources */, 118 | ); 119 | buildRules = ( 120 | ); 121 | dependencies = ( 122 | ); 123 | name = CommentDemo; 124 | productName = CommentDemo; 125 | productReference = C30D0FA71C78662C008C7F4F /* CommentDemo.app */; 126 | productType = "com.apple.product-type.application"; 127 | }; 128 | /* End PBXNativeTarget section */ 129 | 130 | /* Begin PBXProject section */ 131 | C30D0F9F1C78662B008C7F4F /* Project object */ = { 132 | isa = PBXProject; 133 | attributes = { 134 | LastUpgradeCheck = 0720; 135 | ORGANIZATIONNAME = caishi; 136 | TargetAttributes = { 137 | C30D0FA61C78662C008C7F4F = { 138 | CreatedOnToolsVersion = 7.2.1; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = C30D0FA21C78662B008C7F4F /* Build configuration list for PBXProject "CommentDemo" */; 143 | compatibilityVersion = "Xcode 3.2"; 144 | developmentRegion = English; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = C30D0F9E1C78662B008C7F4F; 151 | productRefGroup = C30D0FA81C78662C008C7F4F /* Products */; 152 | projectDirPath = ""; 153 | projectRoot = ""; 154 | targets = ( 155 | C30D0FA61C78662C008C7F4F /* CommentDemo */, 156 | ); 157 | }; 158 | /* End PBXProject section */ 159 | 160 | /* Begin PBXResourcesBuildPhase section */ 161 | C30D0FA51C78662C008C7F4F /* Resources */ = { 162 | isa = PBXResourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | C30D0FBA1C78662C008C7F4F /* LaunchScreen.storyboard in Resources */, 166 | C30D0FB71C78662C008C7F4F /* Assets.xcassets in Resources */, 167 | C30D0FB51C78662C008C7F4F /* Main.storyboard in Resources */, 168 | C455FB771E0E2D120061FE93 /* 1111.png in Resources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXResourcesBuildPhase section */ 173 | 174 | /* Begin PBXSourcesBuildPhase section */ 175 | C30D0FA31C78662C008C7F4F /* Sources */ = { 176 | isa = PBXSourcesBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | C30D0FB21C78662C008C7F4F /* ViewController.m in Sources */, 180 | C455FB751E0E1E530061FE93 /* BulletBackgroudView.m in Sources */, 181 | C30D0FAF1C78662C008C7F4F /* AppDelegate.m in Sources */, 182 | C30D0FC41C786792008C7F4F /* BulletView.m in Sources */, 183 | C30D0FAC1C78662C008C7F4F /* main.m in Sources */, 184 | C30D0FC71C786AC8008C7F4F /* BulletManager.m in Sources */, 185 | ); 186 | runOnlyForDeploymentPostprocessing = 0; 187 | }; 188 | /* End PBXSourcesBuildPhase section */ 189 | 190 | /* Begin PBXVariantGroup section */ 191 | C30D0FB31C78662C008C7F4F /* Main.storyboard */ = { 192 | isa = PBXVariantGroup; 193 | children = ( 194 | C30D0FB41C78662C008C7F4F /* Base */, 195 | ); 196 | name = Main.storyboard; 197 | sourceTree = ""; 198 | }; 199 | C30D0FB81C78662C008C7F4F /* LaunchScreen.storyboard */ = { 200 | isa = PBXVariantGroup; 201 | children = ( 202 | C30D0FB91C78662C008C7F4F /* Base */, 203 | ); 204 | name = LaunchScreen.storyboard; 205 | sourceTree = ""; 206 | }; 207 | /* End PBXVariantGroup section */ 208 | 209 | /* Begin XCBuildConfiguration section */ 210 | C30D0FBC1C78662C008C7F4F /* Debug */ = { 211 | isa = XCBuildConfiguration; 212 | buildSettings = { 213 | ALWAYS_SEARCH_USER_PATHS = NO; 214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 215 | CLANG_CXX_LIBRARY = "libc++"; 216 | CLANG_ENABLE_MODULES = YES; 217 | CLANG_ENABLE_OBJC_ARC = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_CONSTANT_CONVERSION = YES; 220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 221 | CLANG_WARN_EMPTY_BODY = YES; 222 | CLANG_WARN_ENUM_CONVERSION = YES; 223 | CLANG_WARN_INT_CONVERSION = YES; 224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 225 | CLANG_WARN_UNREACHABLE_CODE = YES; 226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 227 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 228 | COPY_PHASE_STRIP = NO; 229 | DEBUG_INFORMATION_FORMAT = dwarf; 230 | ENABLE_STRICT_OBJC_MSGSEND = YES; 231 | ENABLE_TESTABILITY = YES; 232 | GCC_C_LANGUAGE_STANDARD = gnu99; 233 | GCC_DYNAMIC_NO_PIC = NO; 234 | GCC_NO_COMMON_BLOCKS = YES; 235 | GCC_OPTIMIZATION_LEVEL = 0; 236 | GCC_PREPROCESSOR_DEFINITIONS = ( 237 | "DEBUG=1", 238 | "$(inherited)", 239 | ); 240 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 241 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 242 | GCC_WARN_UNDECLARED_SELECTOR = YES; 243 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 244 | GCC_WARN_UNUSED_FUNCTION = YES; 245 | GCC_WARN_UNUSED_VARIABLE = YES; 246 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 247 | MTL_ENABLE_DEBUG_INFO = YES; 248 | ONLY_ACTIVE_ARCH = YES; 249 | SDKROOT = iphoneos; 250 | }; 251 | name = Debug; 252 | }; 253 | C30D0FBD1C78662C008C7F4F /* Release */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 258 | CLANG_CXX_LIBRARY = "libc++"; 259 | CLANG_ENABLE_MODULES = YES; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_CONSTANT_CONVERSION = YES; 263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_UNREACHABLE_CODE = YES; 269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 271 | COPY_PHASE_STRIP = NO; 272 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 273 | ENABLE_NS_ASSERTIONS = NO; 274 | ENABLE_STRICT_OBJC_MSGSEND = YES; 275 | GCC_C_LANGUAGE_STANDARD = gnu99; 276 | GCC_NO_COMMON_BLOCKS = YES; 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 284 | MTL_ENABLE_DEBUG_INFO = NO; 285 | SDKROOT = iphoneos; 286 | VALIDATE_PRODUCT = YES; 287 | }; 288 | name = Release; 289 | }; 290 | C30D0FBF1C78662C008C7F4F /* Debug */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 294 | INFOPLIST_FILE = CommentDemo/Info.plist; 295 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 296 | PRODUCT_BUNDLE_IDENTIFIER = com.caishi.app.CommentDemo; 297 | PRODUCT_NAME = "$(TARGET_NAME)"; 298 | }; 299 | name = Debug; 300 | }; 301 | C30D0FC01C78662C008C7F4F /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 305 | INFOPLIST_FILE = CommentDemo/Info.plist; 306 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 307 | PRODUCT_BUNDLE_IDENTIFIER = com.caishi.app.CommentDemo; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | }; 310 | name = Release; 311 | }; 312 | /* End XCBuildConfiguration section */ 313 | 314 | /* Begin XCConfigurationList section */ 315 | C30D0FA21C78662B008C7F4F /* Build configuration list for PBXProject "CommentDemo" */ = { 316 | isa = XCConfigurationList; 317 | buildConfigurations = ( 318 | C30D0FBC1C78662C008C7F4F /* Debug */, 319 | C30D0FBD1C78662C008C7F4F /* Release */, 320 | ); 321 | defaultConfigurationIsVisible = 0; 322 | defaultConfigurationName = Release; 323 | }; 324 | C30D0FBE1C78662C008C7F4F /* Build configuration list for PBXNativeTarget "CommentDemo" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | C30D0FBF1C78662C008C7F4F /* Debug */, 328 | C30D0FC01C78662C008C7F4F /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | /* End XCConfigurationList section */ 334 | }; 335 | rootObject = C30D0F9F1C78662B008C7F4F /* Project object */; 336 | } 337 | -------------------------------------------------------------------------------- /CommentDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CommentDemo.xcodeproj/project.xcworkspace/xcuserdata/appleboyaug.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appleboyaug/CommentDemo/b55cf24ec75c76e4b8458ce00d3811d5d1ded3fc/CommentDemo.xcodeproj/project.xcworkspace/xcuserdata/appleboyaug.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CommentDemo.xcodeproj/xcuserdata/appleboyaug.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 51 | 52 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /CommentDemo.xcodeproj/xcuserdata/appleboyaug.xcuserdatad/xcschemes/CommentDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /CommentDemo.xcodeproj/xcuserdata/appleboyaug.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CommentDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C30D0FA61C78662C008C7F4F 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CommentDemo/1111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appleboyaug/CommentDemo/b55cf24ec75c76e4b8458ce00d3811d5d1ded3fc/CommentDemo/1111.png -------------------------------------------------------------------------------- /CommentDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /CommentDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CommentDemo/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 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /CommentDemo/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 | -------------------------------------------------------------------------------- /CommentDemo/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 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletBackgroudView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BulletBackgroudView.h 3 | // CommentDemo 4 | // 5 | // Created by jia feng on 2016/12/24. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class BulletView; 12 | @interface BulletBackgroudView : UIView 13 | 14 | - (void)dealTapGesture:(UITapGestureRecognizer *)gesture block:(void(^)(BulletView *bulletView))block; 15 | @end 16 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletBackgroudView.m: -------------------------------------------------------------------------------- 1 | // 2 | // BulletBackgroudView.m 3 | // CommentDemo 4 | // 5 | // Created by jia feng on 2016/12/24. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import "BulletBackgroudView.h" 10 | #import "BulletView.h" 11 | 12 | @implementation BulletBackgroudView 13 | 14 | - (instancetype)init { 15 | if (self = [super init]) { 16 | self.userInteractionEnabled = NO; 17 | 18 | } 19 | return self; 20 | } 21 | 22 | 23 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 24 | if ([self findClickBulletView:point]) { 25 | return self; 26 | } 27 | return nil; 28 | } 29 | 30 | - (BulletView *)findClickBulletView:(CGPoint)point { 31 | BulletView *bulletView = nil; 32 | for (UIView *v in [self subviews]) { 33 | if ([v isKindOfClass:[BulletView class]]) { 34 | if ([v.layer.presentationLayer hitTest:point]) { 35 | bulletView = (BulletView *)v; 36 | break; 37 | } 38 | } 39 | } 40 | 41 | return bulletView; 42 | } 43 | 44 | - (void)dealTapGesture:(UITapGestureRecognizer *)gesture block:(void (^)(BulletView *bulletView))block { 45 | CGPoint clickPoint = [gesture locationInView:self]; 46 | 47 | BulletView *bulletView = [self findClickBulletView:clickPoint]; 48 | if (bulletView) { 49 | bulletView.backgroundColor = [UIColor blueColor]; 50 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 51 | bulletView.backgroundColor = [UIColor redColor]; 52 | }); 53 | if (block) { 54 | block(bulletView); 55 | } 56 | } 57 | 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // BulletManager.h 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | @class BulletView; 11 | @interface BulletManager : NSObject 12 | @property (nonatomic, copy) void(^generateBulletBlock)(BulletView *view); 13 | - (void)start; 14 | - (void)stop; 15 | @end 16 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // BulletManager.m 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import "BulletManager.h" 10 | #import "BulletView.h" 11 | 12 | @interface BulletManager() 13 | @property (nonatomic, strong) NSMutableArray *allComments; 14 | @property (nonatomic, strong) NSMutableArray *tmpComments; 15 | @property (nonatomic, strong) NSMutableArray *bulletQueue; 16 | 17 | @property BOOL bStarted; 18 | @property BOOL bStopAnimation; 19 | 20 | @end 21 | 22 | @implementation BulletManager 23 | - (void)start { 24 | if (self.tmpComments.count == 0) { 25 | [self.tmpComments addObjectsFromArray:self.allComments]; 26 | } 27 | self.bStarted = YES; 28 | self.bStopAnimation = NO; 29 | [self initBulletCommentView]; 30 | 31 | } 32 | 33 | - (void)stop { 34 | self.bStopAnimation = YES; 35 | [self.bulletQueue enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 36 | BulletView *view = obj; 37 | [view stopAnimation]; 38 | view = nil; 39 | }]; 40 | } 41 | 42 | #pragma mark - Private 43 | /** 44 | * 创建弹幕 45 | * 46 | * @param comment 弹幕内容 47 | * @param trajectory 弹道位置 48 | */ 49 | - (void)createBulletComment:(NSString *)comment trajectory:(Trajectory)trajectory { 50 | if (self.bStopAnimation) { 51 | return; 52 | } 53 | //创建一个弹幕view 54 | BulletView *view = [[BulletView alloc] initWithContent:comment]; 55 | //设置运行轨迹 56 | view.trajectory = trajectory; 57 | __weak BulletView *weakBulletView = view; 58 | __weak BulletManager *myself = self; 59 | /** 60 | * 弹幕view的动画过程中的回调状态 61 | * Start:创建弹幕在进入屏幕之前 62 | * Enter:弹幕完全进入屏幕 63 | * End:弹幕飞出屏幕后 64 | */ 65 | view.moveBlock = ^(CommentMoveStatus status) { 66 | if (myself.bStopAnimation) { 67 | return ; 68 | } 69 | switch (status) { 70 | case Start: 71 | //弹幕开始……将view加入弹幕管理queue 72 | [self.bulletQueue addObject:weakBulletView]; 73 | break; 74 | case Enter: { 75 | //弹幕完全进入屏幕,判断接下来是否还有内容,如果有则在该弹道轨迹对列中创建弹幕…… 76 | NSString *comment = [myself nextComment]; 77 | if (comment) { 78 | [myself createBulletComment:comment trajectory:trajectory]; 79 | } else { 80 | //说明到了评论的结尾了 81 | } 82 | break; 83 | } 84 | case End: { 85 | //弹幕飞出屏幕后从弹幕管理queue中删除 86 | if ([myself.bulletQueue containsObject:weakBulletView]) { 87 | [myself.bulletQueue removeObject:weakBulletView]; 88 | } 89 | if (myself.bulletQueue.count == 0) { 90 | //说明屏幕上已经没有弹幕评论了,循环开始 91 | [myself start]; 92 | } 93 | break; 94 | } 95 | default: 96 | break; 97 | } 98 | }; 99 | //弹幕生成后,传到viewcontroller进行页面展示 100 | if (self.generateBulletBlock) { 101 | self.generateBulletBlock(view); 102 | } 103 | } 104 | /** 105 | * 初始化弹幕 106 | */ 107 | - (void)initBulletCommentView { 108 | //初始化三条弹幕轨迹 109 | NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@(0), @(1), @(2)]]; 110 | for (int i = 3; i > 0; i--) { 111 | NSString *comment = [self.tmpComments firstObject]; 112 | if (comment) { 113 | [self.tmpComments removeObjectAtIndex:0]; 114 | //随机生成弹道创建弹幕进行展示(弹幕的随机飞入效果) 115 | NSInteger index = arc4random()%arr.count; 116 | Trajectory trajectory = [[arr objectAtIndex:index] intValue]; 117 | [arr removeObjectAtIndex:index]; 118 | [self createBulletComment:comment trajectory:trajectory]; 119 | } else { 120 | //当弹幕小于三个,则跳出 121 | break; 122 | } 123 | } 124 | } 125 | 126 | - (NSString *)nextComment { 127 | NSString *comment = [self.tmpComments firstObject]; 128 | if (comment) { 129 | [self.tmpComments removeObjectAtIndex:0]; 130 | } 131 | return comment; 132 | } 133 | 134 | #pragma mark - Getter 135 | 136 | - (NSMutableArray *)allComments { 137 | if (!_allComments) { 138 | _allComments = [NSMutableArray arrayWithObjects: 139 | @"我是一条弹幕1", 140 | @"我是一条弹幕我是一条弹幕2", 141 | @"弹幕3", 142 | @"弹幕4在这里", 143 | @"弹幕5 hhh", 144 | @"弹6", nil]; 145 | } 146 | return _allComments; 147 | } 148 | 149 | - (NSMutableArray *)tmpComments { 150 | if (!_tmpComments) { 151 | _tmpComments = [NSMutableArray array]; 152 | } 153 | return _tmpComments; 154 | } 155 | 156 | - (NSMutableArray *)bulletQueue { 157 | if (!_bulletQueue) { 158 | _bulletQueue = [NSMutableArray array]; 159 | } 160 | return _bulletQueue; 161 | } 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BulletView.h 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger, CommentMoveStatus) { 12 | Start, 13 | Enter, 14 | End 15 | 16 | }; 17 | 18 | typedef NS_ENUM(NSInteger, Trajectory) { 19 | Trajectory_1, 20 | Trajectory_2, 21 | Trajectory_3 22 | }; 23 | 24 | @interface BulletView : UIView 25 | @property (nonatomic, copy) void(^moveBlock)(CommentMoveStatus status); 26 | @property Trajectory trajectory; //弹幕弹道定义 27 | @property (nonatomic, strong) UILabel *lbComment; 28 | 29 | 30 | - (instancetype)initWithContent:(NSString *)content; 31 | - (void)startAnimation; 32 | - (void)stopAnimation; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CommentDemo/Bullet/BulletView.m: -------------------------------------------------------------------------------- 1 | // 2 | // BulletView.m 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import "BulletView.h" 10 | 11 | #define mWidth [UIScreen mainScreen].bounds.size.width 12 | #define mHeight [UIScreen mainScreen].bounds.size.height 13 | #define mDuration 5 14 | #define Padding 5 15 | @interface BulletView () 16 | 17 | @property BOOL bDealloc; 18 | @end 19 | 20 | @implementation BulletView 21 | 22 | - (void)dealloc { 23 | [self stopAnimation]; 24 | self.moveBlock = nil; 25 | } 26 | 27 | - (instancetype)initWithContent:(NSString *)content { 28 | if (self == [super init]) { 29 | self.userInteractionEnabled = NO; 30 | self.backgroundColor = [UIColor redColor]; 31 | NSDictionary *attributes = @{ 32 | NSFontAttributeName:[UIFont systemFontOfSize:14] 33 | }; 34 | float width = [content sizeWithAttributes:attributes].width; 35 | self.bounds = CGRectMake(0, 0, width + Padding*2, 25); 36 | 37 | self.lbComment = [UILabel new]; 38 | self.lbComment.frame = CGRectMake(Padding, 0, (width), 25); 39 | self.lbComment.backgroundColor = [UIColor clearColor]; 40 | self.lbComment.text = content; 41 | self.lbComment.font = [UIFont systemFontOfSize:14]; 42 | self.lbComment.textColor = [UIColor blackColor]; 43 | [self addSubview:self.lbComment]; 44 | } 45 | return self; 46 | } 47 | 48 | - (void)startAnimation { 49 | 50 | //根据定义的duration计算速度以及完全进入屏幕的时间 51 | CGFloat wholeWidth = CGRectGetWidth(self.frame) + mWidth + 50; 52 | CGFloat speed = wholeWidth/mDuration; 53 | CGFloat dur = (CGRectGetWidth(self.frame) + 50)/speed; 54 | 55 | 56 | __block CGRect frame = self.frame; 57 | if (self.moveBlock) { 58 | //弹幕开始进入屏幕 59 | self.moveBlock(Start); 60 | } 61 | 62 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dur * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 63 | //避免重复,通过变量判断是否已经释放了资源,释放后,不在进行操作 64 | if (self.bDealloc) { 65 | return; 66 | } 67 | //dur时间后弹幕完全进入屏幕 68 | if (self.moveBlock) { 69 | self.moveBlock(Enter); 70 | } 71 | }); 72 | 73 | //弹幕完全离开屏幕 74 | [UIView animateWithDuration:mDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ 75 | frame.origin.x = -CGRectGetWidth(frame); 76 | self.frame = frame; 77 | } completion:^(BOOL finished) { 78 | if (self.moveBlock) { 79 | self.moveBlock(End); 80 | } 81 | [self removeFromSuperview]; 82 | }]; 83 | } 84 | 85 | 86 | - (void)stopAnimation { 87 | self.bDealloc = YES; 88 | [self.layer removeAllAnimations]; 89 | [self removeFromSuperview]; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /CommentDemo/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 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CommentDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /CommentDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "BulletView.h" 11 | #import "BulletManager.h" 12 | #import "BulletBackgroudView.h" 13 | @interface ViewController () 14 | @property (nonatomic, strong) BulletManager *bulletManager; 15 | @property (nonatomic, strong) BulletBackgroudView *bulletBgView; 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // Do any additional setup after loading the view, typically from a nib. 23 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 24 | btn.frame = CGRectMake(100, 370, 100, 40); 25 | [btn setTitle:@"点击我" forState:UIControlStateNormal]; 26 | [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 27 | [btn setBackgroundImage:[UIImage imageNamed:@"1111"] forState:UIControlStateNormal]; 28 | [btn addTarget:self action:@selector(clickBtn) forControlEvents:UIControlEventTouchUpInside]; 29 | [self.view addSubview:btn]; 30 | 31 | 32 | 33 | [self configStartBtn]; 34 | [self configStopBtn]; 35 | [self addTapGesture]; 36 | 37 | self.bulletManager = [[BulletManager alloc] init]; 38 | __weak ViewController *myself = self; 39 | self.bulletManager.generateBulletBlock = ^(BulletView *bulletView) { 40 | [myself addBulletView:bulletView]; 41 | }; 42 | 43 | 44 | 45 | 46 | } 47 | 48 | - (void)didReceiveMemoryWarning { 49 | [super didReceiveMemoryWarning]; 50 | // Dispose of any resources that can be recreated. 51 | } 52 | 53 | - (void)addTapGesture { 54 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapHandler:)]; 55 | tap.cancelsTouchesInView = NO; 56 | [self.view addGestureRecognizer:tap]; 57 | 58 | } 59 | 60 | - (void)tapHandler:(UITapGestureRecognizer *)gesture { 61 | [self.bulletBgView dealTapGesture:gesture block:^(BulletView *bulletView){ 62 | NSLog(@"%@", bulletView.lbComment.text); 63 | }]; 64 | } 65 | 66 | - (void)clickBtn { 67 | NSLog(@"clickBtn"); 68 | } 69 | 70 | - (void)configStartBtn { 71 | UIButton *start = [UIButton buttonWithType:UIButtonTypeCustom]; 72 | start.frame = CGRectMake(CGRectGetWidth(self.view.frame)/2 - 80, 80, 70, 30); 73 | [start setTitle:@"start" forState:UIControlStateNormal]; 74 | [start setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 75 | [start addTarget:self action:@selector(clickStart:) forControlEvents:UIControlEventTouchUpInside]; 76 | [self.view addSubview:start]; 77 | } 78 | 79 | - (void)configStopBtn { 80 | UIButton *stop = [UIButton buttonWithType:UIButtonTypeCustom]; 81 | stop.frame = CGRectMake(CGRectGetWidth(self.view.frame)/2 +10, 80, 70, 30); 82 | [stop setTitle:@"stop" forState:UIControlStateNormal]; 83 | [stop setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 84 | [stop addTarget:self action:@selector(clickStop:) forControlEvents:UIControlEventTouchUpInside]; 85 | [self.view addSubview:stop]; 86 | } 87 | 88 | - (void)clickStart:(UIButton *)btn { 89 | [self.bulletManager start]; 90 | } 91 | 92 | - (void)clickStop:(UIButton *)btn { 93 | [self.bulletManager stop]; 94 | } 95 | 96 | - (void)addBulletView:(BulletView *)bulletView { 97 | bulletView.frame = CGRectMake(CGRectGetWidth(self.view.frame)+50, 20 + 34 * bulletView.trajectory, CGRectGetWidth(bulletView.bounds), CGRectGetHeight(bulletView.bounds)); 98 | [self.bulletBgView addSubview:bulletView]; 99 | [bulletView startAnimation]; 100 | } 101 | 102 | - (BulletBackgroudView *)bulletBgView { 103 | if (!_bulletBgView) { 104 | _bulletBgView = [[BulletBackgroudView alloc] init]; 105 | _bulletBgView.frame = CGRectMake(0, 300, CGRectGetWidth(self.view.frame), 150); 106 | _bulletBgView.backgroundColor = [UIColor clearColor]; 107 | [self.view addSubview:_bulletBgView]; 108 | } 109 | return _bulletBgView; 110 | } 111 | 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CommentDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CommentDemo 4 | // 5 | // Created by feng jia on 16/2/20. 6 | // Copyright © 2016年 caishi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CommentDemo 2 | iOS弹幕的原理分析与实现详见:http://www.jianshu.com/p/f39b8abc8008 3 | 效果如下: 4 | 5 | ![](http://7xr4e4.com1.z0.glb.clouddn.com/danmu_xiaoguo.gif) 6 | --------------------------------------------------------------------------------