├── .gitignore ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── Headers │ └── Private │ │ ├── YYImage │ │ ├── YYAnimatedImageView.h │ │ ├── YYFrameImage.h │ │ ├── YYImage.h │ │ ├── YYImageCoder.h │ │ └── YYSpriteSheetImage.h │ │ └── YYText │ │ ├── NSAttributedString+YYText.h │ │ ├── NSParagraphStyle+YYText.h │ │ ├── UIPasteboard+YYText.h │ │ ├── UIView+YYText.h │ │ ├── YYLabel.h │ │ ├── YYText.h │ │ ├── YYTextArchiver.h │ │ ├── YYTextAsyncLayer.h │ │ ├── YYTextAttribute.h │ │ ├── YYTextContainerView.h │ │ ├── YYTextDebugOption.h │ │ ├── YYTextEffectWindow.h │ │ ├── YYTextInput.h │ │ ├── YYTextKeyboardManager.h │ │ ├── YYTextLayout.h │ │ ├── YYTextLine.h │ │ ├── YYTextMagnifier.h │ │ ├── YYTextParser.h │ │ ├── YYTextRubyAnnotation.h │ │ ├── YYTextRunDelegate.h │ │ ├── YYTextSelectionView.h │ │ ├── YYTextTransaction.h │ │ ├── YYTextUtilities.h │ │ ├── YYTextView.h │ │ └── YYTextWeakProxy.h ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── Target Support Files │ ├── Pods-YYTextSwiftDemo │ │ ├── Info.plist │ │ ├── Pods-YYTextSwiftDemo-acknowledgements.markdown │ │ ├── Pods-YYTextSwiftDemo-acknowledgements.plist │ │ ├── Pods-YYTextSwiftDemo-dummy.m │ │ ├── Pods-YYTextSwiftDemo-frameworks.sh │ │ ├── Pods-YYTextSwiftDemo-resources.sh │ │ ├── Pods-YYTextSwiftDemo-umbrella.h │ │ ├── Pods-YYTextSwiftDemo.debug.xcconfig │ │ ├── Pods-YYTextSwiftDemo.modulemap │ │ └── Pods-YYTextSwiftDemo.release.xcconfig │ ├── YYImage │ │ ├── Info.plist │ │ ├── YYImage-dummy.m │ │ ├── YYImage-prefix.pch │ │ ├── YYImage-umbrella.h │ │ ├── YYImage.modulemap │ │ └── YYImage.xcconfig │ └── YYText │ │ ├── Info.plist │ │ ├── YYText-dummy.m │ │ ├── YYText-prefix.pch │ │ ├── YYText-umbrella.h │ │ ├── YYText.modulemap │ │ └── YYText.xcconfig ├── YYImage │ ├── LICENSE │ ├── README.md │ └── YYImage │ │ ├── YYAnimatedImageView.h │ │ ├── YYAnimatedImageView.m │ │ ├── YYFrameImage.h │ │ ├── YYFrameImage.m │ │ ├── YYImage.h │ │ ├── YYImage.m │ │ ├── YYImageCoder.h │ │ ├── YYImageCoder.m │ │ ├── YYSpriteSheetImage.h │ │ └── YYSpriteSheetImage.m └── YYText │ ├── LICENSE │ ├── README.md │ └── YYText │ ├── Component │ ├── YYTextContainerView.h │ ├── YYTextContainerView.m │ ├── YYTextDebugOption.h │ ├── YYTextDebugOption.m │ ├── YYTextEffectWindow.h │ ├── YYTextEffectWindow.m │ ├── YYTextInput.h │ ├── YYTextInput.m │ ├── YYTextKeyboardManager.h │ ├── YYTextKeyboardManager.m │ ├── YYTextLayout.h │ ├── YYTextLayout.m │ ├── YYTextLine.h │ ├── YYTextLine.m │ ├── YYTextMagnifier.h │ ├── YYTextMagnifier.m │ ├── YYTextSelectionView.h │ └── YYTextSelectionView.m │ ├── String │ ├── YYTextArchiver.h │ ├── YYTextArchiver.m │ ├── YYTextAttribute.h │ ├── YYTextAttribute.m │ ├── YYTextParser.h │ ├── YYTextParser.m │ ├── YYTextRubyAnnotation.h │ ├── YYTextRubyAnnotation.m │ ├── YYTextRunDelegate.h │ └── YYTextRunDelegate.m │ ├── Utility │ ├── NSAttributedString+YYText.h │ ├── NSAttributedString+YYText.m │ ├── NSParagraphStyle+YYText.h │ ├── NSParagraphStyle+YYText.m │ ├── UIPasteboard+YYText.h │ ├── UIPasteboard+YYText.m │ ├── UIView+YYText.h │ ├── UIView+YYText.m │ ├── YYTextAsyncLayer.h │ ├── YYTextAsyncLayer.m │ ├── YYTextTransaction.h │ ├── YYTextTransaction.m │ ├── YYTextUtilities.h │ ├── YYTextUtilities.m │ ├── YYTextWeakProxy.h │ └── YYTextWeakProxy.m │ ├── YYLabel.h │ ├── YYLabel.m │ ├── YYText.h │ ├── YYTextView.h │ └── YYTextView.m ├── README.md ├── YYTextSwiftDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── YYTextSwiftDemo.xcworkspace └── contents.xcworkspacedata ├── YYTextSwiftDemo ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── dribbble64_imageio.imageset │ │ ├── Contents.json │ │ └── dribbble64_imageio.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Helpers │ ├── String+Extension.swift │ ├── TextLinePositionModifier.swift │ ├── TextParser.swift │ ├── UILabel+Extension.swift │ └── UIView+Frame.swift ├── Info.plist ├── ViewController.swift └── YYTextSwiftDemo-Bridging-Header.h └── YYTextSwiftDemoTests ├── Info.plist └── YYTextSwiftDemoTests.swift /.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 | Carthage 20 | *.generated.swift 21 | 22 | # CocoaPods 23 | # 24 | # We recommend against adding the Pods directory to your .gitignore. However 25 | # you should judge for yourself, the pros and cons are mentioned at: 26 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 27 | # 28 | # Pods/ 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Hilen Lai 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 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform:ios,'8.0' 4 | use_frameworks! 5 | # ignore all warnings from all pods 6 | inhibit_all_warnings! 7 | 8 | target 'YYTextSwiftDemo' do 9 | pod 'YYImage' 10 | pod 'YYText', '~> 1.0.3' 11 | end 12 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - YYImage (1.0.1): 3 | - YYImage/Core (= 1.0.1) 4 | - YYImage/Core (1.0.1) 5 | - YYText (1.0.3) 6 | 7 | DEPENDENCIES: 8 | - YYImage 9 | - YYText (~> 1.0.3) 10 | 11 | SPEC CHECKSUMS: 12 | YYImage: b41b45bc5f32bfcdf67bdfb9c09da9e9832357c0 13 | YYText: 3050159192035d7f232b537ce76668aac2e2bd8b 14 | 15 | COCOAPODS: 0.39.0 16 | -------------------------------------------------------------------------------- /Pods/Headers/Private/YYImage/YYAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | ../../../YYImage/YYImage/YYAnimatedImageView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYImage/YYFrameImage.h: -------------------------------------------------------------------------------- 1 | ../../../YYImage/YYImage/YYFrameImage.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYImage/YYImage.h: -------------------------------------------------------------------------------- 1 | ../../../YYImage/YYImage/YYImage.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYImage/YYImageCoder.h: -------------------------------------------------------------------------------- 1 | ../../../YYImage/YYImage/YYImageCoder.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYImage/YYSpriteSheetImage.h: -------------------------------------------------------------------------------- 1 | ../../../YYImage/YYImage/YYSpriteSheetImage.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/NSAttributedString+YYText.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/NSAttributedString+YYText.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/NSParagraphStyle+YYText.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/NSParagraphStyle+YYText.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/UIPasteboard+YYText.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/UIPasteboard+YYText.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/UIView+YYText.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/UIView+YYText.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYLabel.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/YYLabel.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYText.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/YYText.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextArchiver.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/String/YYTextArchiver.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextAsyncLayer.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/YYTextAsyncLayer.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextAttribute.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/String/YYTextAttribute.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextContainerView.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextContainerView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextDebugOption.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextDebugOption.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextEffectWindow.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextEffectWindow.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextInput.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextInput.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextKeyboardManager.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextKeyboardManager.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextLayout.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextLayout.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextLine.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextLine.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextMagnifier.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextMagnifier.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextParser.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/String/YYTextParser.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextRubyAnnotation.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/String/YYTextRubyAnnotation.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextRunDelegate.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/String/YYTextRunDelegate.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextSelectionView.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Component/YYTextSelectionView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextTransaction.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/YYTextTransaction.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextUtilities.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/YYTextUtilities.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextView.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/YYTextView.h -------------------------------------------------------------------------------- /Pods/Headers/Private/YYText/YYTextWeakProxy.h: -------------------------------------------------------------------------------- 1 | ../../../YYText/YYText/Utility/YYTextWeakProxy.h -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - YYImage (1.0.1): 3 | - YYImage/Core (= 1.0.1) 4 | - YYImage/Core (1.0.1) 5 | - YYText (1.0.3) 6 | 7 | DEPENDENCIES: 8 | - YYImage 9 | - YYText (~> 1.0.3) 10 | 11 | SPEC CHECKSUMS: 12 | YYImage: b41b45bc5f32bfcdf67bdfb9c09da9e9832357c0 13 | YYText: 3050159192035d7f232b537ce76668aac2e2bd8b 14 | 15 | COCOAPODS: 0.39.0 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## YYImage 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2015 ibireme 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | 29 | 30 | ## YYText 31 | 32 | The MIT License (MIT) 33 | 34 | Copyright (c) 2015 ibireme 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | 54 | 55 | Generated by CocoaPods - http://cocoapods.org 56 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2015 ibireme <ibireme@gmail.com> 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | 40 | Title 41 | YYImage 42 | Type 43 | PSGroupSpecifier 44 | 45 | 46 | FooterText 47 | The MIT License (MIT) 48 | 49 | Copyright (c) 2015 ibireme <ibireme@gmail.com> 50 | 51 | Permission is hereby granted, free of charge, to any person obtaining a copy 52 | of this software and associated documentation files (the "Software"), to deal 53 | in the Software without restriction, including without limitation the rights 54 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 55 | copies of the Software, and to permit persons to whom the Software is 56 | furnished to do so, subject to the following conditions: 57 | 58 | The above copyright notice and this permission notice shall be included in all 59 | copies or substantial portions of the Software. 60 | 61 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 64 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 65 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 66 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 67 | SOFTWARE. 68 | 69 | 70 | Title 71 | YYText 72 | Type 73 | PSGroupSpecifier 74 | 75 | 76 | FooterText 77 | Generated by CocoaPods - http://cocoapods.org 78 | Title 79 | 80 | Type 81 | PSGroupSpecifier 82 | 83 | 84 | StringsTable 85 | Acknowledgements 86 | Title 87 | Acknowledgements 88 | 89 | 90 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_YYTextSwiftDemo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_YYTextSwiftDemo 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" 63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" 64 | fi 65 | } 66 | 67 | # Strip invalid architectures 68 | strip_invalid_archs() { 69 | binary="$1" 70 | # Get architectures for current file 71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 72 | stripped="" 73 | for arch in $archs; do 74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 75 | # Strip non-valid architectures in-place 76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 77 | stripped="$stripped $arch" 78 | fi 79 | done 80 | if [[ "$stripped" ]]; then 81 | echo "Stripped $binary of architectures:$stripped" 82 | fi 83 | } 84 | 85 | 86 | if [[ "$CONFIGURATION" == "Debug" ]]; then 87 | install_framework "Pods-YYTextSwiftDemo/YYImage.framework" 88 | install_framework "Pods-YYTextSwiftDemo/YYText.framework" 89 | fi 90 | if [[ "$CONFIGURATION" == "Release" ]]; then 91 | install_framework "Pods-YYTextSwiftDemo/YYImage.framework" 92 | install_framework "Pods-YYTextSwiftDemo/YYText.framework" 93 | fi 94 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | FOUNDATION_EXPORT double Pods_YYTextSwiftDemoVersionNumber; 5 | FOUNDATION_EXPORT const unsigned char Pods_YYTextSwiftDemoVersionString[]; 6 | 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/YYImage.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/YYText.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "YYImage" -framework "YYText" 5 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-YYTextSwiftDemo 6 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_YYTextSwiftDemo { 2 | umbrella header "Pods-YYTextSwiftDemo-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YYTextSwiftDemo/Pods-YYTextSwiftDemo.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/YYImage.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/YYText.framework/Headers" 4 | OTHER_LDFLAGS = $(inherited) -framework "YYImage" -framework "YYText" 5 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-YYTextSwiftDemo 6 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/YYImage-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_YYImage : NSObject 3 | @end 4 | @implementation PodsDummy_YYImage 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/YYImage-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/YYImage-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "YYAnimatedImageView.h" 4 | #import "YYFrameImage.h" 5 | #import "YYImage.h" 6 | #import "YYImageCoder.h" 7 | #import "YYSpriteSheetImage.h" 8 | 9 | FOUNDATION_EXPORT double YYImageVersionNumber; 10 | FOUNDATION_EXPORT const unsigned char YYImageVersionString[]; 11 | 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/YYImage.modulemap: -------------------------------------------------------------------------------- 1 | framework module YYImage { 2 | umbrella header "YYImage-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYImage/YYImage.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/YYImage" "${PODS_ROOT}/Headers/Public" 3 | OTHER_LDFLAGS = -l"z" -framework "Accelerate" -framework "AssetsLibrary" -framework "CoreFoundation" -framework "ImageIO" -framework "MobileCoreServices" -framework "QuartzCore" -framework "UIKit" 4 | PODS_ROOT = ${SRCROOT} 5 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.3 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/YYText-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_YYText : NSObject 3 | @end 4 | @implementation PodsDummy_YYText 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/YYText-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/YYText-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "YYTextContainerView.h" 4 | #import "YYTextDebugOption.h" 5 | #import "YYTextEffectWindow.h" 6 | #import "YYTextInput.h" 7 | #import "YYTextKeyboardManager.h" 8 | #import "YYTextLayout.h" 9 | #import "YYTextLine.h" 10 | #import "YYTextMagnifier.h" 11 | #import "YYTextSelectionView.h" 12 | #import "YYTextArchiver.h" 13 | #import "YYTextAttribute.h" 14 | #import "YYTextParser.h" 15 | #import "YYTextRubyAnnotation.h" 16 | #import "YYTextRunDelegate.h" 17 | #import "NSAttributedString+YYText.h" 18 | #import "NSParagraphStyle+YYText.h" 19 | #import "UIPasteboard+YYText.h" 20 | #import "UIView+YYText.h" 21 | #import "YYTextAsyncLayer.h" 22 | #import "YYTextTransaction.h" 23 | #import "YYTextUtilities.h" 24 | #import "YYTextWeakProxy.h" 25 | #import "YYLabel.h" 26 | #import "YYText.h" 27 | #import "YYTextView.h" 28 | 29 | FOUNDATION_EXPORT double YYTextVersionNumber; 30 | FOUNDATION_EXPORT const unsigned char YYTextVersionString[]; 31 | 32 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/YYText.modulemap: -------------------------------------------------------------------------------- 1 | framework module YYText { 2 | umbrella header "YYText-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYText/YYText.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/YYText" "${PODS_ROOT}/Headers/Public" 3 | OTHER_LDFLAGS = -framework "Accelerate" -framework "CoreFoundation" -framework "CoreText" -framework "MobileCoreServices" -framework "QuartzCore" -framework "UIKit" 4 | PODS_ROOT = ${SRCROOT} 5 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Pods/YYImage/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ibireme 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 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYAnimatedImageView.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/19. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | An image view for displaying animated image. 18 | 19 | @discussion It is a fully compatible `UIImageView` subclass. 20 | If the `image` or `highlightedImage` property adopt to the `YYAnimatedImage` protocol, 21 | then it can be used to play the multi-frame animation. The animation can also be 22 | controlled with the UIImageView methods `-startAnimating`, `-stopAnimating` and `-isAnimating`. 23 | 24 | This view request the frame data just in time. When the device has enough free memory, 25 | this view may cache some or all future frames in an inner buffer for lower CPU cost. 26 | Buffer size is dynamically adjusted based on the current state of the device memory. 27 | 28 | Sample Code: 29 | 30 | // ani@3x.gif 31 | YYImage *image = [YYImage imageNamed:@"ani"]; 32 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 33 | [view addSubView:imageView]; 34 | */ 35 | @interface YYAnimatedImageView : UIImageView 36 | 37 | /** 38 | If the image has more than one frame, set this value to `YES` will automatically 39 | play/stop the animation when the view become visible/invisible. 40 | 41 | The default value is `YES`. 42 | */ 43 | @property (nonatomic) BOOL autoPlayAnimatedImage; 44 | 45 | /** 46 | Index of the currently displayed frame (index from 0). 47 | 48 | Set a new value to this property will cause to display the new frame immediately. 49 | If the new value is invalid, this method has no effect. 50 | 51 | You can add an observer to this property to observe the playing status. 52 | */ 53 | @property (nonatomic) NSUInteger currentAnimatedImageIndex; 54 | 55 | /** 56 | Whether the image view is playing animation currently. 57 | 58 | You can add an observer to this property to observe the playing status. 59 | */ 60 | @property (nonatomic, readonly) BOOL currentIsPlayingAnimation; 61 | 62 | /** 63 | The animation timer's runloop mode, default is `NSRunLoopCommonModes`. 64 | 65 | Set this property to `NSDefaultRunLoopMode` will make the animation pause during 66 | UIScrollView scrolling. 67 | */ 68 | @property (nonatomic, copy) NSString *runloopMode; 69 | 70 | /** 71 | The max size (in bytes) for inner frame buffer size, default is 0 (dynamically). 72 | 73 | When the device has enough free memory, this view will request and decode some or 74 | all future frame image into an inner buffer. If this property's value is 0, then 75 | the max buffer size will be dynamically adjusted based on the current state of 76 | the device free memory. Otherwise, the buffer size will be limited by this value. 77 | 78 | When receive memory warning or app enter background, the buffer will be released 79 | immediately, and may grow back at the right time. 80 | */ 81 | @property (nonatomic) NSUInteger maxBufferSize; 82 | 83 | @end 84 | 85 | 86 | 87 | /** 88 | The YYAnimatedImage protocol declares the required methods for animated image 89 | display with YYAnimatedImageView. 90 | 91 | Subclass a UIImage and implement this protocol, so that instances of that class 92 | can be set to YYAnimatedImageView.image or YYAnimatedImageView.highlightedImage 93 | to display animation. 94 | 95 | See `YYImage` and `YYFrameImage` for example. 96 | */ 97 | @protocol YYAnimatedImage 98 | @required 99 | /// Total animated frame count. 100 | /// It the frame count is less than 1, then the methods below will be ignored. 101 | - (NSUInteger)animatedImageFrameCount; 102 | 103 | /// Animation loop count, 0 means infinite looping. 104 | - (NSUInteger)animatedImageLoopCount; 105 | 106 | /// Bytes per frame (in memory). It may used to optimize memory buffer size. 107 | - (NSUInteger)animatedImageBytesPerFrame; 108 | 109 | /// Returns the frame image from a specified index. 110 | /// This method may be called on background thread. 111 | /// @param index Frame index (zero based). 112 | - (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; 113 | 114 | /// Returns the frames's duration from a specified index. 115 | /// @param index Frame index (zero based). 116 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; 117 | 118 | @optional 119 | /// A rectangle in image coordinates defining the subrectangle of the image that 120 | /// will be displayed. The rectangle should not outside the image's bounds. 121 | /// It may used to display sprite animation with a single image (sprite sheet). 122 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index; 123 | @end 124 | 125 | NS_ASSUME_NONNULL_END 126 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYFrameImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display frame-based animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | It only support system image format such as png and jpeg. 29 | The animation can be played by YYAnimatedImageView. 30 | 31 | Sample Code: 32 | 33 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"]; 34 | NSArray *times = @[@0.1, @0.2, @0.1]; 35 | YYFrameImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES]; 36 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 37 | [view addSubView:imageView]; 38 | */ 39 | @interface YYFrameImage : UIImage 40 | 41 | /** 42 | Create a frame animated image from files. 43 | 44 | @param paths An array of NSString objects, contains the full or 45 | partial path to each image file. 46 | e.g. @[@"/ani/1.png",@"/ani/2.png",@"/ani/3.png"] 47 | 48 | @param oneFrameDuration The duration (in seconds) per frame. 49 | 50 | @param loopCount The animation loop count, 0 means infinite. 51 | 52 | @return An initialized YYFrameImage object, or nil when an error occurs. 53 | */ 54 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 55 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 56 | loopCount:(NSUInteger)loopCount; 57 | 58 | /** 59 | Create a frame animated image from files. 60 | 61 | @param paths An array of NSString objects, contains the full or 62 | partial path to each image file. 63 | e.g. @[@"/ani/frame1.png",@"/ani/frame2.png",@"/ani/frame3.png"] 64 | 65 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 66 | e.g. @[@0.1, @0.2, @0.3]; 67 | 68 | @param loopCount The animation loop count, 0 means infinite. 69 | 70 | @return An initialized YYFrameImage object, or nil when an error occurs. 71 | */ 72 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 73 | frameDurations:(NSArray *)frameDurations 74 | loopCount:(NSUInteger)loopCount; 75 | 76 | /** 77 | Create a frame animated image from an array of data. 78 | 79 | @param dataArray An array of NSData objects. 80 | 81 | @param oneFrameDuration The duration (in seconds) per frame. 82 | 83 | @param loopCount The animation loop count, 0 means infinite. 84 | 85 | @return An initialized YYFrameImage object, or nil when an error occurs. 86 | */ 87 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 88 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 89 | loopCount:(NSUInteger)loopCount; 90 | 91 | /** 92 | Create a frame animated image from an array of data. 93 | 94 | @param dataArray An array of NSData objects. 95 | 96 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 97 | e.g. @[@0.1, @0.2, @0.3]; 98 | 99 | @param loopCount The animation loop count, 0 means infinite. 100 | 101 | @return An initialized YYFrameImage object, or nil when an error occurs. 102 | */ 103 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 104 | frameDurations:(NSArray *)frameDurations 105 | loopCount:(NSUInteger)loopCount; 106 | 107 | @end 108 | 109 | NS_ASSUME_NONNULL_END 110 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYFrameImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYFrameImage.h" 13 | #import "YYImageCoder.h" 14 | 15 | 16 | /** 17 | Return the path scale. 18 | 19 | e.g. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
29 | */ 30 | static CGFloat _NSStringPathScale(NSString *string) { 31 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 32 | NSString *name = string.stringByDeletingPathExtension; 33 | __block CGFloat scale = 1; 34 | 35 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 36 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 37 | if (result.range.location >= 3) { 38 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 39 | } 40 | }]; 41 | 42 | return scale; 43 | } 44 | 45 | 46 | 47 | @implementation YYFrameImage { 48 | NSUInteger _loopCount; 49 | NSUInteger _oneFrameBytes; 50 | NSArray *_imagePaths; 51 | NSArray *_imageDatas; 52 | NSArray *_frameDurations; 53 | } 54 | 55 | - (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 56 | NSMutableArray *durations = [NSMutableArray new]; 57 | for (int i = 0, max = (int)paths.count; i < max; i++) { 58 | [durations addObject:@(oneFrameDuration)]; 59 | } 60 | return [self initWithImagePaths:paths frameDurations:durations loopCount:loopCount]; 61 | } 62 | 63 | - (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 64 | if (paths.count == 0) return nil; 65 | if (paths.count != frameDurations.count) return nil; 66 | 67 | NSString *firstPath = paths[0]; 68 | NSData *firstData = [NSData dataWithContentsOfFile:firstPath]; 69 | CGFloat scale = _NSStringPathScale(firstPath); 70 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 71 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 72 | if (!self) return nil; 73 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 74 | _oneFrameBytes = (NSUInteger)frameByte; 75 | _imagePaths = paths.copy; 76 | _frameDurations = frameDurations.copy; 77 | _loopCount = loopCount; 78 | 79 | return self; 80 | } 81 | 82 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 83 | NSMutableArray *durations = [NSMutableArray new]; 84 | for (int i = 0, max = (int)dataArray.count; i < max; i++) { 85 | [durations addObject:@(oneFrameDuration)]; 86 | } 87 | return [self initWithImageDataArray:dataArray frameDurations:durations loopCount:loopCount]; 88 | } 89 | 90 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 91 | if (dataArray.count == 0) return nil; 92 | if (dataArray.count != frameDurations.count) return nil; 93 | 94 | NSData *firstData = dataArray[0]; 95 | CGFloat scale = [UIScreen mainScreen].scale; 96 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 97 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 98 | if (!self) return nil; 99 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 100 | _oneFrameBytes = (NSUInteger)frameByte; 101 | _imageDatas = dataArray.copy; 102 | _frameDurations = frameDurations.copy; 103 | _loopCount = loopCount; 104 | 105 | return self; 106 | } 107 | 108 | #pragma mark - YYAnimtedImage 109 | 110 | - (NSUInteger)animatedImageFrameCount { 111 | if (_imagePaths) { 112 | return _imagePaths.count; 113 | } else if (_imageDatas) { 114 | return _imageDatas.count; 115 | } else { 116 | return 1; 117 | } 118 | } 119 | 120 | - (NSUInteger)animatedImageLoopCount { 121 | return _loopCount; 122 | } 123 | 124 | - (NSUInteger)animatedImageBytesPerFrame { 125 | return _oneFrameBytes; 126 | } 127 | 128 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 129 | if (_imagePaths) { 130 | if (index >= _imagePaths.count) return nil; 131 | NSString *path = _imagePaths[index]; 132 | CGFloat scale = _NSStringPathScale(path); 133 | NSData *data = [NSData dataWithContentsOfFile:path]; 134 | return [[UIImage imageWithData:data scale:scale] yy_imageByDecoded]; 135 | } else if (_imageDatas) { 136 | if (index >= _imageDatas.count) return nil; 137 | NSData *data = _imageDatas[index]; 138 | return [[UIImage imageWithData:data scale:[UIScreen mainScreen].scale] yy_imageByDecoded]; 139 | } else { 140 | return index == 0 ? self : nil; 141 | } 142 | } 143 | 144 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 145 | if (index >= _frameDurations.count) return 0; 146 | NSNumber *num = _frameDurations[index]; 147 | return [num doubleValue]; 148 | } 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYImageVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYImageVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #import 21 | #elif __has_include() 22 | #import 23 | #import 24 | #import 25 | #import 26 | #else 27 | #import "YYFrameImage.h" 28 | #import "YYSpriteSheetImage.h" 29 | #import "YYImageCoder.h" 30 | #import "YYAnimatedImageView.h" 31 | #endif 32 | 33 | NS_ASSUME_NONNULL_BEGIN 34 | 35 | 36 | /** 37 | A YYImage object is a high-level way to display animated image data. 38 | 39 | @discussion It is a fully compatible `UIImage` subclass. It extends the UIImage 40 | to support animated WebP, APNG and GIF format image data decoding. It also 41 | support NSCoding protocol to archive and unarchive multi-frame image data. 42 | 43 | If the image is created from multi-frame image data, and you want to play the 44 | animation, try replace UIImageView with `YYAnimatedImageView`. 45 | 46 | Sample Code: 47 | 48 | // animation@3x.webp 49 | YYImage *image = [YYImage imageNamed:@"animation.webp"]; 50 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 51 | [view addSubView:imageView]; 52 | 53 | */ 54 | @interface YYImage : UIImage 55 | 56 | + (nullable YYImage *)imageNamed:(NSString *)name; // no cache! 57 | + (nullable YYImage *)imageWithContentsOfFile:(NSString *)path; 58 | + (nullable YYImage *)imageWithData:(NSData *)data; 59 | + (nullable YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale; 60 | 61 | /** 62 | If the image is created from data or file, then the value indicates the data type. 63 | */ 64 | @property (nonatomic, readonly) YYImageType animatedImageType; 65 | 66 | /** 67 | If the image is created from animated image data (multi-frame GIF/APNG/WebP), 68 | this property stores the original image data. 69 | */ 70 | @property (nullable, nonatomic, readonly) NSData *animatedImageData; 71 | 72 | /** 73 | The total memory usage (in bytes) if all frame images was loaded into memory. 74 | The value is 0 if the image is not created from a multi-frame image data. 75 | */ 76 | @property (nonatomic, readonly) NSUInteger animatedImageMemorySize; 77 | 78 | /** 79 | Preload all frame image to memory. 80 | 81 | @discussion Set this property to `YES` will block the calling thread to decode 82 | all animation frame image to memory, set to `NO` will release the preloaded frames. 83 | If the image is shared by lots of image views (such as emoticon), preload all 84 | frames will reduce the CPU cost. 85 | 86 | See `animatedImageMemorySize` for memory cost. 87 | */ 88 | @property (nonatomic) BOOL preloadAllAnimatedImageFrames; 89 | 90 | @end 91 | 92 | NS_ASSUME_NONNULL_END 93 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYImage.h" 13 | 14 | /** 15 | An array of NSNumber objects, shows the best order for path scale search. 16 | e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1] 17 | */ 18 | static NSArray *_NSBundlePreferredScales() { 19 | static NSArray *scales; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | CGFloat screenScale = [UIScreen mainScreen].scale; 23 | if (screenScale <= 1) { 24 | scales = @[@1,@2,@3]; 25 | } else if (screenScale <= 2) { 26 | scales = @[@2,@3,@1]; 27 | } else { 28 | scales = @[@3,@2,@1]; 29 | } 30 | }); 31 | return scales; 32 | } 33 | 34 | /** 35 | Add scale modifier to the file name (without path extension), 36 | From @"name" to @"name@2x". 37 | 38 | e.g. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Before After(scale:2)
"icon" "icon@2x"
"icon " "icon @2x"
"icon.top" "icon.top@2x"
"/p/name" "/p/name@2x"
"/path/" "/path/"
47 | 48 | @param scale Resource scale. 49 | @return String by add scale modifier, or just return if it's not end with file name. 50 | */ 51 | static NSString *_NSStringByAppendingNameScale(NSString *string, CGFloat scale) { 52 | if (!string) return nil; 53 | if (fabs(scale - 1) <= __FLT_EPSILON__ || string.length == 0 || [string hasSuffix:@"/"]) return string.copy; 54 | return [string stringByAppendingFormat:@"@%@x", @(scale)]; 55 | } 56 | 57 | /** 58 | Return the path scale. 59 | 60 | e.g. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
70 | */ 71 | static CGFloat _NSStringPathScale(NSString *string) { 72 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 73 | NSString *name = string.stringByDeletingPathExtension; 74 | __block CGFloat scale = 1; 75 | 76 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 77 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 78 | if (result.range.location >= 3) { 79 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 80 | } 81 | }]; 82 | 83 | return scale; 84 | } 85 | 86 | 87 | @implementation YYImage { 88 | YYImageDecoder *_decoder; 89 | NSArray *_preloadedFrames; 90 | dispatch_semaphore_t _preloadedLock; 91 | NSUInteger _bytesPerFrame; 92 | } 93 | 94 | + (YYImage *)imageNamed:(NSString *)name { 95 | if (name.length == 0) return nil; 96 | if ([name hasSuffix:@"/"]) return nil; 97 | 98 | NSString *res = name.stringByDeletingPathExtension; 99 | NSString *ext = name.pathExtension; 100 | NSString *path = nil; 101 | CGFloat scale = 1; 102 | 103 | // If no extension, guess by system supported (same as UIImage). 104 | NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"]; 105 | NSArray *scales = _NSBundlePreferredScales(); 106 | for (int s = 0; s < scales.count; s++) { 107 | scale = ((NSNumber *)scales[s]).floatValue; 108 | NSString *scaledName = _NSStringByAppendingNameScale(res, scale); 109 | for (NSString *e in exts) { 110 | path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e]; 111 | if (path) break; 112 | } 113 | if (path) break; 114 | } 115 | if (path.length == 0) return nil; 116 | 117 | NSData *data = [NSData dataWithContentsOfFile:path]; 118 | if (data.length == 0) return nil; 119 | 120 | return [[self alloc] initWithData:data scale:scale]; 121 | } 122 | 123 | + (YYImage *)imageWithContentsOfFile:(NSString *)path { 124 | return [[self alloc] initWithContentsOfFile:path]; 125 | } 126 | 127 | + (YYImage *)imageWithData:(NSData *)data { 128 | return [[self alloc] initWithData:data]; 129 | } 130 | 131 | + (YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale { 132 | return [[self alloc] initWithData:data scale:scale]; 133 | } 134 | 135 | - (instancetype)initWithContentsOfFile:(NSString *)path { 136 | NSData *data = [NSData dataWithContentsOfFile:path]; 137 | return [self initWithData:data scale:_NSStringPathScale(path)]; 138 | } 139 | 140 | - (instancetype)initWithData:(NSData *)data { 141 | return [self initWithData:data scale:1]; 142 | } 143 | 144 | - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { 145 | if (data.length == 0) return nil; 146 | if (scale <= 0) scale = [UIScreen mainScreen].scale; 147 | _preloadedLock = dispatch_semaphore_create(1); 148 | @autoreleasepool { 149 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; 150 | YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES]; 151 | UIImage *image = frame.image; 152 | if (!image) return nil; 153 | self = [self initWithCGImage:image.CGImage scale:decoder.scale orientation:image.imageOrientation]; 154 | if (!self) return nil; 155 | _animatedImageType = decoder.type; 156 | if (decoder.frameCount > 1) { 157 | _decoder = decoder; 158 | _bytesPerFrame = CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage); 159 | _animatedImageMemorySize = _bytesPerFrame * decoder.frameCount; 160 | } 161 | self.yy_isDecodedForDisplay = YES; 162 | } 163 | return self; 164 | } 165 | 166 | - (NSData *)animatedImageData { 167 | return _decoder.data; 168 | } 169 | 170 | - (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames { 171 | if (_preloadAllAnimatedImageFrames != preloadAllAnimatedImageFrames) { 172 | if (preloadAllAnimatedImageFrames && _decoder.frameCount > 0) { 173 | NSMutableArray *frames = [NSMutableArray new]; 174 | for (NSUInteger i = 0, max = _decoder.frameCount; i < max; i++) { 175 | UIImage *img = [self animatedImageFrameAtIndex:i]; 176 | if (img) { 177 | [frames addObject:img]; 178 | } else { 179 | [frames addObject:[NSNull null]]; 180 | } 181 | } 182 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 183 | _preloadedFrames = frames; 184 | dispatch_semaphore_signal(_preloadedLock); 185 | } else { 186 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 187 | _preloadedFrames = nil; 188 | dispatch_semaphore_signal(_preloadedLock); 189 | } 190 | } 191 | } 192 | 193 | #pragma mark - protocol NSCoding 194 | 195 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 196 | NSNumber *scale = [aDecoder decodeObjectForKey:@"YYImageScale"]; 197 | NSData *data = [aDecoder decodeObjectForKey:@"YYImageData"]; 198 | if (data.length) { 199 | self = [self initWithData:data scale:scale.doubleValue]; 200 | } else { 201 | self = [super initWithCoder:aDecoder]; 202 | } 203 | return self; 204 | } 205 | 206 | - (void)encodeWithCoder:(NSCoder *)aCoder { 207 | if (_decoder.data.length) { 208 | [aCoder encodeObject:@(self.scale) forKey:@"YYImageScale"]; 209 | [aCoder encodeObject:_decoder.data forKey:@"YYImageData"]; 210 | } else { 211 | [super encodeWithCoder:aCoder]; // Apple use UIImagePNGRepresentation() to encode UIImage. 212 | } 213 | } 214 | 215 | #pragma mark - protocol YYAnimatedImage 216 | 217 | - (NSUInteger)animatedImageFrameCount { 218 | return _decoder.frameCount; 219 | } 220 | 221 | - (NSUInteger)animatedImageLoopCount { 222 | return _decoder.loopCount; 223 | } 224 | 225 | - (NSUInteger)animatedImageBytesPerFrame { 226 | return _bytesPerFrame; 227 | } 228 | 229 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 230 | if (index >= _decoder.frameCount) return nil; 231 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 232 | UIImage *image = _preloadedFrames[index]; 233 | dispatch_semaphore_signal(_preloadedLock); 234 | if (image) return image == (id)[NSNull null] ? nil : image; 235 | return [_decoder frameAtIndex:index decodeForDisplay:YES].image; 236 | } 237 | 238 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 239 | NSTimeInterval duration = [_decoder frameDurationAtIndex:index]; 240 | 241 | /* 242 | http://opensource.apple.com/source/WebCore/WebCore-7600.1.25/platform/graphics/cg/ImageSourceCG.cpp 243 | Many annoying ads specify a 0 duration to make an image flash as quickly as 244 | possible. We follow Safari and Firefox's behavior and use a duration of 100 ms 245 | for any frames that specify a duration of <= 10 ms. 246 | See and for more information. 247 | 248 | See also: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser. 249 | */ 250 | if (duration < 0.011f) return 0.100f; 251 | return duration; 252 | } 253 | 254 | @end 255 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYSpriteSheetImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display sprite sheet animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | The animation can be played by YYAnimatedImageView. 29 | 30 | Sample Code: 31 | 32 | // 8 * 12 sprites in a single sheet image 33 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"]; 34 | NSMutableArray *contentRects = [NSMutableArray new]; 35 | NSMutableArray *durations = [NSMutableArray new]; 36 | for (int j = 0; j < 12; j++) { 37 | for (int i = 0; i < 8; i++) { 38 | CGRect rect; 39 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 40 | rect.origin.x = img.size.width / 8 * i; 41 | rect.origin.y = img.size.height / 12 * j; 42 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 43 | [durations addObject:@(1 / 60.0)]; 44 | } 45 | } 46 | YYSpriteSheetImage *sprite; 47 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img 48 | contentRects:contentRects 49 | frameDurations:durations 50 | loopCount:0]; 51 | YYAnimatedImageView *imgView = [YYAnimatedImageView new]; 52 | imgView.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 53 | imgView.image = sprite; 54 | 55 | 56 | 57 | @discussion It can also be used to display single frame in sprite sheet image. 58 | Sample Code: 59 | 60 | YYSpriteSheetImage *sheet = ...; 61 | UIImageView *imageView = ...; 62 | imageView.image = sheet; 63 | imageView.layer.contentsRect = [sheet contentsRectForCALayerAtIndex:6]; 64 | 65 | */ 66 | @interface YYSpriteSheetImage : UIImage 67 | 68 | /** 69 | Creates and returns an image object. 70 | 71 | @param image The sprite sheet image (contains all frames). 72 | 73 | @param contentRects The sprite sheet image frame rects in the image coordinates. 74 | The rectangle should not outside the image's bounds. The objects in this array 75 | should be created with [NSValue valueWithCGRect:]. 76 | 77 | @param frameDurations The sprite sheet image frame's durations in seconds. 78 | The objects in this array should be NSNumber. 79 | 80 | @param loopCount Animation loop count, 0 means infinite looping. 81 | 82 | @return An image object, or nil if an error occurs. 83 | */ 84 | - (nullable instancetype)initWithSpriteSheetImage:(UIImage *)image 85 | contentRects:(NSArray *)contentRects 86 | frameDurations:(NSArray *)frameDurations 87 | loopCount:(NSUInteger)loopCount; 88 | 89 | @property (nonatomic, readonly) NSArray *contentRects; 90 | @property (nonatomic, readonly) NSArray *frameDurations; 91 | @property (nonatomic, readonly) NSUInteger loopCount; 92 | 93 | /** 94 | Get the contents rect for CALayer. 95 | See "contentsRect" property in CALayer for more information. 96 | 97 | @param index Index of frame. 98 | @return Contents Rect. 99 | */ 100 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index; 101 | 102 | @end 103 | 104 | NS_ASSUME_NONNULL_END 105 | -------------------------------------------------------------------------------- /Pods/YYImage/YYImage/YYSpriteSheetImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYSpriteSheetImage.h" 13 | 14 | @implementation YYSpriteSheetImage 15 | 16 | - (instancetype)initWithSpriteSheetImage:(UIImage *)image 17 | contentRects:(NSArray *)contentRects 18 | frameDurations:(NSArray *)frameDurations 19 | loopCount:(NSUInteger)loopCount { 20 | if (!image.CGImage) return nil; 21 | if (contentRects.count < 1 || frameDurations.count < 1) return nil; 22 | if (contentRects.count != frameDurations.count) return nil; 23 | 24 | self = [super initWithCGImage:image.CGImage scale:image.scale orientation:image.imageOrientation]; 25 | if (!self) return nil; 26 | 27 | _contentRects = contentRects.copy; 28 | _frameDurations = frameDurations.copy; 29 | _loopCount = loopCount; 30 | return self; 31 | } 32 | 33 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index { 34 | CGRect layerRect = CGRectMake(0, 0, 1, 1); 35 | if (index >= _contentRects.count) return layerRect; 36 | 37 | CGSize imageSize = self.size; 38 | CGRect rect = [self animatedImageContentsRectAtIndex:index]; 39 | if (imageSize.width > 0.01 && imageSize.height > 0.01) { 40 | layerRect.origin.x = rect.origin.x / imageSize.width; 41 | layerRect.origin.y = rect.origin.y / imageSize.height; 42 | layerRect.size.width = rect.size.width / imageSize.width; 43 | layerRect.size.height = rect.size.height / imageSize.height; 44 | layerRect = CGRectIntersection(layerRect, CGRectMake(0, 0, 1, 1)); 45 | if (CGRectIsNull(layerRect) || CGRectIsEmpty(layerRect)) { 46 | layerRect = CGRectMake(0, 0, 1, 1); 47 | } 48 | } 49 | return layerRect; 50 | } 51 | 52 | #pragma mark @protocol YYAnimatedImage 53 | 54 | - (NSUInteger)animatedImageFrameCount { 55 | return _contentRects.count; 56 | } 57 | 58 | - (NSUInteger)animatedImageLoopCount { 59 | return _loopCount; 60 | } 61 | 62 | - (NSUInteger)animatedImageBytesPerFrame { 63 | return 0; 64 | } 65 | 66 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 67 | return self; 68 | } 69 | 70 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 71 | if (index >= _frameDurations.count) return 0; 72 | return ((NSNumber *)_frameDurations[index]).doubleValue; 73 | } 74 | 75 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index { 76 | if (index >= _contentRects.count) return CGRectZero; 77 | return ((NSValue *)_contentRects[index]).CGRectValue; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Pods/YYText/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ibireme 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 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextContainerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextContainerView.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYTextLayout.h" 18 | #endif 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /** 23 | A simple view to diaplay `YYTextLayout`. 24 | 25 | @discussion This view can become first responder. If this view is first responder, 26 | all the action (such as UIMenu's action) would forward to the `hostView` property. 27 | Typically, you should not use this class directly. 28 | 29 | @warning All the methods in this class should be called on main thread. 30 | */ 31 | @interface YYTextContainerView : UIView 32 | 33 | /// First responder's aciton will forward to this view. 34 | @property (nullable, nonatomic, weak) UIView *hostView; 35 | 36 | /// Debug option for layout debug. Set this property will let the view redraw it's contents. 37 | @property (nullable, nonatomic, copy) YYTextDebugOption *debugOption; 38 | 39 | /// Text vertical alignment. 40 | @property (nonatomic) YYTextVerticalAlignment textVerticalAlignment; 41 | 42 | /// Text layout. Set this property will let the view redraw it's contents. 43 | @property (nullable, nonatomic, strong) YYTextLayout *layout; 44 | 45 | /// The contents fade animation duration when the layout's contents changed. Default is 0 (no animation). 46 | @property (nonatomic) NSTimeInterval contentsFadeDuration; 47 | 48 | /// Convenience method to set `layout` and `contentsFadeDuration`. 49 | /// @param layout Same as `layout` property. 50 | /// @param fadeDuration Same as `contentsFadeDuration` property. 51 | - (void)setLayout:(nullable YYTextLayout *)layout withFadeDuration:(NSTimeInterval)fadeDuration; 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextContainerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextContainerView.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextContainerView.h" 13 | 14 | @implementation YYTextContainerView { 15 | BOOL _attachmentChanged; 16 | NSMutableArray *_attachmentViews; 17 | NSMutableArray *_attachmentLayers; 18 | } 19 | 20 | - (instancetype)initWithFrame:(CGRect)frame { 21 | self = [super initWithFrame:frame]; 22 | if (!self) return nil; 23 | self.backgroundColor = [UIColor clearColor]; 24 | _attachmentViews = [NSMutableArray array]; 25 | _attachmentLayers = [NSMutableArray array]; 26 | return self; 27 | } 28 | 29 | - (void)setDebugOption:(YYTextDebugOption *)debugOption { 30 | BOOL needDraw = _debugOption.needDrawDebug; 31 | _debugOption = debugOption.copy; 32 | if (_debugOption.needDrawDebug != needDraw) { 33 | [self setNeedsDisplay]; 34 | } 35 | } 36 | 37 | - (void)setTextVerticalAlignment:(YYTextVerticalAlignment)textVerticalAlignment { 38 | if (_textVerticalAlignment == textVerticalAlignment) return; 39 | _textVerticalAlignment = textVerticalAlignment; 40 | [self setNeedsDisplay]; 41 | } 42 | 43 | - (void)setContentsFadeDuration:(NSTimeInterval)contentsFadeDuration { 44 | if (_contentsFadeDuration == contentsFadeDuration) return; 45 | _contentsFadeDuration = contentsFadeDuration; 46 | if (contentsFadeDuration <= 0) { 47 | [self.layer removeAnimationForKey:@"contents"]; 48 | } 49 | } 50 | 51 | - (void)setLayout:(YYTextLayout *)layout { 52 | if (_layout == layout) return; 53 | _layout = layout; 54 | _attachmentChanged = YES; 55 | [self setNeedsDisplay]; 56 | } 57 | 58 | - (void)setLayout:(YYTextLayout *)layout withFadeDuration:(NSTimeInterval)fadeDuration { 59 | self.contentsFadeDuration = fadeDuration; 60 | self.layout = layout; 61 | } 62 | 63 | - (void)drawRect:(CGRect)rect { 64 | // fade content 65 | [self.layer removeAnimationForKey:@"contents"]; 66 | if (_contentsFadeDuration > 0) { 67 | CATransition *transition = [CATransition animation]; 68 | transition.duration = _contentsFadeDuration; 69 | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 70 | transition.type = kCATransitionFade; 71 | [self.layer addAnimation:transition forKey:@"contents"]; 72 | } 73 | 74 | // update attachment 75 | if (_attachmentChanged) { 76 | for (UIView *view in _attachmentViews) { 77 | if (view.superview == self) [view removeFromSuperview]; 78 | } 79 | for (CALayer *layer in _attachmentLayers) { 80 | if (layer.superlayer == self.layer) [layer removeFromSuperlayer]; 81 | } 82 | [_attachmentViews removeAllObjects]; 83 | [_attachmentLayers removeAllObjects]; 84 | } 85 | 86 | // draw layout 87 | CGSize boundingSize = _layout.textBoundingSize; 88 | CGPoint point = CGPointZero; 89 | if (_textVerticalAlignment == YYTextVerticalAlignmentCenter) { 90 | if (_layout.container.isVerticalForm) { 91 | point.x = -(self.bounds.size.width - boundingSize.width) * 0.5; 92 | } else { 93 | point.y = (self.bounds.size.height - boundingSize.height) * 0.5; 94 | } 95 | } else if (_textVerticalAlignment == YYTextVerticalAlignmentBottom) { 96 | if (_layout.container.isVerticalForm) { 97 | point.x = -(self.bounds.size.width - boundingSize.width); 98 | } else { 99 | point.y = (self.bounds.size.height - boundingSize.height); 100 | } 101 | } 102 | [_layout drawInContext:UIGraphicsGetCurrentContext() size:self.bounds.size point:point view:self layer:self.layer debug:_debugOption cancel:nil]; 103 | 104 | // update attachment 105 | if (_attachmentChanged) { 106 | _attachmentChanged = NO; 107 | for (YYTextAttachment *a in _layout.attachments) { 108 | if ([a.content isKindOfClass:[UIView class]]) [_attachmentViews addObject:a.content]; 109 | if ([a.content isKindOfClass:[CALayer class]]) [_attachmentLayers addObject:a.content]; 110 | } 111 | } 112 | } 113 | 114 | - (void)setFrame:(CGRect)frame { 115 | CGSize oldSize = self.bounds.size; 116 | [super setFrame:frame]; 117 | if (!CGSizeEqualToSize(oldSize, self.bounds.size)) { 118 | [self setNeedsLayout]; 119 | } 120 | } 121 | 122 | - (void)setBounds:(CGRect)bounds { 123 | CGSize oldSize = self.bounds.size; 124 | [super setBounds:bounds]; 125 | if (!CGSizeEqualToSize(oldSize, self.bounds.size)) { 126 | [self setNeedsLayout]; 127 | } 128 | } 129 | 130 | #pragma mark - UIResponder forward 131 | 132 | - (BOOL)canBecomeFirstResponder { 133 | return YES; 134 | } 135 | 136 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 137 | return [self.hostView canPerformAction:action withSender:sender]; 138 | } 139 | 140 | - (id)forwardingTargetForSelector:(SEL)aSelector { 141 | return self.hostView; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextDebugOption.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextDebugOption.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/8. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | @class YYTextDebugOption; 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | /** 19 | The YYTextDebugTarget protocol defines the method a debug target should implement. 20 | A debug target can be add to the global container to receive the shared debug 21 | option changed notification. 22 | */ 23 | @protocol YYTextDebugTarget 24 | 25 | @required 26 | /** 27 | When the shared debug option changed, this method would be called on main thread. 28 | It should return as quickly as possible. The option's property should not be changed 29 | in this method. 30 | 31 | @param option The shared debug option. 32 | */ 33 | - (void)setDebugOption:(nullable YYTextDebugOption *)option; 34 | @end 35 | 36 | 37 | 38 | /** 39 | The debug option for YYText. 40 | */ 41 | @interface YYTextDebugOption : NSObject 42 | @property (nullable, nonatomic, strong) UIColor *baselineColor; ///< baseline color 43 | @property (nullable, nonatomic, strong) UIColor *CTFrameBorderColor; ///< CTFrame path border color 44 | @property (nullable, nonatomic, strong) UIColor *CTFrameFillColor; ///< CTFrame path fill color 45 | @property (nullable, nonatomic, strong) UIColor *CTLineBorderColor; ///< CTLine bounds border color 46 | @property (nullable, nonatomic, strong) UIColor *CTLineFillColor; ///< CTLine bounds fill color 47 | @property (nullable, nonatomic, strong) UIColor *CTLineNumberColor; ///< CTLine line number color 48 | @property (nullable, nonatomic, strong) UIColor *CTRunBorderColor; ///< CTRun bounds border color 49 | @property (nullable, nonatomic, strong) UIColor *CTRunFillColor; ///< CTRun bounds fill color 50 | @property (nullable, nonatomic, strong) UIColor *CTRunNumberColor; ///< CTRun number color 51 | @property (nullable, nonatomic, strong) UIColor *CGGlyphBorderColor; ///< CGGlyph bounds border color 52 | @property (nullable, nonatomic, strong) UIColor *CGGlyphFillColor; ///< CGGlyph bounds fill color 53 | 54 | - (BOOL)needDrawDebug; ///< `YES`: at least one debug color is visible. `NO`: all debug color is invisible/nil. 55 | - (void)clear; ///< Set all debug color to nil. 56 | 57 | /** 58 | Add a debug target. 59 | 60 | @discussion When `setSharedDebugOption:` is called, all added debug target will 61 | receive `setDebugOption:` in main thread. It maintains an unsafe_unretained 62 | reference to this target. The target must to removed before dealloc. 63 | 64 | @param target A debug target. 65 | */ 66 | + (void)addDebugTarget:(id)target; 67 | 68 | /** 69 | Remove a debug target which is added by `addDebugTarget:`. 70 | 71 | @param target A debug target. 72 | */ 73 | + (void)removeDebugTarget:(id)target; 74 | 75 | /** 76 | Returns the shared debug option. 77 | 78 | @return The shared debug option, default is nil. 79 | */ 80 | + (nullable YYTextDebugOption *)sharedDebugOption; 81 | 82 | /** 83 | Set a debug option as shared debug option. 84 | This method must be called on main thread. 85 | 86 | @discussion When call this method, the new option will set to all debug target 87 | which is added by `addDebugTarget:`. 88 | 89 | @param option A new debug option (nil is valid). 90 | */ 91 | + (void)setSharedDebugOption:(nullable YYTextDebugOption *)option; 92 | 93 | @end 94 | 95 | NS_ASSUME_NONNULL_END 96 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextDebugOption.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextDebugOption.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/8. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextDebugOption.h" 13 | #import "YYTextWeakProxy.h" 14 | #import 15 | #import 16 | 17 | static pthread_mutex_t _sharedDebugLock; 18 | static CFMutableSetRef _sharedDebugTargets = nil; 19 | static YYTextDebugOption *_sharedDebugOption = nil; 20 | 21 | static const void* _sharedDebugSetRetain(CFAllocatorRef allocator, const void *value) { 22 | return value; 23 | } 24 | 25 | static void _sharedDebugSetRelease(CFAllocatorRef allocator, const void *value) { 26 | } 27 | 28 | void _sharedDebugSetFunction(const void *value, void *context) { 29 | id target = (__bridge id)(value); 30 | [target setDebugOption:_sharedDebugOption]; 31 | } 32 | 33 | static void _initSharedDebug() { 34 | static dispatch_once_t onceToken; 35 | dispatch_once(&onceToken, ^{ 36 | pthread_mutex_init(&_sharedDebugLock, NULL); 37 | CFSetCallBacks callbacks = kCFTypeSetCallBacks; 38 | callbacks.retain = _sharedDebugSetRetain; 39 | callbacks.release = _sharedDebugSetRelease; 40 | _sharedDebugTargets = CFSetCreateMutable(CFAllocatorGetDefault(), 0, &callbacks); 41 | }); 42 | } 43 | 44 | static void _setSharedDebugOption(YYTextDebugOption *option) { 45 | _initSharedDebug(); 46 | pthread_mutex_lock(&_sharedDebugLock); 47 | _sharedDebugOption = option.copy; 48 | CFSetApplyFunction(_sharedDebugTargets, _sharedDebugSetFunction, NULL); 49 | pthread_mutex_unlock(&_sharedDebugLock); 50 | } 51 | 52 | static YYTextDebugOption *_getSharedDebugOption() { 53 | _initSharedDebug(); 54 | pthread_mutex_lock(&_sharedDebugLock); 55 | YYTextDebugOption *op = _sharedDebugOption; 56 | pthread_mutex_unlock(&_sharedDebugLock); 57 | return op; 58 | } 59 | 60 | static void _addDebugTarget(id target) { 61 | _initSharedDebug(); 62 | pthread_mutex_lock(&_sharedDebugLock); 63 | CFSetAddValue(_sharedDebugTargets, (__bridge const void *)(target)); 64 | pthread_mutex_unlock(&_sharedDebugLock); 65 | } 66 | 67 | static void _removeDebugTarget(id target) { 68 | _initSharedDebug(); 69 | pthread_mutex_lock(&_sharedDebugLock); 70 | CFSetRemoveValue(_sharedDebugTargets, (__bridge const void *)(target)); 71 | pthread_mutex_unlock(&_sharedDebugLock); 72 | } 73 | 74 | 75 | @implementation YYTextDebugOption 76 | 77 | - (id)copyWithZone:(NSZone *)zone { 78 | YYTextDebugOption *op = [self.class new]; 79 | op.baselineColor = self.baselineColor; 80 | op.CTFrameBorderColor = self.CTFrameBorderColor; 81 | op.CTFrameFillColor = self.CTFrameFillColor; 82 | op.CTLineBorderColor = self.CTLineBorderColor; 83 | op.CTLineFillColor = self.CTLineFillColor; 84 | op.CTLineNumberColor = self.CTLineNumberColor; 85 | op.CTRunBorderColor = self.CTRunBorderColor; 86 | op.CTRunFillColor = self.CTRunFillColor; 87 | op.CTRunNumberColor = self.CTRunNumberColor; 88 | op.CGGlyphBorderColor = self.CGGlyphBorderColor; 89 | op.CGGlyphFillColor = self.CGGlyphFillColor; 90 | return op; 91 | } 92 | 93 | - (BOOL)needDrawDebug { 94 | if (self.baselineColor || 95 | self.CTFrameBorderColor || 96 | self.CTFrameFillColor || 97 | self.CTLineBorderColor || 98 | self.CTLineFillColor || 99 | self.CTLineNumberColor || 100 | self.CTRunBorderColor || 101 | self.CTRunFillColor || 102 | self.CTRunNumberColor || 103 | self.CGGlyphBorderColor || 104 | self.CGGlyphFillColor) return YES; 105 | return NO; 106 | } 107 | 108 | - (void)clear { 109 | self.baselineColor = nil; 110 | self.CTFrameBorderColor = nil; 111 | self.CTFrameFillColor = nil; 112 | self.CTLineBorderColor = nil; 113 | self.CTLineFillColor = nil; 114 | self.CTLineNumberColor = nil; 115 | self.CTRunBorderColor = nil; 116 | self.CTRunFillColor = nil; 117 | self.CTRunNumberColor = nil; 118 | self.CGGlyphBorderColor = nil; 119 | self.CGGlyphFillColor = nil; 120 | } 121 | 122 | + (void)addDebugTarget:(id)target { 123 | if (target) _addDebugTarget(target); 124 | } 125 | 126 | + (void)removeDebugTarget:(id)target { 127 | if (target) _removeDebugTarget(target); 128 | } 129 | 130 | + (YYTextDebugOption *)sharedDebugOption { 131 | return _getSharedDebugOption(); 132 | } 133 | 134 | + (void)setSharedDebugOption:(YYTextDebugOption *)option { 135 | NSAssert([NSThread isMainThread], @"This method must be called on the main thread"); 136 | _setSharedDebugOption(option); 137 | } 138 | 139 | @end 140 | 141 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextEffectWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextEffectWindow.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/2/25. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #import 17 | #else 18 | #import "YYTextMagnifier.h" 19 | #import "YYTextSelectionView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | A window to display magnifier and extra contents for text view. 26 | 27 | @discussion Use `sharedWindow` to get the instance, don't create your own instance. 28 | Typically, you should not use this class directly. 29 | */ 30 | @interface YYTextEffectWindow : UIWindow 31 | 32 | /// Returns the shared instance (returns nil in App Extension). 33 | + (nullable instancetype)sharedWindow; 34 | 35 | /// Show the magnifier in this window with a 'popup' animation. @param mag A magnifier. 36 | - (void)showMagnifier:(YYTextMagnifier *)mag; 37 | /// Update the magnifier content and position. @param mag A magnifier. 38 | - (void)moveMagnifier:(YYTextMagnifier *)mag; 39 | /// Remove the magnifier from this window with a 'shrink' animation. @param mag A magnifier. 40 | - (void)hideMagnifier:(YYTextMagnifier *)mag; 41 | 42 | 43 | /// Show the selection dot in this window if the dot is clipped by the selection view. 44 | /// @param selection A selection view. 45 | - (void)showSelectionDot:(YYTextSelectionView *)selection; 46 | /// Remove the selection dot from this window. 47 | /// @param selection A selection view. 48 | - (void)hideSelectionDot:(YYTextSelectionView *)selection; 49 | 50 | @end 51 | 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextInput.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextInput.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/17. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Text position affinity. For example, the offset appears after the last 18 | character on a line is backward affinity, before the first character on 19 | the following line is forward affinity. 20 | */ 21 | typedef NS_ENUM(NSInteger, YYTextAffinity) { 22 | YYTextAffinityForward = 0, ///< offset appears before the character 23 | YYTextAffinityBackward = 1, ///< offset appears after the character 24 | }; 25 | 26 | 27 | /** 28 | A YYTextPosition object represents a position in a text container; in other words, 29 | it is an index into the backing string in a text-displaying view. 30 | 31 | YYTextPosition has the same API as Apple's implementation in UITextView/UITextField, 32 | so you can alse use it to interact with UITextView/UITextField. 33 | */ 34 | @interface YYTextPosition : UITextPosition 35 | 36 | @property (nonatomic, readonly) NSInteger offset; 37 | @property (nonatomic, readonly) YYTextAffinity affinity; 38 | 39 | + (instancetype)positionWithOffset:(NSInteger)offset; 40 | + (instancetype)positionWithOffset:(NSInteger)offset affinity:(YYTextAffinity) affinity; 41 | 42 | - (NSComparisonResult)compare:(id)otherPosition; 43 | 44 | @end 45 | 46 | 47 | /** 48 | A YYTextRange object represents a range of characters in a text container; in other words, 49 | it identifies a starting index and an ending index in string backing a text-displaying view. 50 | 51 | YYTextRange has the same API as Apple's implementation in UITextView/UITextField, 52 | so you can alse use it to interact with UITextView/UITextField. 53 | */ 54 | @interface YYTextRange : UITextRange 55 | 56 | @property (nonatomic, readonly) YYTextPosition *start; 57 | @property (nonatomic, readonly) YYTextPosition *end; 58 | @property (nonatomic, readonly, getter=isEmpty) BOOL empty; 59 | 60 | + (instancetype)rangeWithRange:(NSRange)range; 61 | + (instancetype)rangeWithRange:(NSRange)range affinity:(YYTextAffinity) affinity; 62 | + (instancetype)rangeWithStart:(YYTextPosition *)start end:(YYTextPosition *)end; 63 | + (instancetype)defaultRange; ///< <{0,0} Forward> 64 | 65 | - (NSRange)asRange; 66 | 67 | @end 68 | 69 | 70 | /** 71 | A YYTextSelectionRect object encapsulates information about a selected range of 72 | text in a text-displaying view. 73 | 74 | YYTextSelectionRect has the same API as Apple's implementation in UITextView/UITextField, 75 | so you can alse use it to interact with UITextView/UITextField. 76 | */ 77 | @interface YYTextSelectionRect : UITextSelectionRect 78 | 79 | @property (nonatomic, readwrite) CGRect rect; 80 | @property (nonatomic, readwrite) UITextWritingDirection writingDirection; 81 | @property (nonatomic, readwrite) BOOL containsStart; 82 | @property (nonatomic, readwrite) BOOL containsEnd; 83 | @property (nonatomic, readwrite) BOOL isVertical; 84 | 85 | @end 86 | 87 | NS_ASSUME_NONNULL_END 88 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextInput.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextInput.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/17. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextInput.h" 13 | #import "YYTextUtilities.h" 14 | 15 | 16 | @implementation YYTextPosition 17 | 18 | + (instancetype)positionWithOffset:(NSInteger)offset { 19 | return [self positionWithOffset:offset affinity:YYTextAffinityForward]; 20 | } 21 | 22 | + (instancetype)positionWithOffset:(NSInteger)offset affinity:(YYTextAffinity)affinity { 23 | YYTextPosition *p = [self new]; 24 | p->_offset = offset; 25 | p->_affinity = affinity; 26 | return p; 27 | } 28 | 29 | - (instancetype)copyWithZone:(NSZone *)zone { 30 | return [self.class positionWithOffset:_offset affinity:_affinity]; 31 | } 32 | 33 | - (NSString *)description { 34 | return [NSString stringWithFormat:@"<%@: %p> (%@%@)", self.class, self, @(_offset), _affinity == YYTextAffinityForward ? @"F":@"B"]; 35 | } 36 | 37 | - (NSUInteger)hash { 38 | return _offset * 2 + (_affinity == YYTextAffinityForward ? 1 : 0); 39 | } 40 | 41 | - (BOOL)isEqual:(YYTextPosition *)object { 42 | if (!object) return NO; 43 | return _offset == object.offset && _affinity == object.affinity; 44 | } 45 | 46 | - (NSComparisonResult)compare:(YYTextPosition *)otherPosition { 47 | if (!otherPosition) return NSOrderedAscending; 48 | if (_offset < otherPosition.offset) return NSOrderedAscending; 49 | if (_offset > otherPosition.offset) return NSOrderedDescending; 50 | if (_affinity == YYTextAffinityBackward && otherPosition.affinity == YYTextAffinityForward) return NSOrderedAscending; 51 | if (_affinity == YYTextAffinityForward && otherPosition.affinity == YYTextAffinityBackward) return NSOrderedDescending; 52 | return NSOrderedSame; 53 | } 54 | 55 | @end 56 | 57 | 58 | 59 | @implementation YYTextRange { 60 | YYTextPosition *_start; 61 | YYTextPosition *_end; 62 | } 63 | 64 | - (instancetype)init { 65 | self = [super init]; 66 | if (!self) return nil; 67 | _start = [YYTextPosition positionWithOffset:0]; 68 | _end = [YYTextPosition positionWithOffset:0]; 69 | return self; 70 | } 71 | 72 | - (YYTextPosition *)start { 73 | return _start; 74 | } 75 | 76 | - (YYTextPosition *)end { 77 | return _end; 78 | } 79 | 80 | - (BOOL)isEmpty { 81 | return _start.offset == _end.offset; 82 | } 83 | 84 | - (NSRange)asRange { 85 | return NSMakeRange(_start.offset, _end.offset - _start.offset); 86 | } 87 | 88 | + (instancetype)rangeWithRange:(NSRange)range { 89 | return [self rangeWithRange:range affinity:YYTextAffinityForward]; 90 | } 91 | 92 | + (instancetype)rangeWithRange:(NSRange)range affinity:(YYTextAffinity)affinity { 93 | YYTextPosition *start = [YYTextPosition positionWithOffset:range.location affinity:affinity]; 94 | YYTextPosition *end = [YYTextPosition positionWithOffset:range.location + range.length affinity:affinity]; 95 | return [self rangeWithStart:start end:end]; 96 | } 97 | 98 | + (instancetype)rangeWithStart:(YYTextPosition *)start end:(YYTextPosition *)end { 99 | if (!start || !end) return nil; 100 | if ([start compare:end] == NSOrderedDescending) { 101 | YYTEXT_SWAP(start, end); 102 | } 103 | YYTextRange *range = [YYTextRange new]; 104 | range->_start = start; 105 | range->_end = end; 106 | return range; 107 | } 108 | 109 | + (instancetype)defaultRange { 110 | return [self new]; 111 | } 112 | 113 | - (instancetype)copyWithZone:(NSZone *)zone { 114 | return [self.class rangeWithStart:_start end:_end]; 115 | } 116 | 117 | - (NSString *)description { 118 | return [NSString stringWithFormat:@"<%@: %p> (%@, %@)%@", self.class, self, @(_start.offset), @(_end.offset - _start.offset), _end.affinity == YYTextAffinityForward ? @"F":@"B"]; 119 | } 120 | 121 | - (NSUInteger)hash { 122 | return (sizeof(NSUInteger) == 8 ? OSSwapInt64(_start.hash) : OSSwapInt32(_start.hash)) + _end.hash; 123 | } 124 | 125 | - (BOOL)isEqual:(YYTextRange *)object { 126 | if (!object) return NO; 127 | return [_start isEqual:object.start] && [_end isEqual:object.end]; 128 | } 129 | 130 | @end 131 | 132 | 133 | 134 | @implementation YYTextSelectionRect 135 | 136 | @synthesize rect = _rect; 137 | @synthesize writingDirection = _writingDirection; 138 | @synthesize containsStart = _containsStart; 139 | @synthesize containsEnd = _containsEnd; 140 | @synthesize isVertical = _isVertical; 141 | 142 | - (id)copyWithZone:(NSZone *)zone { 143 | YYTextSelectionRect *one = [self.class new]; 144 | one.rect = _rect; 145 | one.writingDirection = _writingDirection; 146 | one.containsStart = _containsStart; 147 | one.containsEnd = _containsEnd; 148 | one.isVertical = _isVertical; 149 | return one; 150 | } 151 | 152 | @end 153 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextKeyboardManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextKeyboardManager.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/6/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | System keyboard transition information. 18 | Use -[YYTextKeyboardManager convertRect:toView:] to convert frame to specified view. 19 | */ 20 | typedef struct { 21 | BOOL fromVisible; ///< Keyboard visible before transition. 22 | BOOL toVisible; ///< Keyboard visible after transition. 23 | CGRect fromFrame; ///< Keyboard frame before transition. 24 | CGRect toFrame; ///< Keyboard frame after transition. 25 | NSTimeInterval animationDuration; ///< Keyboard transition animation duration. 26 | UIViewAnimationCurve animationCurve; ///< Keyboard transition animation curve. 27 | UIViewAnimationOptions animationOption; ///< Keybaord transition animation option. 28 | } YYTextKeyboardTransition; 29 | 30 | 31 | /** 32 | The YYTextKeyboardObserver protocol defines the method you can use 33 | to receive system keyboard change information. 34 | */ 35 | @protocol YYTextKeyboardObserver 36 | @optional 37 | - (void)keyboardChangedWithTransition:(YYTextKeyboardTransition)transition; 38 | @end 39 | 40 | 41 | /** 42 | A YYTextKeyboardManager object lets you get the system keyboard information, 43 | and track the keyboard visible/frame/transition. 44 | 45 | @discussion You should access this class in main thread. 46 | Compatible: iPhone/iPad with iOS6/7/8/9. 47 | */ 48 | @interface YYTextKeyboardManager : NSObject 49 | 50 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 51 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 52 | 53 | /// Get the default manager (returns nil in App Extension). 54 | + (nullable instancetype)defaultManager; 55 | 56 | /// Get the keyboard window. nil if there's no keyboard window. 57 | @property (nullable, nonatomic, readonly) UIWindow *keyboardWindow; 58 | 59 | /// Get the keyboard view. nil if there's no keyboard view. 60 | @property (nullable, nonatomic, readonly) UIView *keyboardView; 61 | 62 | /// Whether the keyboard is visible. 63 | @property (nonatomic, readonly, getter=isKeyboardVisible) BOOL keyboardVisible; 64 | 65 | /// Get the keyboard frame. CGRectNull if there's no keyboard view. 66 | /// Use convertRect:toView: to convert frame to specified view. 67 | @property (nonatomic, readonly) CGRect keyboardFrame; 68 | 69 | 70 | /** 71 | Add an observer to manager to get keyboard change information. 72 | This method makes a weak reference to the observer. 73 | 74 | @param observer An observer. 75 | This method will do nothing if the observer is nil, or already added. 76 | */ 77 | - (void)addObserver:(id)observer; 78 | 79 | /** 80 | Remove an observer from manager. 81 | 82 | @param observer An observer. 83 | This method will do nothing if the observer is nil, or not in manager. 84 | */ 85 | - (void)removeObserver:(id)observer; 86 | 87 | /** 88 | Convert rect to specified view or window. 89 | 90 | @param rect The frame rect. 91 | @param view A specified view or window (pass nil to convert for main window). 92 | @return The converted rect in specifeid view. 93 | */ 94 | - (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view; 95 | 96 | @end 97 | 98 | NS_ASSUME_NONNULL_END 99 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextLine.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/3/10. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | #if __has_include() 16 | #import 17 | #else 18 | #import "YYTextAttribute.h" 19 | #endif 20 | 21 | @class YYTextRunGlyphRange; 22 | 23 | NS_ASSUME_NONNULL_BEGIN 24 | 25 | /** 26 | A text line object wrapped `CTLineRef`, see `YYTextLayout` for more. 27 | */ 28 | @interface YYTextLine : NSObject 29 | 30 | + (instancetype)lineWithCTLine:(CTLineRef)CTLine position:(CGPoint)position vertical:(BOOL)isVertical; 31 | 32 | @property (nonatomic) NSUInteger index; ///< line index 33 | @property (nonatomic) NSUInteger row; ///< line row 34 | @property (nullable, nonatomic, strong) NSArray *> *verticalRotateRange; ///< Run rotate range 35 | 36 | @property (nonatomic, readonly) CTLineRef CTLine; ///< CoreText line 37 | @property (nonatomic, readonly) NSRange range; ///< string range 38 | @property (nonatomic, readonly) BOOL vertical; ///< vertical form 39 | 40 | @property (nonatomic, readonly) CGRect bounds; ///< bounds (ascent + descent) 41 | @property (nonatomic, readonly) CGSize size; ///< bounds.size 42 | @property (nonatomic, readonly) CGFloat width; ///< bounds.size.width 43 | @property (nonatomic, readonly) CGFloat height; ///< bounds.size.height 44 | @property (nonatomic, readonly) CGFloat top; ///< bounds.origin.y 45 | @property (nonatomic, readonly) CGFloat bottom; ///< bounds.origin.y + bounds.size.height 46 | @property (nonatomic, readonly) CGFloat left; ///< bounds.origin.x 47 | @property (nonatomic, readonly) CGFloat right; ///< bounds.origin.x + bounds.size.width 48 | 49 | @property (nonatomic) CGPoint position; ///< baseline position 50 | @property (nonatomic, readonly) CGFloat ascent; ///< line ascent 51 | @property (nonatomic, readonly) CGFloat descent; ///< line descent 52 | @property (nonatomic, readonly) CGFloat leading; ///< line leading 53 | @property (nonatomic, readonly) CGFloat lineWidth; ///< line width 54 | @property (nonatomic, readonly) CGFloat trailingWhitespaceWidth; 55 | 56 | @property (nonatomic, readonly) NSArray *attachments; ///< YYTextAttachment 57 | @property (nonatomic, readonly) NSArray *attachmentRanges; ///< NSRange(NSValue) 58 | @property (nonatomic, readonly) NSArray *attachmentRects; ///< CGRect(NSValue) 59 | 60 | @end 61 | 62 | 63 | typedef NS_ENUM(NSUInteger, YYTextRunGlyphDrawMode) { 64 | /// No rotate. 65 | YYTextRunGlyphDrawModeHorizontal = 0, 66 | 67 | /// Rotate vertical for single glyph. 68 | YYTextRunGlyphDrawModeVerticalRotate = 1, 69 | 70 | /// Rotate vertical for single glyph, and move the glyph to a better position, 71 | /// such as fullwidth punctuation. 72 | YYTextRunGlyphDrawModeVerticalRotateMove = 2, 73 | }; 74 | 75 | /** 76 | A range in CTRun, used for vertical form. 77 | */ 78 | @interface YYTextRunGlyphRange : NSObject 79 | @property (nonatomic) NSRange glyphRangeInRun; 80 | @property (nonatomic) YYTextRunGlyphDrawMode drawMode; 81 | + (instancetype)rangeWithRange:(NSRange)range drawMode:(YYTextRunGlyphDrawMode)mode; 82 | @end 83 | 84 | NS_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextLine.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYYTextLine.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/3/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextLine.h" 13 | #import "YYTextUtilities.h" 14 | 15 | 16 | @implementation YYTextLine { 17 | CGFloat _firstGlyphPos; // first glyph position for baseline, typically 0. 18 | } 19 | 20 | + (instancetype)lineWithCTLine:(CTLineRef)CTLine position:(CGPoint)position vertical:(BOOL)isVertical { 21 | if (!CTLine) return nil; 22 | YYTextLine *line = [self new]; 23 | line->_position = position; 24 | line->_vertical = isVertical; 25 | [line setCTLine:CTLine]; 26 | return line; 27 | } 28 | 29 | - (void)dealloc { 30 | if (_CTLine) CFRelease(_CTLine); 31 | } 32 | 33 | - (void)setCTLine:(CTLineRef)CTLine { 34 | if (_CTLine != CTLine) { 35 | if (CTLine) CFRetain(CTLine); 36 | if (_CTLine) CFRelease(_CTLine); 37 | _CTLine = CTLine; 38 | if (_CTLine) { 39 | _lineWidth = CTLineGetTypographicBounds(_CTLine, &_ascent, &_descent, &_leading); 40 | CFRange range = CTLineGetStringRange(_CTLine); 41 | _range = NSMakeRange(range.location, range.length); 42 | if (CTLineGetGlyphCount(_CTLine) > 0) { 43 | CFArrayRef runs = CTLineGetGlyphRuns(_CTLine); 44 | CTRunRef run = CFArrayGetValueAtIndex(runs, 0); 45 | CGPoint pos; 46 | CTRunGetPositions(run, CFRangeMake(0, 1), &pos); 47 | _firstGlyphPos = pos.x; 48 | } else { 49 | _firstGlyphPos = 0; 50 | } 51 | _trailingWhitespaceWidth = CTLineGetTrailingWhitespaceWidth(_CTLine); 52 | } else { 53 | _lineWidth = _ascent = _descent = _leading = _firstGlyphPos = _trailingWhitespaceWidth = 0; 54 | _range = NSMakeRange(0, 0); 55 | } 56 | [self reloadBounds]; 57 | } 58 | } 59 | 60 | - (void)setPosition:(CGPoint)position { 61 | _position = position; 62 | [self reloadBounds]; 63 | } 64 | 65 | - (void)reloadBounds { 66 | if (_vertical) { 67 | _bounds = CGRectMake(_position.x - _descent, _position.y, _ascent + _descent, _lineWidth); 68 | _bounds.origin.y += _firstGlyphPos; 69 | } else { 70 | _bounds = CGRectMake(_position.x, _position.y - _ascent, _lineWidth, _ascent + _descent); 71 | _bounds.origin.x += _firstGlyphPos; 72 | } 73 | 74 | _attachments = nil; 75 | _attachmentRanges = nil; 76 | _attachmentRects = nil; 77 | if (!_CTLine) return; 78 | CFArrayRef runs = CTLineGetGlyphRuns(_CTLine); 79 | NSUInteger runCount = CFArrayGetCount(runs); 80 | if (runCount == 0) return; 81 | 82 | NSMutableArray *attachments = [NSMutableArray new]; 83 | NSMutableArray *attachmentRanges = [NSMutableArray new]; 84 | NSMutableArray *attachmentRects = [NSMutableArray new]; 85 | for (NSUInteger r = 0; r < runCount; r++) { 86 | CTRunRef run = CFArrayGetValueAtIndex(runs, r); 87 | CFIndex glyphCount = CTRunGetGlyphCount(run); 88 | if (glyphCount == 0) continue; 89 | NSDictionary *attrs = (id)CTRunGetAttributes(run); 90 | YYTextAttachment *attachment = attrs[YYTextAttachmentAttributeName]; 91 | if (attachment) { 92 | CGPoint runPosition = CGPointZero; 93 | CTRunGetPositions(run, CFRangeMake(0, 1), &runPosition); 94 | 95 | CGFloat ascent, descent, leading, runWidth; 96 | CGRect runTypoBounds; 97 | runWidth = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, &leading); 98 | 99 | if (_vertical) { 100 | YYTEXT_SWAP(runPosition.x, runPosition.y); 101 | runPosition.y = _position.y + runPosition.y; 102 | runTypoBounds = CGRectMake(_position.x + runPosition.x - descent, runPosition.y , ascent + descent, runWidth); 103 | } else { 104 | runPosition.x += _position.x; 105 | runPosition.y = _position.y - runPosition.y; 106 | runTypoBounds = CGRectMake(runPosition.x, runPosition.y - ascent, runWidth, ascent + descent); 107 | } 108 | 109 | NSRange runRange = YYTextNSRangeFromCFRange(CTRunGetStringRange(run)); 110 | [attachments addObject:attachment]; 111 | [attachmentRanges addObject:[NSValue valueWithRange:runRange]]; 112 | [attachmentRects addObject:[NSValue valueWithCGRect:runTypoBounds]]; 113 | } 114 | } 115 | _attachments = attachments.count ? attachments : nil; 116 | _attachmentRanges = attachmentRanges.count ? attachmentRanges : nil; 117 | _attachmentRects = attachmentRects.count ? attachmentRects : nil; 118 | } 119 | 120 | - (CGSize)size { 121 | return _bounds.size; 122 | } 123 | 124 | - (CGFloat)width { 125 | return CGRectGetWidth(_bounds); 126 | } 127 | 128 | - (CGFloat)height { 129 | return CGRectGetHeight(_bounds); 130 | } 131 | 132 | - (CGFloat)top { 133 | return CGRectGetMinY(_bounds); 134 | } 135 | 136 | - (CGFloat)bottom { 137 | return CGRectGetMaxY(_bounds); 138 | } 139 | 140 | - (CGFloat)left { 141 | return CGRectGetMinX(_bounds); 142 | } 143 | 144 | - (CGFloat)right { 145 | return CGRectGetMaxX(_bounds); 146 | } 147 | 148 | - (NSString *)description { 149 | NSMutableString *desc = @"".mutableCopy; 150 | NSRange range = self.range; 151 | [desc appendFormat:@" row:%zd range:%tu,%tu",self, self.row, range.location, range.length]; 152 | [desc appendFormat:@" position:%@",NSStringFromCGPoint(self.position)]; 153 | [desc appendFormat:@" bounds:%@",NSStringFromCGRect(self.bounds)]; 154 | return desc; 155 | } 156 | 157 | @end 158 | 159 | 160 | @implementation YYTextRunGlyphRange 161 | + (instancetype)rangeWithRange:(NSRange)range drawMode:(YYTextRunGlyphDrawMode)mode { 162 | YYTextRunGlyphRange *one = [self new]; 163 | one.glyphRangeInRun = range; 164 | one.drawMode = mode; 165 | return one; 166 | } 167 | @end 168 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextMagnifier.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextMagnifier.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/2/25. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #else 17 | #import "YYTextAttribute.h" 18 | #endif 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | /// Magnifier type 23 | typedef NS_ENUM(NSInteger, YYTextMagnifierType) { 24 | YYTextMagnifierTypeCaret, ///< Circular magnifier 25 | YYTextMagnifierTypeRanged, ///< Round rectangle magnifier 26 | }; 27 | 28 | /** 29 | A magnifier view which can be displayed in `YYTextEffectWindow`. 30 | 31 | @discussion Use `magnifierWithType:` to create instance. 32 | Typically, you should not use this class directly. 33 | */ 34 | @interface YYTextMagnifier : UIView 35 | 36 | /// Create a mangifier with the specified type. @param type The magnifier type. 37 | + (id)magnifierWithType:(YYTextMagnifierType)type; 38 | 39 | @property (nonatomic, readonly) YYTextMagnifierType type; ///< Type of magnifier 40 | @property (nonatomic, readonly) CGSize fitSize; ///< The 'best' size for magnifier view. 41 | @property (nonatomic, readonly) CGSize snapshotSize; ///< The 'best' snapshot image size for magnifier. 42 | @property (nullable, nonatomic, strong) UIImage *snapshot; ///< The image in magnifier (readwrite). 43 | 44 | @property (nullable, nonatomic, weak) UIView *hostView; ///< The coordinate based view. 45 | @property (nonatomic) CGPoint hostCaptureCenter; ///< The snapshot capture center in `hostView`. 46 | @property (nonatomic) CGPoint hostPopoverCenter; ///< The popover center in `hostView`. 47 | @property (nonatomic) BOOL hostVerticalForm; ///< The host view is vertical form. 48 | @property (nonatomic) BOOL captureDisabled; ///< A hint for `YYTextEffectWindow` to disable capture. 49 | @property (nonatomic) BOOL captureFadeAnimation; ///< Show fade animation when the snapshot image changed. 50 | @end 51 | 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Component/YYTextSelectionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextSelectionView.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/2/25. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #import 17 | #else 18 | #import "YYTextAttribute.h" 19 | #import "YYTextInput.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | A single dot view. The frame should be foursquare. 26 | Change the background color for display. 27 | 28 | @discussion Typically, you should not use this class directly. 29 | */ 30 | @interface YYSelectionGrabberDot : UIView 31 | /// Dont't access this property. It was used by `YYTextEffectWindow`. 32 | @property (nonatomic, strong) UIView *mirror; 33 | @end 34 | 35 | 36 | /** 37 | A grabber (stick with a dot). 38 | 39 | @discussion Typically, you should not use this class directly. 40 | */ 41 | @interface YYSelectionGrabber : UIView 42 | 43 | @property (nonatomic, readonly) YYSelectionGrabberDot *dot; ///< the dot view 44 | @property (nonatomic) YYTextDirection dotDirection; ///< don't support composite direction 45 | @property (nullable, nonatomic, strong) UIColor *color; ///< tint color, default is nil 46 | 47 | @end 48 | 49 | 50 | /** 51 | The selection view for text edit and select. 52 | 53 | @discussion Typically, you should not use this class directly. 54 | */ 55 | @interface YYTextSelectionView : UIView 56 | 57 | @property (nullable, nonatomic, weak) UIView *hostView; ///< the holder view 58 | @property (nullable, nonatomic, strong) UIColor *color; ///< the tint color 59 | @property (nonatomic, getter = isCaretBlinks) BOOL caretBlinks; ///< whether the caret is blinks 60 | @property (nonatomic, getter = isCaretVisible) BOOL caretVisible; ///< whether the caret is visible 61 | @property (nonatomic, getter = isVerticalForm) BOOL verticalForm; ///< weather the text view is vertical form 62 | 63 | @property (nonatomic) CGRect caretRect; ///< caret rect (width==0 or height==0) 64 | @property (nullable, nonatomic, copy) NSArray *selectionRects; ///< default is nil 65 | 66 | @property (nonatomic, readonly) UIView *caretView; 67 | @property (nonatomic, readonly) YYSelectionGrabber *startGrabber; 68 | @property (nonatomic, readonly) YYSelectionGrabber *endGrabber; 69 | 70 | - (BOOL)isGrabberContainsPoint:(CGPoint)point; 71 | - (BOOL)isStartGrabberContainsPoint:(CGPoint)point; 72 | - (BOOL)isEndGrabberContainsPoint:(CGPoint)point; 73 | - (BOOL)isCaretContainsPoint:(CGPoint)point; 74 | - (BOOL)isSelectionRectsContainsPoint:(CGPoint)point; 75 | 76 | @end 77 | 78 | NS_ASSUME_NONNULL_END 79 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextArchiver.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextArchiver.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/3/16. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | A subclass of `NSKeyedArchiver` which implement `NSKeyedArchiverDelegate` protocol. 18 | 19 | The archiver can encode the object which contains 20 | CGColor/CGImage/CTRunDelegateRef/.. (such as NSAttributedString). 21 | */ 22 | @interface YYTextArchiver : NSKeyedArchiver 23 | @end 24 | 25 | /** 26 | A subclass of `NSKeyedUnarchiver` which implement `NSKeyedUnarchiverDelegate` 27 | protocol. The unarchiver can decode the data which is encoded by 28 | `YYTextArchiver` or `NSKeyedArchiver`. 29 | */ 30 | @interface YYTextUnarchiver : NSKeyedUnarchiver 31 | @end 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextArchiver.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextArchiver.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/3/16. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextArchiver.h" 13 | #import "YYTextRunDelegate.h" 14 | #import "YYTextRubyAnnotation.h" 15 | 16 | /** 17 | When call CTRunDelegateGetTypeID() on some devices (runs iOS6), I got the error: 18 | "dyld: lazy symbol binding failed: Symbol not found: _CTRunDelegateGetTypeID" 19 | 20 | Here's a workaround for this issue. 21 | */ 22 | static CFTypeID CTRunDelegateTypeID() { 23 | static CFTypeID typeID; 24 | static dispatch_once_t onceToken; 25 | dispatch_once(&onceToken, ^{ 26 | /* 27 | if ((long)CTRunDelegateGetTypeID + 1 > 1) { //avoid compiler optimization 28 | typeID = CTRunDelegateGetTypeID(); 29 | } 30 | */ 31 | YYTextRunDelegate *delegate = [YYTextRunDelegate new]; 32 | CTRunDelegateRef ref = delegate.CTRunDelegate; 33 | typeID = CFGetTypeID(ref); 34 | CFRelease(ref); 35 | }); 36 | return typeID; 37 | } 38 | 39 | static CFTypeID CTRubyAnnotationTypeID() { 40 | static CFTypeID typeID; 41 | static dispatch_once_t onceToken; 42 | dispatch_once(&onceToken, ^{ 43 | if ((long)CTRubyAnnotationGetTypeID + 1 > 1) { //avoid compiler optimization 44 | typeID = CTRunDelegateGetTypeID(); 45 | } else { 46 | typeID = kCFNotFound; 47 | } 48 | }); 49 | return typeID; 50 | } 51 | 52 | /** 53 | A wrapper for CGColorRef. Used for Archive/Unarchive/Copy. 54 | */ 55 | @interface _YYCGColor : NSObject 56 | @property (nonatomic, assign) CGColorRef CGColor; 57 | + (instancetype)colorWithCGColor:(CGColorRef)CGColor; 58 | @end 59 | 60 | @implementation _YYCGColor 61 | 62 | + (instancetype)colorWithCGColor:(CGColorRef)CGColor { 63 | _YYCGColor *color = [self new]; 64 | color.CGColor = CGColor; 65 | return color; 66 | } 67 | 68 | - (void)setCGColor:(CGColorRef)CGColor { 69 | if (_CGColor != CGColor) { 70 | if (CGColor) CGColor = (CGColorRef)CFRetain(CGColor); 71 | if (_CGColor) CFRelease(_CGColor); 72 | _CGColor = CGColor; 73 | } 74 | } 75 | 76 | - (void)dealloc { 77 | if (_CGColor) CFRelease(_CGColor); 78 | _CGColor = NULL; 79 | } 80 | 81 | - (id)copyWithZone:(NSZone *)zone { 82 | _YYCGColor *color = [self.class new]; 83 | color.CGColor = self.CGColor; 84 | return color; 85 | } 86 | 87 | - (void)encodeWithCoder:(NSCoder *)aCoder { 88 | UIColor *color = [UIColor colorWithCGColor:_CGColor]; 89 | [aCoder encodeObject:color forKey:@"color"]; 90 | } 91 | 92 | - (id)initWithCoder:(NSCoder *)aDecoder { 93 | self = [self init]; 94 | UIColor *color = [aDecoder decodeObjectForKey:@"color"]; 95 | self.CGColor = color.CGColor; 96 | return self; 97 | } 98 | 99 | @end 100 | 101 | /** 102 | A wrapper for CGImageRef. Used for Archive/Unarchive/Copy. 103 | */ 104 | @interface _YYCGImage : NSObject 105 | @property (nonatomic, assign) CGImageRef CGImage; 106 | + (instancetype)imageWithCGImage:(CGImageRef)CGImage; 107 | @end 108 | 109 | @implementation _YYCGImage 110 | 111 | + (instancetype)imageWithCGImage:(CGImageRef)CGImage { 112 | _YYCGImage *image = [self new]; 113 | image.CGImage = CGImage; 114 | return image; 115 | } 116 | 117 | - (void)setCGImage:(CGImageRef)CGImage { 118 | if (_CGImage != CGImage) { 119 | if (CGImage) CGImage = (CGImageRef)CFRetain(CGImage); 120 | if (_CGImage) CFRelease(_CGImage); 121 | _CGImage = CGImage; 122 | } 123 | } 124 | 125 | - (void)dealloc { 126 | if (_CGImage) CFRelease(_CGImage); 127 | } 128 | 129 | - (id)copyWithZone:(NSZone *)zone { 130 | _YYCGImage *image = [self.class new]; 131 | image.CGImage = self.CGImage; 132 | return image; 133 | } 134 | 135 | - (void)encodeWithCoder:(NSCoder *)aCoder { 136 | UIImage *image = [UIImage imageWithCGImage:_CGImage]; 137 | [aCoder encodeObject:image forKey:@"image"]; 138 | } 139 | 140 | - (id)initWithCoder:(NSCoder *)aDecoder { 141 | self = [self init]; 142 | UIImage *image = [aDecoder decodeObjectForKey:@"image"]; 143 | self.CGImage = image.CGImage; 144 | return self; 145 | } 146 | 147 | @end 148 | 149 | 150 | @implementation YYTextArchiver 151 | 152 | + (NSData *)archivedDataWithRootObject:(id)rootObject { 153 | if (!rootObject) return nil; 154 | NSMutableData *data = [NSMutableData data]; 155 | YYTextArchiver *archiver = [[[self class] alloc] initForWritingWithMutableData:data]; 156 | [archiver encodeRootObject:rootObject]; 157 | [archiver finishEncoding]; 158 | return data; 159 | } 160 | 161 | + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path { 162 | NSData *data = [self archivedDataWithRootObject:rootObject]; 163 | if (!data) return NO; 164 | return [data writeToFile:path atomically:YES]; 165 | } 166 | 167 | - (instancetype)init { 168 | self = [super init]; 169 | self.delegate = self; 170 | return self; 171 | } 172 | 173 | - (instancetype)initForWritingWithMutableData:(NSMutableData *)data { 174 | self = [super initForWritingWithMutableData:data]; 175 | self.delegate = self; 176 | return self; 177 | } 178 | 179 | - (id)archiver:(NSKeyedArchiver *)archiver willEncodeObject:(id)object { 180 | CFTypeID typeID = CFGetTypeID((CFTypeRef)object); 181 | if (typeID == CTRunDelegateTypeID()) { 182 | CTRunDelegateRef runDelegate = (__bridge CFTypeRef)(object); 183 | id ref = CTRunDelegateGetRefCon(runDelegate); 184 | if (ref) return ref; 185 | } else if (typeID == CTRubyAnnotationTypeID()) { 186 | CTRubyAnnotationRef ctRuby = (__bridge CFTypeRef)(object); 187 | YYTextRubyAnnotation *ruby = [YYTextRubyAnnotation rubyWithCTRubyRef:ctRuby]; 188 | if (ruby) return ruby; 189 | } else if (typeID == CGColorGetTypeID()) { 190 | return [_YYCGColor colorWithCGColor:(CGColorRef)object]; 191 | } else if (typeID == CGImageGetTypeID()) { 192 | return [_YYCGImage imageWithCGImage:(CGImageRef)object]; 193 | } 194 | return object; 195 | } 196 | 197 | @end 198 | 199 | 200 | @implementation YYTextUnarchiver 201 | 202 | + (id)unarchiveObjectWithData:(NSData *)data { 203 | if (data.length == 0) return nil; 204 | YYTextUnarchiver *unarchiver = [[self alloc] initForReadingWithData:data]; 205 | return [unarchiver decodeObject]; 206 | } 207 | 208 | + (id)unarchiveObjectWithFile:(NSString *)path { 209 | NSData *data = [NSData dataWithContentsOfFile:path]; 210 | return [self unarchiveObjectWithData:data]; 211 | } 212 | 213 | - (instancetype)init { 214 | self = [super init]; 215 | self.delegate = self; 216 | return self; 217 | } 218 | 219 | - (instancetype)initForReadingWithData:(NSData *)data { 220 | self = [super initForReadingWithData:data]; 221 | self.delegate = self; 222 | return self; 223 | } 224 | 225 | - (id)unarchiver:(NSKeyedUnarchiver *)unarchiver didDecodeObject:(id) NS_RELEASES_ARGUMENT object NS_RETURNS_RETAINED { 226 | if ([object class] == [YYTextRunDelegate class]) { 227 | YYTextRunDelegate *runDelegate = object; 228 | CTRunDelegateRef ct = runDelegate.CTRunDelegate; 229 | id ctObj = (__bridge id)ct; 230 | if (ct) CFRelease(ct); 231 | return ctObj; 232 | } else if ([object class] == [YYTextRubyAnnotation class]) { 233 | YYTextRubyAnnotation *ruby = object; 234 | if ([UIDevice currentDevice].systemVersion.floatValue >= 8) { 235 | CTRubyAnnotationRef ct = ruby.CTRubyAnnotation; 236 | id ctObj = (__bridge id)(ct); 237 | if (ct) CFRelease(ct); 238 | return ctObj; 239 | } else { 240 | return object; 241 | } 242 | } else if ([object class] == [_YYCGColor class]) { 243 | _YYCGColor *color = object; 244 | return (id)color.CGColor; 245 | } else if ([object class] == [_YYCGImage class]) { 246 | _YYCGImage *image = object; 247 | return (id)image.CGImage; 248 | } 249 | return object; 250 | } 251 | 252 | @end 253 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextParser.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/3/6. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | The YYTextParser protocol declares the required method for YYTextView and YYLabel 18 | to modify the text during editing. 19 | 20 | You can implement this protocol to add code highlighting or emoticon replacement for 21 | YYTextView and YYLabel. See `YYTextSimpleMarkdownParser` and `YYTextSimpleEmoticonParser` for example. 22 | */ 23 | @protocol YYTextParser 24 | @required 25 | /** 26 | When text is changed in YYTextView or YYLabel, this method will be called. 27 | 28 | @param text The original attributed string. This method may parse the text and 29 | change the text attributes or content. 30 | 31 | @param selectedRange Current selected range in `text`. 32 | This method should correct the range if the text content is changed. If there's 33 | no selected range (such as YYLabel), this value is NULL. 34 | 35 | @return If the 'text' is modified in this method, returns `YES`, otherwise returns `NO`. 36 | */ 37 | - (BOOL)parseText:(nullable NSMutableAttributedString *)text selectedRange:(nullable NSRangePointer)selectedRange; 38 | @end 39 | 40 | 41 | 42 | /** 43 | A simple markdown parser. 44 | 45 | It'a very simple markdown parser, you can use this parser to highlight some 46 | small piece of markdown text. 47 | 48 | This markdown parser use regular expression to parse text, slow and weak. 49 | If you want to write a better parser, try these projests: 50 | https://github.com/NimbusKit/markdown 51 | https://github.com/dreamwieber/AttributedMarkdown 52 | https://github.com/indragiek/CocoaMarkdown 53 | 54 | Or you can use lex/yacc to generate your custom parser. 55 | */ 56 | @interface YYTextSimpleMarkdownParser : NSObject 57 | @property (nonatomic) CGFloat fontSize; ///< default is 14 58 | @property (nonatomic) CGFloat headerFontSize; ///< default is 20 59 | 60 | @property (nullable, nonatomic, strong) UIColor *textColor; 61 | @property (nullable, nonatomic, strong) UIColor *controlTextColor; 62 | @property (nullable, nonatomic, strong) UIColor *headerTextColor; 63 | @property (nullable, nonatomic, strong) UIColor *inlineTextColor; 64 | @property (nullable, nonatomic, strong) UIColor *codeTextColor; 65 | @property (nullable, nonatomic, strong) UIColor *linkTextColor; 66 | 67 | - (void)setColorWithBrightTheme; ///< reset the color properties to pre-defined value. 68 | - (void)setColorWithDarkTheme; ///< reset the color properties to pre-defined value. 69 | @end 70 | 71 | 72 | 73 | /** 74 | A simple emoticon parser. 75 | 76 | Use this parser to map some specified piece of string to image emoticon. 77 | Example: "Hello :smile:" -> "Hello 😀" 78 | 79 | It can also be used to extend the "unicode emoticon". 80 | */ 81 | @interface YYTextSimpleEmoticonParser : NSObject 82 | 83 | /** 84 | The custom emoticon mapper. 85 | The key is a specified plain string, such as @":smile:". 86 | The value is a UIImage which will replace the specified plain string in text. 87 | */ 88 | @property (nullable, copy) NSDictionary *emoticonMapper; 89 | @end 90 | 91 | NS_ASSUME_NONNULL_END 92 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextRubyAnnotation.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextRubyAnnotation.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/24. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | /** 18 | Wrapper for CTRubyAnnotationRef. 19 | 20 | Example: 21 | 22 | YYTextRubyAnnotation *ruby = [YYTextRubyAnnotation new]; 23 | ruby.textBefore = @"zhù yīn"; 24 | CTRubyAnnotationRef ctRuby = ruby.CTRubyAnnotation; 25 | if (ctRuby) { 26 | /// add to attributed string 27 | CFRelease(ctRuby); 28 | } 29 | 30 | */ 31 | @interface YYTextRubyAnnotation : NSObject 32 | 33 | /// Specifies how the ruby text and the base text should be aligned relative to each other. 34 | @property (nonatomic) CTRubyAlignment alignment; 35 | 36 | /// Specifies how the ruby text can overhang adjacent characters. 37 | @property (nonatomic) CTRubyOverhang overhang; 38 | 39 | /// Specifies the size of the annotation text as a percent of the size of the base text. 40 | @property (nonatomic) CGFloat sizeFactor; 41 | 42 | 43 | /// The ruby text is positioned before the base text; 44 | /// i.e. above horizontal text and to the right of vertical text. 45 | @property (nullable, nonatomic, copy) NSString *textBefore; 46 | 47 | /// The ruby text is positioned after the base text; 48 | /// i.e. below horizontal text and to the left of vertical text. 49 | @property (nullable, nonatomic, copy) NSString *textAfter; 50 | 51 | /// The ruby text is positioned to the right of the base text whether it is horizontal or vertical. 52 | /// This is the way that Bopomofo annotations are attached to Chinese text in Taiwan. 53 | @property (nullable, nonatomic, copy) NSString *textInterCharacter; 54 | 55 | /// The ruby text follows the base text with no special styling. 56 | @property (nullable, nonatomic, copy) NSString *textInline; 57 | 58 | 59 | /** 60 | Create a ruby object from CTRuby object. 61 | 62 | @param ctRuby A CTRuby object. 63 | 64 | @return A ruby object, or nil when an error occurs. 65 | */ 66 | + (instancetype)rubyWithCTRubyRef:(CTRubyAnnotationRef)ctRuby NS_AVAILABLE_IOS(8_0); 67 | 68 | /** 69 | Create a CTRuby object from the instance. 70 | 71 | @return A new CTRuby object, or NULL when an error occurs. 72 | The returned value should be release after used. 73 | */ 74 | - (nullable CTRubyAnnotationRef)CTRubyAnnotation CF_RETURNS_RETAINED NS_AVAILABLE_IOS(8_0); 75 | 76 | @end 77 | 78 | NS_ASSUME_NONNULL_END 79 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextRubyAnnotation.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextRubyAnnotation.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/24. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextRubyAnnotation.h" 13 | 14 | @implementation YYTextRubyAnnotation 15 | 16 | - (instancetype)init { 17 | self = super.init; 18 | self.alignment = kCTRubyAlignmentAuto; 19 | self.overhang = kCTRubyOverhangAuto; 20 | self.sizeFactor = 0.5; 21 | return self; 22 | } 23 | 24 | + (instancetype)rubyWithCTRubyRef:(CTRubyAnnotationRef)ctRuby { 25 | if (!ctRuby) return nil; 26 | YYTextRubyAnnotation *one = [self new]; 27 | one.alignment = CTRubyAnnotationGetAlignment(ctRuby); 28 | one.overhang = CTRubyAnnotationGetOverhang(ctRuby); 29 | one.sizeFactor = CTRubyAnnotationGetSizeFactor(ctRuby); 30 | one.textBefore = (__bridge NSString *)(CTRubyAnnotationGetTextForPosition(ctRuby, kCTRubyPositionBefore)); 31 | one.textAfter = (__bridge NSString *)(CTRubyAnnotationGetTextForPosition(ctRuby, kCTRubyPositionAfter)); 32 | one.textInterCharacter = (__bridge NSString *)(CTRubyAnnotationGetTextForPosition(ctRuby, kCTRubyPositionInterCharacter)); 33 | one.textInline = (__bridge NSString *)(CTRubyAnnotationGetTextForPosition(ctRuby, kCTRubyPositionInline)); 34 | return one; 35 | } 36 | 37 | - (CTRubyAnnotationRef)CTRubyAnnotation CF_RETURNS_RETAINED { 38 | if (((long)CTRubyAnnotationCreate + 1) == 1) return NULL; // system not support 39 | 40 | CFStringRef text[kCTRubyPositionCount]; 41 | text[kCTRubyPositionBefore] = (__bridge CFStringRef)(_textBefore); 42 | text[kCTRubyPositionAfter] = (__bridge CFStringRef)(_textAfter); 43 | text[kCTRubyPositionInterCharacter] = (__bridge CFStringRef)(_textInterCharacter); 44 | text[kCTRubyPositionInline] = (__bridge CFStringRef)(_textInline); 45 | CTRubyAnnotationRef ruby = CTRubyAnnotationCreate(_alignment, _overhang, _sizeFactor, text); 46 | return ruby; 47 | } 48 | 49 | - (id)copyWithZone:(NSZone *)zone { 50 | YYTextRubyAnnotation *one = [self.class new]; 51 | one.alignment = _alignment; 52 | one.overhang = _overhang; 53 | one.sizeFactor = _sizeFactor; 54 | one.textBefore = _textBefore; 55 | one.textAfter = _textAfter; 56 | one.textInterCharacter = _textInterCharacter; 57 | one.textInline = _textInline; 58 | return one; 59 | } 60 | 61 | - (void)encodeWithCoder:(NSCoder *)aCoder { 62 | [aCoder encodeObject:@(_alignment) forKey:@"alignment"]; 63 | [aCoder encodeObject:@(_overhang) forKey:@"overhang"]; 64 | [aCoder encodeObject:@(_sizeFactor) forKey:@"sizeFactor"]; 65 | [aCoder encodeObject:_textBefore forKey:@"textBefore"]; 66 | [aCoder encodeObject:_textAfter forKey:@"textAfter"]; 67 | [aCoder encodeObject:_textInterCharacter forKey:@"textInterCharacter"]; 68 | [aCoder encodeObject:_textInline forKey:@"textInline"]; 69 | } 70 | 71 | - (id)initWithCoder:(NSCoder *)aDecoder { 72 | self = [self init]; 73 | _alignment = ((NSNumber *)[aDecoder decodeObjectForKey:@"alignment"]).intValue; 74 | _overhang = ((NSNumber *)[aDecoder decodeObjectForKey:@"overhang"]).intValue; 75 | _sizeFactor = ((NSNumber *)[aDecoder decodeObjectForKey:@"sizeFactor"]).intValue; 76 | _textBefore = [aDecoder decodeObjectForKey:@"textBefore"]; 77 | _textAfter = [aDecoder decodeObjectForKey:@"textAfter"]; 78 | _textInterCharacter = [aDecoder decodeObjectForKey:@"textInterCharacter"]; 79 | _textInline = [aDecoder decodeObjectForKey:@"textInline"]; 80 | return self; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextRunDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextRunDelegate.h 3 | // YYText 4 | // 5 | // Created by ibireme on 14/10/14. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | /** 18 | Wrapper for CTRunDelegateRef. 19 | 20 | Example: 21 | 22 | YYTextRunDelegate *delegate = [YYTextRunDelegate new]; 23 | delegate.ascent = 20; 24 | delegate.descent = 4; 25 | delegate.width = 20; 26 | CTRunDelegateRef ctRunDelegate = delegate.CTRunDelegate; 27 | if (ctRunDelegate) { 28 | /// add to attributed string 29 | CFRelease(ctRunDelegate); 30 | } 31 | 32 | */ 33 | @interface YYTextRunDelegate : NSObject 34 | 35 | /** 36 | Creates and returns the CTRunDelegate. 37 | 38 | @discussion You need call CFRelease() after used. 39 | The CTRunDelegateRef has a strong reference to this YYTextRunDelegate object. 40 | In CoreText, use CTRunDelegateGetRefCon() to get this YYTextRunDelegate object. 41 | 42 | @return The CTRunDelegate object. 43 | */ 44 | - (nullable CTRunDelegateRef)CTRunDelegate CF_RETURNS_RETAINED; 45 | 46 | /** 47 | Additional information about the the run delegate. 48 | */ 49 | @property (nullable, nonatomic, strong) NSDictionary *userInfo; 50 | 51 | /** 52 | The typographic ascent of glyphs in the run. 53 | */ 54 | @property (nonatomic) CGFloat ascent; 55 | 56 | /** 57 | The typographic descent of glyphs in the run. 58 | */ 59 | @property (nonatomic) CGFloat descent; 60 | 61 | /** 62 | The typographic width of glyphs in the run. 63 | */ 64 | @property (nonatomic) CGFloat width; 65 | 66 | @end 67 | 68 | NS_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/String/YYTextRunDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextRunDelegate.m 3 | // YYText 4 | // 5 | // Created by ibireme on 14/10/14. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextRunDelegate.h" 13 | 14 | static void DeallocCallback(void *ref) { 15 | YYTextRunDelegate *self = (__bridge_transfer YYTextRunDelegate *)(ref); 16 | self = nil; // release 17 | } 18 | 19 | static CGFloat GetAscentCallback(void *ref) { 20 | YYTextRunDelegate *self = (__bridge YYTextRunDelegate *)(ref); 21 | return self.ascent; 22 | } 23 | 24 | static CGFloat GetDecentCallback(void *ref) { 25 | YYTextRunDelegate *self = (__bridge YYTextRunDelegate *)(ref); 26 | return self.descent; 27 | } 28 | 29 | static CGFloat GetWidthCallback(void *ref) { 30 | YYTextRunDelegate *self = (__bridge YYTextRunDelegate *)(ref); 31 | return self.width; 32 | } 33 | 34 | @implementation YYTextRunDelegate 35 | 36 | - (CTRunDelegateRef)CTRunDelegate CF_RETURNS_RETAINED { 37 | CTRunDelegateCallbacks callbacks; 38 | callbacks.version = kCTRunDelegateCurrentVersion; 39 | callbacks.dealloc = DeallocCallback; 40 | callbacks.getAscent = GetAscentCallback; 41 | callbacks.getDescent = GetDecentCallback; 42 | callbacks.getWidth = GetWidthCallback; 43 | return CTRunDelegateCreate(&callbacks, (__bridge_retained void *)(self.copy)); 44 | } 45 | 46 | - (void)encodeWithCoder:(NSCoder *)aCoder { 47 | [aCoder encodeObject:@(_ascent) forKey:@"ascent"]; 48 | [aCoder encodeObject:@(_descent) forKey:@"descent"]; 49 | [aCoder encodeObject:@(_width) forKey:@"width"]; 50 | [aCoder encodeObject:_userInfo forKey:@"userInfo"]; 51 | } 52 | 53 | - (id)initWithCoder:(NSCoder *)aDecoder { 54 | self = [super init]; 55 | _ascent = ((NSNumber *)[aDecoder decodeObjectForKey:@"ascent"]).floatValue; 56 | _descent = ((NSNumber *)[aDecoder decodeObjectForKey:@"descent"]).floatValue; 57 | _width = ((NSNumber *)[aDecoder decodeObjectForKey:@"width"]).floatValue; 58 | _userInfo = [aDecoder decodeObjectForKey:@"userInfo"]; 59 | return self; 60 | } 61 | 62 | - (id)copyWithZone:(NSZone *)zone { 63 | typeof(self) one = [self.class new]; 64 | one.ascent = self.ascent; 65 | one.descent = self.descent; 66 | one.width = self.width; 67 | one.userInfo = self.userInfo; 68 | return one; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/NSParagraphStyle+YYText.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSParagraphStyle+YYText.h 3 | // YYText 4 | // 5 | // Created by ibireme on 14/10/7. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Provides extensions for `NSParagraphStyle` to work with CoreText. 18 | */ 19 | @interface NSParagraphStyle (YYText) 20 | 21 | /** 22 | Creates a new NSParagraphStyle object from the CoreText Style. 23 | 24 | @param CTStyle CoreText Paragraph Style. 25 | 26 | @return a new NSParagraphStyle 27 | */ 28 | + (nullable NSParagraphStyle *)yy_styleWithCTStyle:(CTParagraphStyleRef)CTStyle; 29 | 30 | /** 31 | Creates and returns a CoreText Paragraph Style. (need call CFRelease() after used) 32 | */ 33 | - (nullable CTParagraphStyleRef)yy_CTStyle CF_RETURNS_RETAINED; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/UIPasteboard+YYText.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIPasteboard+YYText.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/2. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Extend UIPasteboard to support image and attributed string. 18 | */ 19 | @interface UIPasteboard (YYText) 20 | 21 | @property (nullable, nonatomic, copy) NSData *yy_PNGData; ///< PNG file data 22 | @property (nullable, nonatomic, copy) NSData *yy_JPEGData; ///< JPEG file data 23 | @property (nullable, nonatomic, copy) NSData *yy_GIFData; ///< GIF file data 24 | @property (nullable, nonatomic, copy) NSData *yy_WEBPData; ///< WebP file data 25 | @property (nullable, nonatomic, copy) NSData *yy_ImageData; ///< image file data 26 | 27 | /// Attributed string, 28 | /// Set this attributed will also set the string property which is copy from the attributed string. 29 | /// If the attributed string contains one or more image, it will also set the `images` property. 30 | @property (nullable, nonatomic, copy) NSAttributedString *yy_AttributedString; 31 | 32 | @end 33 | 34 | 35 | /// The name identifying the attributed string in pasteboard. 36 | UIKIT_EXTERN NSString *const YYTextPasteboardTypeAttributedString; 37 | 38 | /// The UTI Type identifying WebP data in pasteboard. 39 | UIKIT_EXTERN NSString *const YYTextUTTypeWEBP; 40 | 41 | NS_ASSUME_NONNULL_END 42 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/UIPasteboard+YYText.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIPasteboard+YYText.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/2. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIPasteboard+YYText.h" 13 | #import "NSAttributedString+YYText.h" 14 | #import 15 | 16 | 17 | #if __has_include("YYImage.h") 18 | #import "YYImage.h" 19 | #define YYTextAnimatedImageAvailable 1 20 | #elif __has_include() 21 | #import 22 | #define YYTextAnimatedImageAvailable 1 23 | #elif __has_include() 24 | #import 25 | #define YYTextAnimatedImageAvailable 1 26 | #else 27 | #define YYTextAnimatedImageAvailable 0 28 | #endif 29 | 30 | 31 | // Dummy class for category 32 | @interface UIPasteboard_YYText : NSObject @end 33 | @implementation UIPasteboard_YYText @end 34 | 35 | 36 | NSString *const YYTextPasteboardTypeAttributedString = @"com.ibireme.NSAttributedString"; 37 | NSString *const YYTextUTTypeWEBP = @"com.google.webp"; 38 | 39 | @implementation UIPasteboard (YYText) 40 | 41 | 42 | - (void)setYy_PNGData:(NSData *)PNGData { 43 | [self setData:PNGData forPasteboardType:(id)kUTTypePNG]; 44 | } 45 | 46 | - (NSData *)yy_PNGData { 47 | return [self dataForPasteboardType:(id)kUTTypePNG]; 48 | } 49 | 50 | - (void)setYy_JPEGData:(NSData *)JPEGData { 51 | [self setData:JPEGData forPasteboardType:(id)kUTTypeJPEG]; 52 | } 53 | 54 | - (NSData *)yy_JPEGData { 55 | return [self dataForPasteboardType:(id)kUTTypeJPEG]; 56 | } 57 | 58 | - (void)setYy_GIFData:(NSData *)GIFData { 59 | [self setData:GIFData forPasteboardType:(id)kUTTypeGIF]; 60 | } 61 | 62 | - (NSData *)yy_GIFData { 63 | return [self dataForPasteboardType:(id)kUTTypeGIF]; 64 | } 65 | 66 | - (void)setYy_WEBPData:(NSData *)WEBPData { 67 | [self setData:WEBPData forPasteboardType:YYTextUTTypeWEBP]; 68 | } 69 | 70 | - (NSData *)yy_WEBPData { 71 | return [self dataForPasteboardType:YYTextUTTypeWEBP]; 72 | } 73 | 74 | - (void)setYy_ImageData:(NSData *)imageData { 75 | [self setData:imageData forPasteboardType:(id)kUTTypeImage]; 76 | } 77 | 78 | - (NSData *)yy_ImageData { 79 | return [self dataForPasteboardType:(id)kUTTypeImage]; 80 | } 81 | 82 | - (void)setYy_AttributedString:(NSAttributedString *)attributedString { 83 | self.string = [attributedString yy_plainTextForRange:NSMakeRange(0, attributedString.length)]; 84 | NSData *data = [attributedString yy_archiveToData]; 85 | if (data) { 86 | NSDictionary *item = @{YYTextPasteboardTypeAttributedString : data}; 87 | [self addItems:@[item]]; 88 | } 89 | [attributedString enumerateAttribute:YYTextAttachmentAttributeName inRange:NSMakeRange(0, attributedString.length) options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(YYTextAttachment *attachment, NSRange range, BOOL *stop) { 90 | 91 | // save image 92 | UIImage *simpleImage = nil; 93 | if ([attachment.content isKindOfClass:[UIImage class]]) { 94 | simpleImage = attachment.content; 95 | } else if ([attachment.content isKindOfClass:[UIImageView class]]) { 96 | simpleImage = ((UIImageView *)attachment.content).image; 97 | } 98 | if (simpleImage) { 99 | NSDictionary *item = @{@"com.apple.uikit.image" : simpleImage}; 100 | [self addItems:@[item]]; 101 | } 102 | 103 | #if YYTextAnimatedImageAvailable 104 | // save animated image 105 | if ([attachment.content isKindOfClass:[UIImageView class]]) { 106 | UIImageView *imageView = attachment.content; 107 | Class aniImageClass = NSClassFromString(@"YYImage"); 108 | UIImage *image = imageView.image; 109 | if (aniImageClass && [image isKindOfClass:aniImageClass]) { 110 | NSData *data = [image valueForKey:@"animatedImageData"]; 111 | NSNumber *type = [image valueForKey:@"animatedImageType"]; 112 | if (data) { 113 | switch (type.unsignedIntegerValue) { 114 | case YYImageTypeGIF: { 115 | NSDictionary *item = @{(id)kUTTypeGIF : data}; 116 | [self addItems:@[item]]; 117 | } break; 118 | case YYImageTypePNG: { // APNG 119 | NSDictionary *item = @{(id)kUTTypePNG : data}; 120 | [self addItems:@[item]]; 121 | } break; 122 | case YYImageTypeWebP: { 123 | NSDictionary *item = @{(id)YYTextUTTypeWEBP : data}; 124 | [self addItems:@[item]]; 125 | } break; 126 | default: break; 127 | } 128 | } 129 | } 130 | } 131 | #endif 132 | 133 | }]; 134 | } 135 | 136 | - (NSAttributedString *)yy_AttributedString { 137 | for (NSDictionary *items in self.items) { 138 | NSData *data = items[YYTextPasteboardTypeAttributedString]; 139 | if (data) { 140 | return [NSAttributedString yy_unarchiveFromData:data]; 141 | } 142 | } 143 | return nil; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/UIView+YYText.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YYText.h 3 | // YYText 4 | // 5 | // Created by ibireme on 13/4/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Provides extensions for `UIView`. 18 | */ 19 | @interface UIView (YYText) 20 | 21 | /** 22 | Returns the view's view controller (may be nil). 23 | */ 24 | @property (nullable, nonatomic, readonly) UIViewController *yy_viewController; 25 | 26 | /** 27 | Returns the visible alpha on screen, taking into account superview and window. 28 | */ 29 | @property (nonatomic, readonly) CGFloat yy_visibleAlpha; 30 | 31 | /** 32 | Converts a point from the receiver's coordinate system to that of the specified view or window. 33 | 34 | @param point A point specified in the local coordinate system (bounds) of the receiver. 35 | @param view The view or window into whose coordinate system point is to be converted. 36 | If view is nil, this method instead converts to window base coordinates. 37 | @return The point converted to the coordinate system of view. 38 | */ 39 | - (CGPoint)yy_convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view; 40 | 41 | /** 42 | Converts a point from the coordinate system of a given view or window to that of the receiver. 43 | 44 | @param point A point specified in the local coordinate system (bounds) of view. 45 | @param view The view or window with point in its coordinate system. 46 | If view is nil, this method instead converts from window base coordinates. 47 | @return The point converted to the local coordinate system (bounds) of the receiver. 48 | */ 49 | - (CGPoint)yy_convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view; 50 | 51 | /** 52 | Converts a rectangle from the receiver's coordinate system to that of another view or window. 53 | 54 | @param rect A rectangle specified in the local coordinate system (bounds) of the receiver. 55 | @param view The view or window that is the target of the conversion operation. If view is nil, this method instead converts to window base coordinates. 56 | @return The converted rectangle. 57 | */ 58 | - (CGRect)yy_convertRect:(CGRect)rect toViewOrWindow:(UIView *)view; 59 | 60 | /** 61 | Converts a rectangle from the coordinate system of another view or window to that of the receiver. 62 | 63 | @param rect A rectangle specified in the local coordinate system (bounds) of view. 64 | @param view The view or window with rect in its coordinate system. 65 | If view is nil, this method instead converts from window base coordinates. 66 | @return The converted rectangle. 67 | */ 68 | - (CGRect)yy_convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view; 69 | 70 | @end 71 | 72 | NS_ASSUME_NONNULL_END 73 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/UIView+YYText.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YYText.m 3 | // YYText 4 | // 5 | // Created by ibireme on 13/4/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIView+YYText.h" 13 | 14 | // Dummy class for category 15 | @interface UIView_YYText : NSObject @end 16 | @implementation UIView_YYText @end 17 | 18 | 19 | @implementation UIView (YYText) 20 | 21 | - (UIViewController *)yy_viewController { 22 | for (UIView *view = self; view; view = view.superview) { 23 | UIResponder *nextResponder = [view nextResponder]; 24 | if ([nextResponder isKindOfClass:[UIViewController class]]) { 25 | return (UIViewController *)nextResponder; 26 | } 27 | } 28 | return nil; 29 | } 30 | 31 | - (CGFloat)yy_visibleAlpha { 32 | if ([self isKindOfClass:[UIWindow class]]) { 33 | if (self.hidden) return 0; 34 | return self.alpha; 35 | } 36 | if (!self.window) return 0; 37 | CGFloat alpha = 1; 38 | UIView *v = self; 39 | while (v) { 40 | if (v.hidden) { 41 | alpha = 0; 42 | break; 43 | } 44 | alpha *= v.alpha; 45 | v = v.superview; 46 | } 47 | return alpha; 48 | } 49 | 50 | - (CGPoint)yy_convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view { 51 | if (!view) { 52 | if ([self isKindOfClass:[UIWindow class]]) { 53 | return [((UIWindow *)self) convertPoint:point toWindow:nil]; 54 | } else { 55 | return [self convertPoint:point toView:nil]; 56 | } 57 | } 58 | 59 | UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window; 60 | UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window; 61 | if ((!from || !to) || (from == to)) return [self convertPoint:point toView:view]; 62 | point = [self convertPoint:point toView:from]; 63 | point = [to convertPoint:point fromWindow:from]; 64 | point = [view convertPoint:point fromView:to]; 65 | return point; 66 | } 67 | 68 | - (CGPoint)yy_convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view { 69 | if (!view) { 70 | if ([self isKindOfClass:[UIWindow class]]) { 71 | return [((UIWindow *)self) convertPoint:point fromWindow:nil]; 72 | } else { 73 | return [self convertPoint:point fromView:nil]; 74 | } 75 | } 76 | 77 | UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window; 78 | UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window; 79 | if ((!from || !to) || (from == to)) return [self convertPoint:point fromView:view]; 80 | point = [from convertPoint:point fromView:view]; 81 | point = [to convertPoint:point fromWindow:from]; 82 | point = [self convertPoint:point fromView:to]; 83 | return point; 84 | } 85 | 86 | - (CGRect)yy_convertRect:(CGRect)rect toViewOrWindow:(UIView *)view { 87 | if (!view) { 88 | if ([self isKindOfClass:[UIWindow class]]) { 89 | return [((UIWindow *)self) convertRect:rect toWindow:nil]; 90 | } else { 91 | return [self convertRect:rect toView:nil]; 92 | } 93 | } 94 | 95 | UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window; 96 | UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window; 97 | if (!from || !to) return [self convertRect:rect toView:view]; 98 | if (from == to) return [self convertRect:rect toView:view]; 99 | rect = [self convertRect:rect toView:from]; 100 | rect = [to convertRect:rect fromWindow:from]; 101 | rect = [view convertRect:rect fromView:to]; 102 | return rect; 103 | } 104 | 105 | - (CGRect)yy_convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view { 106 | if (!view) { 107 | if ([self isKindOfClass:[UIWindow class]]) { 108 | return [((UIWindow *)self) convertRect:rect fromWindow:nil]; 109 | } else { 110 | return [self convertRect:rect fromView:nil]; 111 | } 112 | } 113 | 114 | UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window; 115 | UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window; 116 | if ((!from || !to) || (from == to)) return [self convertRect:rect fromView:view]; 117 | rect = [from convertRect:rect fromView:view]; 118 | rect = [to convertRect:rect fromWindow:from]; 119 | rect = [self convertRect:rect fromView:to]; 120 | return rect; 121 | } 122 | 123 | @end -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextAsyncLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextAsyncLayer.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/11. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | @class YYTextAsyncLayerDisplayTask; 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | 19 | /** 20 | The YYTextAsyncLayer class is a subclass of CALayer used for render contents asynchronously. 21 | 22 | @discussion When the layer need update it's contents, it will ask the delegate 23 | for a async display task to render the contents in a background queue. 24 | */ 25 | @interface YYTextAsyncLayer : CALayer 26 | /// Whether the render code is executed in background. Default is YES. 27 | @property BOOL displaysAsynchronously; 28 | @end 29 | 30 | 31 | /** 32 | The YYTextAsyncLayer's delegate protocol. The delegate of the YYTextAsyncLayer (typically a UIView) 33 | must implements the method in this protocol. 34 | */ 35 | @protocol YYTextAsyncLayerDelegate 36 | @required 37 | /// This method is called to return a new display task when the layer's contents need update. 38 | - (YYTextAsyncLayerDisplayTask *)newAsyncDisplayTask; 39 | @end 40 | 41 | 42 | /** 43 | A display task used by YYTextAsyncLayer to render the contents in background queue. 44 | */ 45 | @interface YYTextAsyncLayerDisplayTask : NSObject 46 | 47 | /** 48 | This block will be called before the asynchronous drawing begins. 49 | It will be called on the main thread. 50 | 51 | @param layer The layer. 52 | */ 53 | @property (nullable, nonatomic, copy) void (^willDisplay)(CALayer *layer); 54 | 55 | /** 56 | This block is called to draw the layer's contents. 57 | 58 | @discussion This block may be called on main thread or background thread, 59 | so is should be thread-safe. 60 | 61 | @param context A new bitmap content created by layer. 62 | @param size The content size (typically same as layer's bound size). 63 | @param isCancelled If this block returns `YES`, the method should cancel the 64 | drawing process and return as quickly as possible. 65 | */ 66 | @property (nullable, nonatomic, copy) void (^display)(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)); 67 | 68 | /** 69 | This block will be called after the asynchronous drawing finished. 70 | It will be called on the main thread. 71 | 72 | @param layer The layer. 73 | @param finished If the draw process is cancelled, it's `NO`, otherwise it's `YES`; 74 | */ 75 | @property (nullable, nonatomic, copy) void (^didDisplay)(CALayer *layer, BOOL finished); 76 | 77 | @end 78 | 79 | NS_ASSUME_NONNULL_END 80 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextAsyncLayer.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextAsyncLayer.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/11. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextAsyncLayer.h" 13 | #import 14 | 15 | 16 | /// Global display queue, used for content rendering. 17 | static dispatch_queue_t YYTextAsyncLayerGetDisplayQueue() { 18 | #define MAX_QUEUE_COUNT 16 19 | static int queueCount; 20 | static dispatch_queue_t queues[MAX_QUEUE_COUNT]; 21 | static dispatch_once_t onceToken; 22 | static int32_t counter = 0; 23 | dispatch_once(&onceToken, ^{ 24 | queueCount = (int)[NSProcessInfo processInfo].activeProcessorCount; 25 | queueCount = queueCount < 1 ? 1 : queueCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueCount; 26 | if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) { 27 | for (NSUInteger i = 0; i < queueCount; i++) { 28 | dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0); 29 | queues[i] = dispatch_queue_create("com.ibireme.text.render", attr); 30 | } 31 | } else { 32 | for (NSUInteger i = 0; i < queueCount; i++) { 33 | queues[i] = dispatch_queue_create("com.ibireme.text.render", DISPATCH_QUEUE_SERIAL); 34 | dispatch_set_target_queue(queues[i], dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 35 | } 36 | } 37 | }); 38 | int32_t cur = OSAtomicIncrement32(&counter); 39 | if (cur < 0) cur = -cur; 40 | return queues[(cur) % queueCount]; 41 | #undef MAX_QUEUE_COUNT 42 | } 43 | 44 | static dispatch_queue_t YYTextAsyncLayerGetReleaseQueue() { 45 | #ifdef YYDispatchQueuePool_h 46 | return YYDispatchQueueGetForQOS(NSQualityOfServiceDefault); 47 | #else 48 | return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); 49 | #endif 50 | } 51 | 52 | 53 | /// a thread safe incrementing counter. 54 | @interface _YYTextSentinel : NSObject 55 | /// Returns the current value of the counter. 56 | @property (atomic, readonly) int32_t value; 57 | /// Increase the value atomically. @return The new value. 58 | - (int32_t)increase; 59 | @end 60 | 61 | @implementation _YYTextSentinel { 62 | int32_t _value; 63 | } 64 | - (int32_t)value { 65 | return _value; 66 | } 67 | - (int32_t)increase { 68 | return OSAtomicIncrement32(&_value); 69 | } 70 | @end 71 | 72 | 73 | @implementation YYTextAsyncLayerDisplayTask 74 | @end 75 | 76 | 77 | @implementation YYTextAsyncLayer { 78 | _YYTextSentinel *_sentinel; 79 | } 80 | 81 | #pragma mark - Override 82 | 83 | + (id)defaultValueForKey:(NSString *)key { 84 | if ([key isEqualToString:@"displaysAsynchronously"]) { 85 | return @(YES); 86 | } else { 87 | return [super defaultValueForKey:key]; 88 | } 89 | } 90 | 91 | - (instancetype)init { 92 | self = [super init]; 93 | static CGFloat scale; //global 94 | static dispatch_once_t onceToken; 95 | dispatch_once(&onceToken, ^{ 96 | scale = [UIScreen mainScreen].scale; 97 | }); 98 | self.contentsScale = scale; 99 | _sentinel = [_YYTextSentinel new]; 100 | _displaysAsynchronously = YES; 101 | return self; 102 | } 103 | 104 | - (void)dealloc { 105 | [_sentinel increase]; 106 | } 107 | 108 | - (void)setNeedsDisplay { 109 | [self _cancelAsyncDisplay]; 110 | [super setNeedsDisplay]; 111 | } 112 | 113 | - (void)display { 114 | super.contents = super.contents; 115 | [self _displayAsync:_displaysAsynchronously]; 116 | } 117 | 118 | #pragma mark - Private 119 | 120 | - (void)_displayAsync:(BOOL)async { 121 | __strong id delegate = self.delegate; 122 | YYTextAsyncLayerDisplayTask *task = [delegate newAsyncDisplayTask]; 123 | if (!task.display) { 124 | if (task.willDisplay) task.willDisplay(self); 125 | self.contents = nil; 126 | if (task.didDisplay) task.didDisplay(self, YES); 127 | return; 128 | } 129 | 130 | if (async) { 131 | if (task.willDisplay) task.willDisplay(self); 132 | _YYTextSentinel *sentinel = _sentinel; 133 | int32_t value = sentinel.value; 134 | BOOL (^isCancelled)() = ^BOOL() { 135 | return value != sentinel.value; 136 | }; 137 | CGSize size = self.bounds.size; 138 | BOOL opaque = self.opaque; 139 | CGFloat scale = self.contentsScale; 140 | CGColorRef backgroundColor = (opaque && self.backgroundColor) ? CGColorRetain(self.backgroundColor) : NULL; 141 | if (size.width < 1 || size.height < 1) { 142 | CGImageRef image = (__bridge_retained CGImageRef)(self.contents); 143 | self.contents = nil; 144 | if (image) { 145 | dispatch_async(YYTextAsyncLayerGetReleaseQueue(), ^{ 146 | CFRelease(image); 147 | }); 148 | } 149 | if (task.didDisplay) task.didDisplay(self, YES); 150 | CGColorRelease(backgroundColor); 151 | return; 152 | } 153 | 154 | dispatch_async(YYTextAsyncLayerGetDisplayQueue(), ^{ 155 | if (isCancelled()) { 156 | CGColorRelease(backgroundColor); 157 | return; 158 | } 159 | UIGraphicsBeginImageContextWithOptions(size, opaque, scale); 160 | CGContextRef context = UIGraphicsGetCurrentContext(); 161 | if (opaque) { 162 | CGContextSaveGState(context); { 163 | if (!backgroundColor || CGColorGetAlpha(backgroundColor) < 1) { 164 | CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); 165 | CGContextAddRect(context, CGRectMake(0, 0, size.width * scale, size.height * scale)); 166 | CGContextFillPath(context); 167 | } 168 | if (backgroundColor) { 169 | CGContextSetFillColorWithColor(context, backgroundColor); 170 | CGContextAddRect(context, CGRectMake(0, 0, size.width * scale, size.height * scale)); 171 | CGContextFillPath(context); 172 | } 173 | } CGContextRestoreGState(context); 174 | CGColorRelease(backgroundColor); 175 | } 176 | task.display(context, size, isCancelled); 177 | if (isCancelled()) { 178 | UIGraphicsEndImageContext(); 179 | dispatch_async(dispatch_get_main_queue(), ^{ 180 | if (task.didDisplay) task.didDisplay(self, NO); 181 | }); 182 | return; 183 | } 184 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 185 | UIGraphicsEndImageContext(); 186 | if (isCancelled()) { 187 | dispatch_async(dispatch_get_main_queue(), ^{ 188 | if (task.didDisplay) task.didDisplay(self, NO); 189 | }); 190 | return; 191 | } 192 | dispatch_async(dispatch_get_main_queue(), ^{ 193 | if (isCancelled()) { 194 | if (task.didDisplay) task.didDisplay(self, NO); 195 | } else { 196 | self.contents = (__bridge id)(image.CGImage); 197 | if (task.didDisplay) task.didDisplay(self, YES); 198 | } 199 | }); 200 | }); 201 | } else { 202 | [_sentinel increase]; 203 | if (task.willDisplay) task.willDisplay(self); 204 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, self.contentsScale); 205 | CGContextRef context = UIGraphicsGetCurrentContext(); 206 | if (self.opaque) { 207 | CGSize size = self.bounds.size; 208 | size.width *= self.contentsScale; 209 | size.height *= self.contentsScale; 210 | CGContextSaveGState(context); { 211 | if (!self.backgroundColor || CGColorGetAlpha(self.backgroundColor) < 1) { 212 | CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); 213 | CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height)); 214 | CGContextFillPath(context); 215 | } 216 | if (self.backgroundColor) { 217 | CGContextSetFillColorWithColor(context, self.backgroundColor); 218 | CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height)); 219 | CGContextFillPath(context); 220 | } 221 | } CGContextRestoreGState(context); 222 | } 223 | task.display(context, self.bounds.size, ^{return NO;}); 224 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 225 | UIGraphicsEndImageContext(); 226 | self.contents = (__bridge id)(image.CGImage); 227 | if (task.didDisplay) task.didDisplay(self, YES); 228 | } 229 | } 230 | 231 | - (void)_cancelAsyncDisplay { 232 | [_sentinel increase]; 233 | } 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextTransaction.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextTransaction.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | YYTextTransaction let you perform a selector once before current runloop sleep. 18 | */ 19 | @interface YYTextTransaction : NSObject 20 | 21 | /** 22 | Creates and returns a transaction with a specified target and selector. 23 | 24 | @param target A specified target, the target is retained until runloop end. 25 | @param selector A selector for target. 26 | 27 | @return A new transaction, or nil if an error occurs. 28 | */ 29 | + (YYTextTransaction *)transactionWithTarget:(id)target selector:(SEL)selector; 30 | 31 | /** 32 | Commit the trancaction to main runloop. 33 | 34 | @discussion It will perform the selector on the target once before main runloop's 35 | current loop sleep. If the same transaction (same target and same selector) has 36 | already commit to runloop in this loop, this method do nothing. 37 | */ 38 | - (void)commit; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextTransaction.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextTransaction.m 3 | // YYText 4 | // 5 | // Created by ibireme on 15/4/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextTransaction.h" 13 | 14 | 15 | @interface YYTextTransaction() 16 | @property (nonatomic, strong) id target; 17 | @property (nonatomic, assign) SEL selector; 18 | @end 19 | 20 | static NSMutableSet *transactionSet = nil; 21 | 22 | static void YYRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { 23 | if (transactionSet.count == 0) return; 24 | NSSet *currentSet = transactionSet; 25 | transactionSet = [NSMutableSet new]; 26 | [currentSet enumerateObjectsUsingBlock:^(YYTextTransaction *transaction, BOOL *stop) { 27 | #pragma clang diagnostic push 28 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 29 | [transaction.target performSelector:transaction.selector]; 30 | #pragma clang diagnostic pop 31 | }]; 32 | } 33 | 34 | static void YYTextTransactionSetup() { 35 | static dispatch_once_t onceToken; 36 | dispatch_once(&onceToken, ^{ 37 | transactionSet = [NSMutableSet new]; 38 | CFRunLoopRef runloop = CFRunLoopGetMain(); 39 | CFRunLoopObserverRef observer; 40 | 41 | observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(), 42 | kCFRunLoopBeforeWaiting | kCFRunLoopExit, 43 | true, // repeat 44 | 0xFFFFFF, // after CATransaction(2000000) 45 | YYRunLoopObserverCallBack, NULL); 46 | CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes); 47 | CFRelease(observer); 48 | }); 49 | } 50 | 51 | 52 | @implementation YYTextTransaction 53 | 54 | + (YYTextTransaction *)transactionWithTarget:(id)target selector:(SEL)selector{ 55 | if (!target || !selector) return nil; 56 | YYTextTransaction *t = [YYTextTransaction new]; 57 | t.target = target; 58 | t.selector = selector; 59 | return t; 60 | } 61 | 62 | - (void)commit { 63 | if (!_target || !_selector) return; 64 | YYTextTransactionSetup(); 65 | [transactionSet addObject:self]; 66 | } 67 | 68 | - (NSUInteger)hash { 69 | long v1 = (long)((void *)_selector); 70 | long v2 = (long)_target; 71 | return v1 ^ v2; 72 | } 73 | 74 | - (BOOL)isEqual:(id)object { 75 | if (self == object) return YES; 76 | if (![object isMemberOfClass:self.class]) return NO; 77 | YYTextTransaction *other = object; 78 | return other.selector == _selector && other.target == _target; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextWeakProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextWeakProxy.h 3 | // YYText 4 | // 5 | // Created by ibireme on 14/10/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | A proxy used to hold a weak object. 18 | It can be used to avoid retain cycles, such as the target in NSTimer or CADisplayLink. 19 | 20 | sample code: 21 | 22 | @implementation MyView { 23 | NSTimer *_timer; 24 | } 25 | 26 | - (void)initTimer { 27 | YYTextWeakProxy *proxy = [YYTextWeakProxy proxyWithTarget:self]; 28 | _timer = [NSTimer timerWithTimeInterval:0.1 target:proxy selector:@selector(tick:) userInfo:nil repeats:YES]; 29 | } 30 | 31 | - (void)tick:(NSTimer *)timer {...} 32 | @end 33 | */ 34 | @interface YYTextWeakProxy : NSProxy 35 | 36 | /** 37 | The proxy target. 38 | */ 39 | @property (nullable, nonatomic, weak, readonly) id target; 40 | 41 | /** 42 | Creates a new weak proxy for target. 43 | 44 | @param target Target object. 45 | 46 | @return A new proxy object. 47 | */ 48 | - (instancetype)initWithTarget:(id)target; 49 | 50 | /** 51 | Creates a new weak proxy for target. 52 | 53 | @param target Target object. 54 | 55 | @return A new proxy object. 56 | */ 57 | + (instancetype)proxyWithTarget:(id)target; 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/Utility/YYTextWeakProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextWeakProxy.m 3 | // YYText 4 | // 5 | // Created by ibireme on 14/10/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYTextWeakProxy.h" 13 | 14 | 15 | @implementation YYTextWeakProxy 16 | 17 | - (instancetype)initWithTarget:(id)target { 18 | _target = target; 19 | return self; 20 | } 21 | 22 | + (instancetype)proxyWithTarget:(id)target { 23 | return [[YYTextWeakProxy alloc] initWithTarget:target]; 24 | } 25 | 26 | - (id)forwardingTargetForSelector:(SEL)selector { 27 | return _target; 28 | } 29 | 30 | - (void)forwardInvocation:(NSInvocation *)invocation { 31 | void *null = NULL; 32 | [invocation setReturnValue:&null]; 33 | } 34 | 35 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { 36 | return [NSObject instanceMethodSignatureForSelector:@selector(init)]; 37 | } 38 | 39 | - (BOOL)respondsToSelector:(SEL)aSelector { 40 | return [_target respondsToSelector:aSelector]; 41 | } 42 | 43 | - (BOOL)isEqual:(id)object { 44 | return [_target isEqual:object]; 45 | } 46 | 47 | - (NSUInteger)hash { 48 | return [_target hash]; 49 | } 50 | 51 | - (Class)superclass { 52 | return [_target superclass]; 53 | } 54 | 55 | - (Class)class { 56 | return [_target class]; 57 | } 58 | 59 | - (BOOL)isKindOfClass:(Class)aClass { 60 | return [_target isKindOfClass:aClass]; 61 | } 62 | 63 | - (BOOL)isMemberOfClass:(Class)aClass { 64 | return [_target isMemberOfClass:aClass]; 65 | } 66 | 67 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol { 68 | return [_target conformsToProtocol:aProtocol]; 69 | } 70 | 71 | - (BOOL)isProxy { 72 | return YES; 73 | } 74 | 75 | - (NSString *)description { 76 | return [_target description]; 77 | } 78 | 79 | - (NSString *)debugDescription { 80 | return [_target debugDescription]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Pods/YYText/YYText/YYText.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYText.h 3 | // YYText 4 | // 5 | // Created by ibireme on 15/2/25. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYTextVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYTextVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | #import 33 | #else 34 | #import "YYLabel.h" 35 | #import "YYTextView.h" 36 | #import "YYTextAttribute.h" 37 | #import "YYTextArchiver.h" 38 | #import "YYTextParser.h" 39 | #import "YYTextRunDelegate.h" 40 | #import "YYTextRubyAnnotation.h" 41 | #import "YYTextLayout.h" 42 | #import "YYTextLine.h" 43 | #import "YYTextInput.h" 44 | #import "YYTextDebugOption.h" 45 | #import "YYTextKeyboardManager.h" 46 | #import "YYTextUtilities.h" 47 | #import "NSAttributedString+YYText.h" 48 | #import "NSParagraphStyle+YYText.h" 49 | #import "UIPasteboard+YYText.h" 50 | #endif 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #[YYText](https://github.com/ibireme/YYText) Swift Demo 2 | 3 | ![demo](https://cloud.githubusercontent.com/assets/16911734/12603881/60c8bed4-c4f1-11e5-8d25-211047d29f4b.png) 4 | -------------------------------------------------------------------------------- /YYTextSwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YYTextSwiftDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/27/16. 6 | // Copyright © 2016 Hilen. 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 throttle down OpenGL ES frame rates. 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 inactive 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 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/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 | } -------------------------------------------------------------------------------- /YYTextSwiftDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /YYTextSwiftDemo/Assets.xcassets/dribbble64_imageio.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "dribbble64_imageio.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /YYTextSwiftDemo/Assets.xcassets/dribbble64_imageio.imageset/dribbble64_imageio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hilen/YYTextSwiftDemo/8759dd9f1c77ac05708aebe32eb49f5018201231/YYTextSwiftDemo/Assets.xcassets/dribbble64_imageio.imageset/dribbble64_imageio.png -------------------------------------------------------------------------------- /YYTextSwiftDemo/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 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/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 | 32 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/Helpers/String+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Extension.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/19/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | func stringHeightWithMaxWidth(_ maxWidth: CGFloat, font: UIFont) -> CGFloat { 13 | let attributes: [String : AnyObject] = [ 14 | NSFontAttributeName: font, 15 | ] 16 | let size: CGSize = self.boundingRect( 17 | with: CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude), 18 | options: NSStringDrawingOptions.usesLineFragmentOrigin, 19 | attributes: attributes, 20 | context: nil 21 | ).size 22 | return size.height 23 | } 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/Helpers/TextLinePositionModifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextLinePositionModifier.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/22/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import YYText 11 | 12 | private let ascentScale: CGFloat = 0.84 13 | private let descentScale: CGFloat = 0.16 14 | 15 | class TextLinePositionModifier: NSObject, YYTextLinePositionModifier { 16 | 17 | internal var font: UIFont // 基准字体 (例如 Heiti SC/PingFang SC) 18 | fileprivate var paddingTop: CGFloat = 2 //文本顶部留白 19 | fileprivate var paddingBottom: CGFloat = 2 //文本底部留白 20 | fileprivate var lineHeightMultiple: CGFloat //行距倍数 21 | 22 | required init(font: UIFont) { 23 | if (UIDevice.current.systemVersion as NSString).floatValue >= 9.0 { 24 | self.lineHeightMultiple = 1.2 // for PingFang SC 25 | } else { 26 | self.lineHeightMultiple = 1.1725 // for Heiti SC 27 | } 28 | self.font = font 29 | super.init() 30 | } 31 | 32 | // MARK: - @delegate YYTextLinePositionModifier 33 | func modifyLines(_ lines: [YYTextLine], fromText text: NSAttributedString, in container: YYTextContainer) { 34 | let ascent: CGFloat = self.font.pointSize * ascentScale 35 | let lineHeight: CGFloat = self.font.pointSize * self.lineHeightMultiple 36 | for line: YYTextLine in lines { 37 | var position: CGPoint = line.position 38 | position.y = self.paddingTop + ascent + CGFloat(line.row) * lineHeight 39 | line.position = position 40 | } 41 | } 42 | 43 | // MARK: - @delegate NSCopying 44 | func copy(with zone: NSZone?) -> Any { 45 | let one = type(of: self).init(font: self.font) 46 | return one 47 | } 48 | 49 | func heightForLineCount(_ lineCount: Int) -> CGFloat { 50 | if lineCount == 0 { 51 | return 0 52 | } 53 | 54 | let ascent: CGFloat = self.font.pointSize * ascentScale; 55 | let descent: CGFloat = self.font.pointSize * descentScale 56 | let lineHeight: CGFloat = self.font.pointSize * self.lineHeightMultiple 57 | return self.paddingTop + self.paddingBottom + ascent + descent + CGFloat((lineCount - 1)) * lineHeight; 58 | } 59 | 60 | } 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/Helpers/TextParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextParser.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/22/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import YYText 11 | 12 | public let kSpeedChatTextKeyPhone = "phone" 13 | public let kSpeedChatTextKeyURL = "URL" 14 | 15 | class TextParser: NSObject { 16 | class func parseText(_ text: String, font: UIFont) -> NSMutableAttributedString? { 17 | if text.characters.count == 0 { 18 | return nil 19 | } 20 | 21 | let attributedText: NSMutableAttributedString = NSMutableAttributedString(string: text) 22 | attributedText.yy_font = font 23 | attributedText.yy_color = UIColor.black 24 | 25 | //匹配电话 26 | self.enumeratePhoneParser(attributedText) 27 | //匹配 URL 28 | self.enumerateURLParser(attributedText) 29 | //匹配 [表情] 30 | self.enumerateEmotionParser(attributedText, fontSize: font.pointSize) 31 | 32 | return attributedText 33 | } 34 | 35 | /** 36 | 匹配电话 37 | 38 | - parameter attributedText: 富文本 39 | */ 40 | fileprivate class func enumeratePhoneParser(_ attributedText: NSMutableAttributedString) { 41 | let phonesResults = TextParseHelper.regexPhoneNumber.matches( 42 | in: attributedText.string, 43 | options: [.reportProgress], 44 | range: attributedText.yy_rangeOfAll() 45 | ) 46 | for phone: NSTextCheckingResult in phonesResults { 47 | if phone.range.location == NSNotFound && phone.range.length <= 1 { 48 | continue 49 | } 50 | 51 | if (attributedText.yy_attribute(YYTextHighlightAttributeName, at: UInt(phone.range.location)) == nil) { 52 | attributedText.yy_setColor(UIColor.yellow, range: phone.range) 53 | let highlight = YYTextHighlight() 54 | let stringRange = attributedText.string.range(from:phone.range)! 55 | highlight.userInfo = [kSpeedChatTextKeyPhone : attributedText.string.substring(with: stringRange)] 56 | attributedText.yy_setTextHighlight(highlight, range: phone.range) 57 | } 58 | } 59 | } 60 | 61 | /** 62 | 匹配 URL 63 | 64 | - parameter attributedText: 富文本 65 | */ 66 | fileprivate class func enumerateURLParser(_ attributedText: NSMutableAttributedString) { 67 | let URLsResults = TextParseHelper.regexURLs.matches( 68 | in: attributedText.string, 69 | options: [.reportProgress], 70 | range: attributedText.yy_rangeOfAll() 71 | ) 72 | for URL: NSTextCheckingResult in URLsResults { 73 | if URL.range.location == NSNotFound && URL.range.length <= 1 { 74 | continue 75 | } 76 | 77 | if (attributedText.yy_attribute(YYTextHighlightAttributeName, at: UInt(URL.range.location)) == nil) { 78 | attributedText.yy_setColor(UIColor.yellow, range: URL.range) 79 | let highlight = YYTextHighlight() 80 | let stringRange = attributedText.string.range(from: URL.range)! 81 | highlight.userInfo = [kSpeedChatTextKeyURL : attributedText.string.substring(with: stringRange)] 82 | attributedText.yy_setTextHighlight(highlight, range: URL.range) 83 | } 84 | } 85 | } 86 | 87 | /** 88 | /匹配 [表情] 89 | 90 | - parameter attributedText: 富文本 91 | - parameter fontSize: 字体大小 92 | */ 93 | fileprivate class func enumerateEmotionParser(_ attributedText: NSMutableAttributedString, fontSize: CGFloat) { 94 | let emoticonResults = TextParseHelper.regexEmotions.matches( 95 | in: attributedText.string, 96 | options: [.reportProgress], 97 | range: attributedText.yy_rangeOfAll() 98 | ) 99 | var emoClipLength: Int = 0 100 | for emotion: NSTextCheckingResult in emoticonResults { 101 | if emotion.range.location == NSNotFound && emotion.range.length <= 1 { 102 | continue 103 | } 104 | var range: NSRange = emotion.range 105 | range.location -= emoClipLength 106 | if (attributedText.yy_attribute(YYTextHighlightAttributeName, at: UInt(range.location)) != nil) { 107 | continue 108 | } 109 | if (attributedText.yy_attribute(YYTextAttachmentAttributeName, at: UInt(range.location)) != nil) { 110 | continue 111 | } 112 | 113 | //这里写死了一个表情 114 | let _ = attributedText.string.substring(with: attributedText.string.range(from:range)!) 115 | // let imagePath = "111111111111,表情路径" 116 | // print("emotionString,imagePath:\(emotionString,imagePath)") 117 | guard let image = UIImage(named: "dribbble64_imageio") else { 118 | continue 119 | } 120 | 121 | let emoText = NSMutableAttributedString.yy_attachmentString(withEmojiImage: image, fontSize: fontSize) 122 | attributedText.replaceCharacters(in: range, with: emoText!) 123 | 124 | emoClipLength += range.length - 1 125 | } 126 | } 127 | } 128 | 129 | 130 | private class TextParseHelper { 131 | /** 132 | 正则:匹配 [哈哈] [笑哭。。] 表情 133 | */ 134 | class var regexEmotions: NSRegularExpression { 135 | get { 136 | let regularExpression = try! NSRegularExpression(pattern: "\\[[^\\[\\]]+?\\]", options: [.caseInsensitive]) 137 | return regularExpression 138 | } 139 | } 140 | 141 | /** 142 | 正则:匹配 www.a.com 或者 http://www.a.com 的类型 143 | 144 | ref: http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url 145 | */ 146 | class var regexURLs: NSRegularExpression { 147 | get { 148 | let regex: String = "([hH]ttp[s]{0,1})://[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)|[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)" 149 | let regularExpression = try! NSRegularExpression(pattern: regex, options: [.caseInsensitive]) 150 | return regularExpression 151 | } 152 | } 153 | 154 | /** 155 | 正则:匹配 7-25 位的数字, 010-62104321, 0373-5957800, 010-62104321-230 156 | */ 157 | class var regexPhoneNumber: NSRegularExpression { 158 | get { 159 | let regex = "([\\d]{7,25}(?!\\d))|((\\d{3,4})-(\\d{7,8}))|((\\d{3,4})-(\\d{7,8})-(\\d{1,4}))" 160 | let regularExpression = try! NSRegularExpression(pattern: regex, options: [.caseInsensitive]) 161 | return regularExpression 162 | } 163 | } 164 | } 165 | 166 | 167 | //http://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index 168 | private extension String { 169 | func nsRange(from range: Range) -> NSRange { 170 | let utf16view = self.utf16 171 | let from = range.lowerBound.samePosition(in: utf16view) 172 | let to = range.upperBound.samePosition(in: utf16view) 173 | return NSMakeRange(utf16view.distance(from: utf16view.startIndex, to: from), 174 | utf16view.distance(from: from, to: to)) 175 | } 176 | 177 | func range(from nsRange: NSRange) -> Range? { 178 | guard 179 | let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex), 180 | let to16 = utf16.index(from16, offsetBy: nsRange.length, limitedBy: utf16.endIndex), 181 | let from = String.Index(from16, within: self), 182 | let to = String.Index(to16, within: self) 183 | else { return nil } 184 | return from ..< to 185 | } 186 | } 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/Helpers/UILabel+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel+Extension.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/19/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UILabel { 12 | func contentSize() -> CGSize { 13 | let paragraphStyle = NSMutableParagraphStyle() 14 | paragraphStyle.lineBreakMode = self.lineBreakMode 15 | paragraphStyle.alignment = self.textAlignment 16 | let attributes: [String : AnyObject] = [NSFontAttributeName: self.font, NSParagraphStyleAttributeName: paragraphStyle] 17 | let contentSize: CGSize = self.text!.boundingRect( 18 | with: self.frame.size, 19 | options: ([.usesLineFragmentOrigin, .usesFontLeading]), 20 | attributes: attributes, 21 | context: nil 22 | ).size 23 | return contentSize 24 | } 25 | 26 | func setFrameWithString(_ string: String, width: CGFloat) { 27 | self.numberOfLines = 0 28 | let attributes: [String : AnyObject] = [ 29 | NSFontAttributeName: self.font, 30 | ] 31 | let resultSize: CGSize = string.boundingRect( 32 | with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), 33 | options: NSStringDrawingOptions.usesLineFragmentOrigin, 34 | attributes: attributes, 35 | context: nil 36 | ).size 37 | let resultHeight: CGFloat = resultSize.height 38 | let resultWidth: CGFloat = resultSize.width 39 | var frame: CGRect = self.frame 40 | frame.size.height = resultHeight 41 | frame.size.width = resultWidth 42 | self.frame = frame 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/Helpers/UIView+Frame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Frame.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/21/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIView { 12 | var width: CGFloat { 13 | get { return self.frame.size.width } 14 | set { 15 | var frame = self.frame 16 | frame.size.width = newValue 17 | self.frame = frame 18 | } 19 | } 20 | 21 | var height: CGFloat { 22 | get { return self.frame.size.height } 23 | set { 24 | var frame = self.frame 25 | frame.size.height = newValue 26 | self.frame = frame 27 | } 28 | } 29 | 30 | var size: CGSize { 31 | get { return self.frame.size } 32 | set { 33 | var frame = self.frame 34 | frame.size = newValue 35 | self.frame = frame 36 | } 37 | } 38 | 39 | var origin: CGPoint { 40 | get { return self.frame.origin } 41 | set { 42 | var frame = self.frame 43 | frame.origin = newValue 44 | self.frame = frame 45 | } 46 | } 47 | 48 | var x: CGFloat { 49 | get { return self.frame.origin.x } 50 | set { 51 | var frame = self.frame 52 | frame.origin.x = newValue 53 | self.frame = frame 54 | } 55 | } 56 | var y: CGFloat { 57 | get { return self.frame.origin.y } 58 | set { 59 | var frame = self.frame 60 | frame.origin.y = newValue 61 | self.frame = frame 62 | } 63 | } 64 | 65 | var centerX: CGFloat { 66 | get { return self.center.x } 67 | set { 68 | self.center = CGPoint(x: newValue, y: self.center.y) 69 | } 70 | } 71 | 72 | var centerY: CGFloat { 73 | get { return self.center.y } 74 | set { 75 | self.center = CGPoint(x: self.center.x, y: newValue) 76 | } 77 | } 78 | 79 | var top : CGFloat { 80 | get { return self.frame.origin.y } 81 | set { 82 | var frame = self.frame 83 | frame.origin.y = newValue 84 | self.frame = frame 85 | } 86 | } 87 | 88 | var bottom : CGFloat { 89 | get { return frame.origin.y + frame.size.height } 90 | set { 91 | var frame = self.frame 92 | frame.origin.y = newValue - frame.size.height 93 | self.frame = frame 94 | } 95 | } 96 | 97 | var right : CGFloat { 98 | get { return self.frame.origin.x + self.frame.size.width } 99 | set { 100 | var frame = self.frame 101 | frame.origin.x = newValue - frame.size.width 102 | self.frame = frame 103 | } 104 | } 105 | 106 | var left : CGFloat { 107 | get { return self.frame.origin.x } 108 | set { 109 | var frame = self.frame 110 | frame.origin.x = newValue 111 | self.frame = frame 112 | } 113 | } 114 | } 115 | 116 | 117 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/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 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // YYTextSwiftDemo 4 | // 5 | // Created by Hilen on 1/27/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import YYText 11 | 12 | private let fontSize:CGFloat = 16 13 | 14 | class ViewController: UIViewController { 15 | @IBOutlet weak var leftYYLabel: YYLabel! 16 | @IBOutlet weak var rightUILabel: UILabel! 17 | @IBOutlet weak var contentScrollView: UIScrollView! 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | let maxWidth: CGFloat = 140 21 | let targetSize = CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude) 22 | let targetFont: UIFont = UIFont.systemFont(ofSize: fontSize) 23 | // let testString: String = " 😯这是一段测试文字,this is test text. 😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--1😯狗狗不理😷🤖👹🤖👽😾👊🏼🏛🍜🍠◽️☆_🔛🔲🔊🔔🔇🇫🇯🇬🇲☆入:--2222" 24 | let testString: String = "这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,这是一段测试的数据,测试富文本高度来使用,因为微信有部分内容,123456789 所以就问问你那边做到啥成都, ios uilabel lineheight value,ios uilabel http://www.baidu.com lineheight 010-62998383 value,ios uilabel [呵呵]lineheight value,[呵]4" 25 | 26 | self.setupYYLabel(testString, targetSize: targetSize, font: targetFont) 27 | self.setupUILabel(testString, targetSize: targetSize, font: targetFont, maxWidth: maxWidth) 28 | self.contentScrollView.contentSize = CGSize(width: UIScreen.main.bounds.size.width, height: self.rightUILabel.height + 200) 29 | self.contentScrollView.size = UIScreen.main.bounds.size 30 | } 31 | 32 | func setupYYLabel(_ text: String, targetSize: CGSize, font: UIFont) { 33 | //解析的文字 34 | let attributedString = TextParser.parseText(text, font: font)! 35 | //布局 36 | let modifier = TextLinePositionModifier(font: font) 37 | 38 | self.leftYYLabel.attributedText = attributedString 39 | self.leftYYLabel.debugOption = self.debugYYLabel() 40 | self.leftYYLabel.numberOfLines = 0 41 | self.leftYYLabel.linePositionModifier = modifier 42 | self.leftYYLabel.backgroundColor = UIColor ( red: 0.7799, green: 0.7799, blue: 0.7799, alpha: 1.0 ) 43 | self.leftYYLabel.textVerticalAlignment = YYTextVerticalAlignment.top 44 | self.leftYYLabel.lineBreakMode = .byWordWrapping 45 | self.leftYYLabel.displaysAsynchronously = true 46 | self.leftYYLabel.ignoreCommonProperties = true 47 | self.leftYYLabel.highlightTapAction = ({containerView, text, range, rect in 48 | print("highlightTapAction taped") 49 | }) 50 | 51 | let textContainer: YYTextContainer = YYTextContainer() 52 | textContainer.size = targetSize 53 | textContainer.linePositionModifier = modifier 54 | textContainer.maximumNumberOfRows = 0 55 | 56 | let textLayout = YYTextLayout(container: textContainer, text: attributedString) 57 | self.leftYYLabel.textLayout = textLayout 58 | self.leftYYLabel.width = textLayout!.textBoundingSize.width 59 | 60 | let contentHeight = modifier.heightForLineCount(Int(textLayout!.rowCount)) 61 | self.leftYYLabel.height = contentHeight 62 | } 63 | 64 | func setupUILabel(_ text: String, targetSize: CGSize, font: UIFont, maxWidth: CGFloat) { 65 | self.rightUILabel.font = font 66 | self.rightUILabel.text = text 67 | self.rightUILabel.numberOfLines = 0 68 | self.rightUILabel.lineBreakMode = .byWordWrapping 69 | self.rightUILabel.backgroundColor = UIColor.yellow 70 | self.rightUILabel.setFrameWithString(text, width: maxWidth) 71 | print("rightUILabel:\(self.rightUILabel)") 72 | } 73 | 74 | func debugYYLabel() -> YYTextDebugOption { 75 | let debugOptions = YYTextDebugOption() 76 | debugOptions.baselineColor = UIColor.red; 77 | debugOptions.ctFrameBorderColor = UIColor.red; 78 | debugOptions.ctLineFillColor = UIColor ( red: 0.0, green: 0.463, blue: 1.0, alpha: 0.18 ) 79 | debugOptions.cgGlyphBorderColor = UIColor ( red: 0.9971, green: 0.6738, blue: 1.0, alpha: 0.360964912280702 ) 80 | return debugOptions 81 | } 82 | 83 | override func didReceiveMemoryWarning() { 84 | super.didReceiveMemoryWarning() 85 | // Dispose of any resources that can be recreated. 86 | } 87 | 88 | 89 | } 90 | 91 | -------------------------------------------------------------------------------- /YYTextSwiftDemo/YYTextSwiftDemo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | @import UIKit; 6 | 7 | #import 8 | #import 9 | -------------------------------------------------------------------------------- /YYTextSwiftDemoTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /YYTextSwiftDemoTests/YYTextSwiftDemoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YYTextSwiftDemoTests.swift 3 | // YYTextSwiftDemoTests 4 | // 5 | // Created by Hilen on 1/27/16. 6 | // Copyright © 2016 Hilen. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import YYTextSwiftDemo 11 | 12 | class YYTextSwiftDemoTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | --------------------------------------------------------------------------------