├── JKRShimmeringLabel.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── huhuaiyi.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── huhuaiyi.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── JKRShimmeringLabel
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── JKRLabel
│ ├── JKRAutoScrollLabel.h
│ ├── JKRAutoScrollLabel.m
│ ├── JKRShimmeringLabel.h
│ └── JKRShimmeringLabel.m
├── ViewController.h
├── ViewController.m
├── YYKit
│ ├── Base
│ │ ├── Foundation
│ │ │ ├── NSArray+YYAdd.h
│ │ │ ├── NSArray+YYAdd.m
│ │ │ ├── NSBundle+YYAdd.h
│ │ │ ├── NSBundle+YYAdd.m
│ │ │ ├── NSData+YYAdd.h
│ │ │ ├── NSData+YYAdd.m
│ │ │ ├── NSDate+YYAdd.h
│ │ │ ├── NSDate+YYAdd.m
│ │ │ ├── NSDictionary+YYAdd.h
│ │ │ ├── NSDictionary+YYAdd.m
│ │ │ ├── NSKeyedUnarchiver+YYAdd.h
│ │ │ ├── NSKeyedUnarchiver+YYAdd.m
│ │ │ ├── NSNotificationCenter+YYAdd.h
│ │ │ ├── NSNotificationCenter+YYAdd.m
│ │ │ ├── NSNumber+YYAdd.h
│ │ │ ├── NSNumber+YYAdd.m
│ │ │ ├── NSObject+YYAdd.h
│ │ │ ├── NSObject+YYAdd.m
│ │ │ ├── NSObject+YYAddForARC.h
│ │ │ ├── NSObject+YYAddForARC.m
│ │ │ ├── NSObject+YYAddForKVO.h
│ │ │ ├── NSObject+YYAddForKVO.m
│ │ │ ├── NSString+YYAdd.h
│ │ │ ├── NSString+YYAdd.m
│ │ │ ├── NSThread+YYAdd.h
│ │ │ ├── NSThread+YYAdd.m
│ │ │ ├── NSTimer+YYAdd.h
│ │ │ └── NSTimer+YYAdd.m
│ │ ├── Quartz
│ │ │ ├── CALayer+YYAdd.h
│ │ │ ├── CALayer+YYAdd.m
│ │ │ ├── YYCGUtilities.h
│ │ │ └── YYCGUtilities.m
│ │ ├── UIKit
│ │ │ ├── UIApplication+YYAdd.h
│ │ │ ├── UIApplication+YYAdd.m
│ │ │ ├── UIBarButtonItem+YYAdd.h
│ │ │ ├── UIBarButtonItem+YYAdd.m
│ │ │ ├── UIBezierPath+YYAdd.h
│ │ │ ├── UIBezierPath+YYAdd.m
│ │ │ ├── UIColor+YYAdd.h
│ │ │ ├── UIColor+YYAdd.m
│ │ │ ├── UIControl+YYAdd.h
│ │ │ ├── UIControl+YYAdd.m
│ │ │ ├── UIDevice+YYAdd.h
│ │ │ ├── UIDevice+YYAdd.m
│ │ │ ├── UIFont+YYAdd.h
│ │ │ ├── UIFont+YYAdd.m
│ │ │ ├── UIGestureRecognizer+YYAdd.h
│ │ │ ├── UIGestureRecognizer+YYAdd.m
│ │ │ ├── UIImage+YYAdd.h
│ │ │ ├── UIImage+YYAdd.m
│ │ │ ├── UIScreen+YYAdd.h
│ │ │ ├── UIScreen+YYAdd.m
│ │ │ ├── UIScrollView+YYAdd.h
│ │ │ ├── UIScrollView+YYAdd.m
│ │ │ ├── UITableView+YYAdd.h
│ │ │ ├── UITableView+YYAdd.m
│ │ │ ├── UITextField+YYAdd.h
│ │ │ ├── UITextField+YYAdd.m
│ │ │ ├── UIView+YYAdd.h
│ │ │ └── UIView+YYAdd.m
│ │ └── YYKitMacro.h
│ ├── Cache
│ │ ├── YYCache.h
│ │ ├── YYCache.m
│ │ ├── YYDiskCache.h
│ │ ├── YYDiskCache.m
│ │ ├── YYKVStorage.h
│ │ ├── YYKVStorage.m
│ │ ├── YYMemoryCache.h
│ │ └── YYMemoryCache.m
│ ├── Image
│ │ ├── Categories
│ │ │ ├── CALayer+YYWebImage.h
│ │ │ ├── CALayer+YYWebImage.m
│ │ │ ├── MKAnnotationView+YYWebImage.h
│ │ │ ├── MKAnnotationView+YYWebImage.m
│ │ │ ├── UIButton+YYWebImage.h
│ │ │ ├── UIButton+YYWebImage.m
│ │ │ ├── UIImageView+YYWebImage.h
│ │ │ ├── UIImageView+YYWebImage.m
│ │ │ ├── _YYWebImageSetter.h
│ │ │ └── _YYWebImageSetter.m
│ │ ├── YYAnimatedImageView.h
│ │ ├── YYAnimatedImageView.m
│ │ ├── YYFrameImage.h
│ │ ├── YYFrameImage.m
│ │ ├── YYImage.h
│ │ ├── YYImage.m
│ │ ├── YYImageCache.h
│ │ ├── YYImageCache.m
│ │ ├── YYImageCoder.h
│ │ ├── YYImageCoder.m
│ │ ├── YYSpriteSheetImage.h
│ │ ├── YYSpriteSheetImage.m
│ │ ├── YYWebImageManager.h
│ │ ├── YYWebImageManager.m
│ │ ├── YYWebImageOperation.h
│ │ └── YYWebImageOperation.m
│ ├── Model
│ │ ├── NSObject+YYModel.h
│ │ ├── NSObject+YYModel.m
│ │ ├── YYClassInfo.h
│ │ └── YYClassInfo.m
│ ├── Text
│ │ ├── 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
│ │ │ ├── NSAttributedString+YYText.h
│ │ │ ├── NSAttributedString+YYText.m
│ │ │ ├── NSParagraphStyle+YYText.h
│ │ │ ├── NSParagraphStyle+YYText.m
│ │ │ ├── UIPasteboard+YYText.h
│ │ │ ├── UIPasteboard+YYText.m
│ │ │ ├── YYTextArchiver.h
│ │ │ ├── YYTextArchiver.m
│ │ │ ├── YYTextAttribute.h
│ │ │ ├── YYTextAttribute.m
│ │ │ ├── YYTextParser.h
│ │ │ ├── YYTextParser.m
│ │ │ ├── YYTextRubyAnnotation.h
│ │ │ ├── YYTextRubyAnnotation.m
│ │ │ ├── YYTextRunDelegate.h
│ │ │ ├── YYTextRunDelegate.m
│ │ │ ├── YYTextUtilities.h
│ │ │ └── YYTextUtilities.m
│ │ ├── YYLabel.h
│ │ ├── YYLabel.m
│ │ ├── YYTextView.h
│ │ └── YYTextView.m
│ ├── Utility
│ │ ├── YYAsyncLayer.h
│ │ ├── YYAsyncLayer.m
│ │ ├── YYDispatchQueuePool.h
│ │ ├── YYDispatchQueuePool.m
│ │ ├── YYFileHash.h
│ │ ├── YYFileHash.m
│ │ ├── YYGestureRecognizer.h
│ │ ├── YYGestureRecognizer.m
│ │ ├── YYKeychain.h
│ │ ├── YYKeychain.m
│ │ ├── YYReachability.h
│ │ ├── YYReachability.m
│ │ ├── YYSentinel.h
│ │ ├── YYSentinel.m
│ │ ├── YYThreadSafeArray.h
│ │ ├── YYThreadSafeArray.m
│ │ ├── YYThreadSafeDictionary.h
│ │ ├── YYThreadSafeDictionary.m
│ │ ├── YYTimer.h
│ │ ├── YYTimer.m
│ │ ├── YYTransaction.h
│ │ ├── YYTransaction.m
│ │ ├── YYWeakProxy.h
│ │ └── YYWeakProxy.m
│ └── YYKit.h
├── ar.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
└── main.m
├── LTR.GIF
├── README.md
└── RTL.GIF
/JKRShimmeringLabel.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel.xcodeproj/project.xcworkspace/xcuserdata/huhuaiyi.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Joker-388/JKRShimmeringLabel/d613b3d2ce70c5bebe70017a192cbfe19a20742f/JKRShimmeringLabel.xcodeproj/project.xcworkspace/xcuserdata/huhuaiyi.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/JKRShimmeringLabel.xcodeproj/xcuserdata/huhuaiyi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel.xcodeproj/xcuserdata/huhuaiyi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | JKRShimmeringLabel.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // JKRShimmeringLabel
4 | //
5 | // Created by 胡怀刈 on 2023/4/11.
6 | //
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 |
12 | @property (nonatomic, strong) UIWindow *window;
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // JKRShimmeringLabel
4 | //
5 | // Created by 胡怀刈 on 2023/4/11.
6 | //
7 |
8 | #import "AppDelegate.h"
9 |
10 | @interface AppDelegate ()
11 |
12 | @end
13 |
14 | @implementation AppDelegate
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | // Override point for customization after application launch.
19 | return YES;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | }
8 | ],
9 | "info" : {
10 | "author" : "xcode",
11 | "version" : 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/JKRLabel/JKRAutoScrollLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // JKRAutoScrollLabel.h
3 | // XMScrollCanvas
4 | //
5 | // Created by Howie on 2021/10/27.
6 | // Copyright © 2021 wxm. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface JKRAutoScrollLabel : UILabel
14 |
15 | @property (nonatomic, assign) NSTimeInterval scrollDelay;
16 |
17 | @property (nonatomic, strong, nullable) UIImage *mask;
18 |
19 | @end
20 |
21 | NS_ASSUME_NONNULL_END
22 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/JKRLabel/JKRShimmeringLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // JKRShimmeringLabel.h
3 | // SoldierShimmering
4 | //
5 | // Created by 胡怀刈 on 2022/12/7.
6 | // Copyright © 2022 Soldier. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface JKRShimmeringLabel : UILabel
14 |
15 | @property (nonatomic, strong, nullable) UIImage *mask;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // JKRShimmeringLabel
4 | //
5 | // Created by 胡怀刈 on 2023/4/11.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSBundle+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle+YYAdd.h
3 | // YYKit
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 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Provides extensions for `NSBundle` to get resource by @2x or @3x...
18 |
19 | Example: ico.png, ico@2x.png, ico@3x.png. Call scaledResource:@"ico" ofType:@"png"
20 | on iPhone6 will return "ico@2x.png"'s path.
21 | */
22 | @interface NSBundle (YYAdd)
23 |
24 | /**
25 | An array of NSNumber objects, shows the best order for path scale search.
26 | e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1]
27 | */
28 | + (NSArray *)preferredScales;
29 |
30 | /**
31 | Returns the full pathname for the resource file identified by the specified
32 | name and extension and residing in a given bundle directory. It first search
33 | the file with current screen's scale (such as @2x), then search from higher
34 | scale to lower scale.
35 |
36 | @param name The name of a resource file contained in the directory
37 | specified by bundlePath.
38 |
39 | @param ext If extension is an empty string or nil, the extension is
40 | assumed not to exist and the file is the first file encountered that exactly matches name.
41 |
42 | @param bundlePath The path of a top-level bundle directory. This must be a
43 | valid path. For example, to specify the bundle directory for a Mac app, you
44 | might specify the path /Applications/MyApp.app.
45 |
46 | @return The full pathname for the resource file or nil if the file could not be
47 | located. This method also returns nil if the bundle specified by the bundlePath
48 | parameter does not exist or is not a readable directory.
49 | */
50 | + (nullable NSString *)pathForScaledResource:(NSString *)name
51 | ofType:(nullable NSString *)ext
52 | inDirectory:(NSString *)bundlePath;
53 |
54 | /**
55 | Returns the full pathname for the resource identified by the specified name and
56 | file extension. It first search the file with current screen's scale (such as @2x),
57 | then search from higher scale to lower scale.
58 |
59 | @param name The name of the resource file. If name is an empty string or
60 | nil, returns the first file encountered of the supplied type.
61 |
62 | @param ext If extension is an empty string or nil, the extension is
63 | assumed not to exist and the file is the first file encountered that exactly matches name.
64 |
65 |
66 | @return The full pathname for the resource file or nil if the file could not be located.
67 | */
68 | - (nullable NSString *)pathForScaledResource:(NSString *)name ofType:(nullable NSString *)ext;
69 |
70 | /**
71 | Returns the full pathname for the resource identified by the specified name and
72 | file extension and located in the specified bundle subdirectory. It first search
73 | the file with current screen's scale (such as @2x), then search from higher
74 | scale to lower scale.
75 |
76 | @param name The name of the resource file.
77 |
78 | @param ext If extension is an empty string or nil, all the files in
79 | subpath and its subdirectories are returned. If an extension is provided the
80 | subdirectories are not searched.
81 |
82 | @param subpath The name of the bundle subdirectory. Can be nil.
83 |
84 | @return The full pathname for the resource file or nil if the file could not be located.
85 | */
86 | - (nullable NSString *)pathForScaledResource:(NSString *)name
87 | ofType:(nullable NSString *)ext
88 | inDirectory:(nullable NSString *)subpath;
89 |
90 | @end
91 |
92 | NS_ASSUME_NONNULL_END
93 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSBundle+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle+YYAdd.m
3 | // YYKit
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 "NSBundle+YYAdd.h"
13 | #import "NSString+YYAdd.h"
14 | #import "YYKitMacro.h"
15 |
16 | YYSYNTH_DUMMY_CLASS(NSBundle_YYAdd)
17 |
18 | @implementation NSBundle (YYAdd)
19 |
20 | + (NSArray *)preferredScales {
21 | static NSArray *scales;
22 | static dispatch_once_t onceToken;
23 | dispatch_once(&onceToken, ^{
24 | CGFloat screenScale = [UIScreen mainScreen].scale;
25 | if (screenScale <= 1) {
26 | scales = @[@1,@2,@3];
27 | } else if (screenScale <= 2) {
28 | scales = @[@2,@3,@1];
29 | } else {
30 | scales = @[@3,@2,@1];
31 | }
32 | });
33 | return scales;
34 | }
35 |
36 | + (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)bundlePath {
37 | if (name.length == 0) return nil;
38 | if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext inDirectory:bundlePath];
39 |
40 | NSString *path = nil;
41 | NSArray *scales = [self preferredScales];
42 | for (int s = 0; s < scales.count; s++) {
43 | CGFloat scale = ((NSNumber *)scales[s]).floatValue;
44 | NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
45 | : [name stringByAppendingPathScale:scale];
46 | path = [self pathForResource:scaledName ofType:ext inDirectory:bundlePath];
47 | if (path) break;
48 | }
49 |
50 | return path;
51 | }
52 |
53 | - (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext {
54 | if (name.length == 0) return nil;
55 | if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext];
56 |
57 | NSString *path = nil;
58 | NSArray *scales = [NSBundle preferredScales];
59 | for (int s = 0; s < scales.count; s++) {
60 | CGFloat scale = ((NSNumber *)scales[s]).floatValue;
61 | NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
62 | : [name stringByAppendingPathScale:scale];
63 | path = [self pathForResource:scaledName ofType:ext];
64 | if (path) break;
65 | }
66 |
67 | return path;
68 | }
69 |
70 | - (NSString *)pathForScaledResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)subpath {
71 | if (name.length == 0) return nil;
72 | if ([name hasSuffix:@"/"]) return [self pathForResource:name ofType:ext];
73 |
74 | NSString *path = nil;
75 | NSArray *scales = [NSBundle preferredScales];
76 | for (int s = 0; s < scales.count; s++) {
77 | CGFloat scale = ((NSNumber *)scales[s]).floatValue;
78 | NSString *scaledName = ext.length ? [name stringByAppendingNameScale:scale]
79 | : [name stringByAppendingPathScale:scale];
80 | path = [self pathForResource:scaledName ofType:ext inDirectory:subpath];
81 | if (path) break;
82 | }
83 |
84 | return path;
85 | }
86 |
87 | @end
88 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSKeyedUnarchiver+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSKeyedUnarchiver+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/4.
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 `NSKeyedUnarchiver`.
18 | */
19 | @interface NSKeyedUnarchiver (YYAdd)
20 |
21 | /**
22 | Same as unarchiveObjectWithData:, except it returns the exception by reference.
23 |
24 | @param data The data need unarchived.
25 |
26 | @param exception Pointer which will, upon return, if an exception occurred and
27 | said pointer is not NULL, point to said NSException.
28 | */
29 | + (nullable id)unarchiveObjectWithData:(NSData *)data
30 | exception:(NSException *_Nullable *_Nullable)exception;
31 |
32 | /**
33 | Same as unarchiveObjectWithFile:, except it returns the exception by reference.
34 |
35 | @param path The path of archived object file.
36 |
37 | @param exception Pointer which will, upon return, if an exception occurred and
38 | said pointer is not NULL, point to said NSException.
39 | */
40 | + (nullable id)unarchiveObjectWithFile:(NSString *)path
41 | exception:(NSException *_Nullable *_Nullable)exception;
42 |
43 | @end
44 |
45 | NS_ASSUME_NONNULL_END
46 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSKeyedUnarchiver+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSKeyedUnarchiver+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/4.
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 "NSKeyedUnarchiver+YYAdd.h"
13 | #import "YYKitMacro.h"
14 |
15 | YYSYNTH_DUMMY_CLASS(NSKeyedUnarchiver_YYAdd)
16 |
17 |
18 | @implementation NSKeyedUnarchiver (YYAdd)
19 |
20 | + (id)unarchiveObjectWithData:(NSData *)data exception:(__autoreleasing NSException **)exception {
21 | id object = nil;
22 | @try {
23 | object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
24 | }
25 | @catch (NSException *e)
26 | {
27 | if (exception) *exception = e;
28 | }
29 | @finally
30 | {
31 | }
32 | return object;
33 | }
34 |
35 | + (id)unarchiveObjectWithFile:(NSString *)path exception:(__autoreleasing NSException **)exception {
36 | id object = nil;
37 |
38 | @try {
39 | object = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
40 | }
41 | @catch (NSException *e)
42 | {
43 | if (exception) *exception = e;
44 | }
45 | @finally
46 | {
47 | }
48 | return object;
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSNotificationCenter+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSNotificationCenter+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/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 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Provide some method for `NSNotificationCenter`
18 | to post notification in different thread.
19 | */
20 | @interface NSNotificationCenter (YYAdd)
21 |
22 | /**
23 | Posts a given notification to the receiver on main thread.
24 | If current thread is main thread, the notification is posted synchronously;
25 | otherwise, is posted asynchronously.
26 |
27 | @param notification The notification to post.
28 | An exception is raised if notification is nil.
29 | */
30 | - (void)postNotificationOnMainThread:(NSNotification *)notification;
31 |
32 | /**
33 | Posts a given notification to the receiver on main thread.
34 |
35 | @param notification The notification to post.
36 | An exception is raised if notification is nil.
37 |
38 | @param wait A Boolean that specifies whether the current thread blocks
39 | until after the specified notification is posted on the
40 | receiver on the main thread. Specify YES to block this
41 | thread; otherwise, specify NO to have this method return
42 | immediately.
43 | */
44 | - (void)postNotificationOnMainThread:(NSNotification *)notification
45 | waitUntilDone:(BOOL)wait;
46 |
47 | /**
48 | Creates a notification with a given name and sender and posts it to the
49 | receiver on main thread. If current thread is main thread, the notification
50 | is posted synchronously; otherwise, is posted asynchronously.
51 |
52 | @param name The name of the notification.
53 |
54 | @param object The object posting the notification.
55 | */
56 | - (void)postNotificationOnMainThreadWithName:(NSString *)name
57 | object:(nullable id)object;
58 |
59 | /**
60 | Creates a notification with a given name and sender and posts it to the
61 | receiver on main thread. If current thread is main thread, the notification
62 | is posted synchronously; otherwise, is posted asynchronously.
63 |
64 | @param name The name of the notification.
65 |
66 | @param object The object posting the notification.
67 |
68 | @param userInfo Information about the the notification. May be nil.
69 | */
70 | - (void)postNotificationOnMainThreadWithName:(NSString *)name
71 | object:(nullable id)object
72 | userInfo:(nullable NSDictionary *)userInfo;
73 |
74 | /**
75 | Creates a notification with a given name and sender and posts it to the
76 | receiver on main thread.
77 |
78 | @param name The name of the notification.
79 |
80 | @param object The object posting the notification.
81 |
82 | @param userInfo Information about the the notification. May be nil.
83 |
84 | @param wait A Boolean that specifies whether the current thread blocks
85 | until after the specified notification is posted on the
86 | receiver on the main thread. Specify YES to block this
87 | thread; otherwise, specify NO to have this method return
88 | immediately.
89 | */
90 | - (void)postNotificationOnMainThreadWithName:(NSString *)name
91 | object:(nullable id)object
92 | userInfo:(nullable NSDictionary *)userInfo
93 | waitUntilDone:(BOOL)wait;
94 |
95 | @end
96 |
97 | NS_ASSUME_NONNULL_END
98 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSNotificationCenter+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNotificationCenter+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/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 "NSNotificationCenter+YYAdd.h"
13 | #include
14 | #import "YYKitMacro.h"
15 |
16 | YYSYNTH_DUMMY_CLASS(NSNotificationCenter_YYAdd)
17 |
18 |
19 | @implementation NSNotificationCenter (YYAdd)
20 |
21 | - (void)postNotificationOnMainThread:(NSNotification *)notification {
22 | if (pthread_main_np()) return [self postNotification:notification];
23 | [self postNotificationOnMainThread:notification waitUntilDone:NO];
24 | }
25 |
26 | - (void)postNotificationOnMainThread:(NSNotification *)notification waitUntilDone:(BOOL)wait {
27 | if (pthread_main_np()) return [self postNotification:notification];
28 | [[self class] performSelectorOnMainThread:@selector(_yy_postNotification:) withObject:notification waitUntilDone:wait];
29 | }
30 |
31 | - (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object {
32 | if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:nil];
33 | [self postNotificationOnMainThreadWithName:name object:object userInfo:nil waitUntilDone:NO];
34 | }
35 |
36 | - (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo {
37 | if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:userInfo];
38 | [self postNotificationOnMainThreadWithName:name object:object userInfo:userInfo waitUntilDone:NO];
39 | }
40 |
41 | - (void)postNotificationOnMainThreadWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo waitUntilDone:(BOOL)wait {
42 | if (pthread_main_np()) return [self postNotificationName:name object:object userInfo:userInfo];
43 | NSMutableDictionary *info = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:3];
44 | if (name) [info setObject:name forKey:@"name"];
45 | if (object) [info setObject:object forKey:@"object"];
46 | if (userInfo) [info setObject:userInfo forKey:@"userInfo"];
47 | [[self class] performSelectorOnMainThread:@selector(_yy_postNotificationName:) withObject:info waitUntilDone:wait];
48 | }
49 |
50 | + (void)_yy_postNotification:(NSNotification *)notification {
51 | [[self defaultCenter] postNotification:notification];
52 | }
53 |
54 | + (void)_yy_postNotificationName:(NSDictionary *)info {
55 | NSString *name = [info objectForKey:@"name"];
56 | id object = [info objectForKey:@"object"];
57 | NSDictionary *userInfo = [info objectForKey:@"userInfo"];
58 |
59 | [[self defaultCenter] postNotificationName:name object:object userInfo:userInfo];
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSNumber+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumber+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/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 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Provide a method to parse `NSString` for `NSNumber`.
18 | */
19 | @interface NSNumber (YYAdd)
20 |
21 | /**
22 | Creates and returns an NSNumber object from a string.
23 | Valid format: @"12", @"12.345", @" -0xFF", @" .23e99 "...
24 |
25 | @param string The string described an number.
26 |
27 | @return an NSNumber when parse succeed, or nil if an error occurs.
28 | */
29 | + (nullable NSNumber *)numberWithString:(NSString *)string;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSNumber+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumber+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/8/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 "NSNumber+YYAdd.h"
13 | #import "NSString+YYAdd.h"
14 | #import "YYKitMacro.h"
15 |
16 | YYSYNTH_DUMMY_CLASS(NSNumber_YYAdd)
17 |
18 |
19 | @implementation NSNumber (YYAdd)
20 |
21 | + (NSNumber *)numberWithString:(NSString *)string {
22 | NSString *str = [[string stringByTrim] lowercaseString];
23 | if (!str || !str.length) {
24 | return nil;
25 | }
26 |
27 | static NSDictionary *dic;
28 | static dispatch_once_t onceToken;
29 | dispatch_once(&onceToken, ^{
30 | dic = @{@"true" : @(YES),
31 | @"yes" : @(YES),
32 | @"false" : @(NO),
33 | @"no" : @(NO),
34 | @"nil" : [NSNull null],
35 | @"null" : [NSNull null],
36 | @"" : [NSNull null]};
37 | });
38 | id num = dic[str];
39 | if (num) {
40 | if (num == [NSNull null]) return nil;
41 | return num;
42 | }
43 |
44 | // hex number
45 | int sign = 0;
46 | if ([str hasPrefix:@"0x"]) sign = 1;
47 | else if ([str hasPrefix:@"-0x"]) sign = -1;
48 | if (sign != 0) {
49 | NSScanner *scan = [NSScanner scannerWithString:str];
50 | unsigned num = -1;
51 | BOOL suc = [scan scanHexInt:&num];
52 | if (suc)
53 | return [NSNumber numberWithLong:((long)num * sign)];
54 | else
55 | return nil;
56 | }
57 | // normal number
58 | NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
59 | [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
60 | return [formatter numberFromString:string];
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSObject+YYAddForARC.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+YYAddForARC.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/12/15.
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 | /**
15 | Debug method for NSObject when using ARC.
16 | */
17 | @interface NSObject (YYAddForARC)
18 |
19 | /// Same as `retain`
20 | - (instancetype)arcDebugRetain;
21 |
22 | /// Same as `release`
23 | - (oneway void)arcDebugRelease;
24 |
25 | /// Same as `autorelease`
26 | - (instancetype)arcDebugAutorelease;
27 |
28 | /// Same as `retainCount`
29 | - (NSUInteger)arcDebugRetainCount;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSObject+YYAddForARC.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+YYAddForARC.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/12/15.
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 "NSObject+YYAddForARC.h"
13 |
14 | @interface NSObject_YYAddForARC : NSObject @end
15 | @implementation NSObject_YYAddForARC @end
16 |
17 | #if __has_feature(objc_arc)
18 | #error This file must be compiled without ARC. Specify the -fno-objc-arc flag to this file.
19 | #endif
20 |
21 |
22 | @implementation NSObject (YYAddForARC)
23 |
24 | - (instancetype)arcDebugRetain {
25 | return [self retain];
26 | }
27 |
28 | - (oneway void)arcDebugRelease {
29 | [self release];
30 | }
31 |
32 | - (instancetype)arcDebugAutorelease {
33 | return [self autorelease];
34 | }
35 |
36 | - (NSUInteger)arcDebugRetainCount {
37 | return [self retainCount];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSObject+YYAddForKVO.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+YYAddForKVO.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/15.
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 | Observer with block (KVO).
18 | */
19 | @interface NSObject (YYAddForKVO)
20 |
21 | /**
22 | Registers a block to receive KVO notifications for the specified key-path
23 | relative to the receiver.
24 |
25 | @discussion The block and block captured objects are retained. Call
26 | `removeObserverBlocksForKeyPath:` or `removeObserverBlocks` to release.
27 |
28 | @param keyPath The key path, relative to the receiver, of the property to
29 | observe. This value must not be nil.
30 |
31 | @param block The block to register for KVO notifications.
32 | */
33 | - (void)addObserverBlockForKeyPath:(NSString*)keyPath block:(void (^)(id _Nonnull obj, _Nullable id oldVal, _Nullable id newVal))block;
34 |
35 | /**
36 | Stops all blocks (associated by `addObserverBlockForKeyPath:block:`) from
37 | receiving change notifications for the property specified by a given key-path
38 | relative to the receiver, and release these blocks.
39 |
40 | @param keyPath A key-path, relative to the receiver, for which blocks is
41 | registered to receive KVO change notifications.
42 | */
43 | - (void)removeObserverBlocksForKeyPath:(NSString*)keyPath;
44 |
45 | /**
46 | Stops all blocks (associated by `addObserverBlockForKeyPath:block:`) from
47 | receiving change notifications, and release these blocks.
48 | */
49 | - (void)removeObserverBlocks;
50 |
51 | @end
52 |
53 | NS_ASSUME_NONNULL_END
54 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSObject+YYAddForKVO.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+YYAddForKVO.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/15.
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 "NSObject+YYAddForKVO.h"
13 | #import "YYKitMacro.h"
14 | #import
15 | #import
16 |
17 | YYSYNTH_DUMMY_CLASS(NSObject_YYAddForKVO)
18 |
19 |
20 |
21 |
22 | static const int block_key;
23 |
24 | @interface _YYNSObjectKVOBlockTarget : NSObject
25 |
26 | @property (nonatomic, copy) void (^block)(__weak id obj, id oldVal, id newVal);
27 |
28 | - (id)initWithBlock:(void (^)(__weak id obj, id oldVal, id newVal))block;
29 |
30 | @end
31 |
32 | @implementation _YYNSObjectKVOBlockTarget
33 |
34 | - (id)initWithBlock:(void (^)(__weak id obj, id oldVal, id newVal))block {
35 | self = [super init];
36 | if (self) {
37 | self.block = block;
38 | }
39 | return self;
40 | }
41 |
42 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
43 | if (!self.block) return;
44 |
45 | BOOL isPrior = [[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue];
46 | if (isPrior) return;
47 |
48 | NSKeyValueChange changeKind = [[change objectForKey:NSKeyValueChangeKindKey] integerValue];
49 | if (changeKind != NSKeyValueChangeSetting) return;
50 |
51 | id oldVal = [change objectForKey:NSKeyValueChangeOldKey];
52 | if (oldVal == [NSNull null]) oldVal = nil;
53 |
54 | id newVal = [change objectForKey:NSKeyValueChangeNewKey];
55 | if (newVal == [NSNull null]) newVal = nil;
56 |
57 | self.block(object, oldVal, newVal);
58 | }
59 |
60 | @end
61 |
62 |
63 |
64 | @implementation NSObject (YYAddForKVO)
65 |
66 | - (void)addObserverBlockForKeyPath:(NSString *)keyPath block:(void (^)(__weak id obj, id oldVal, id newVal))block {
67 | if (!keyPath || !block) return;
68 | _YYNSObjectKVOBlockTarget *target = [[_YYNSObjectKVOBlockTarget alloc] initWithBlock:block];
69 | NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
70 | NSMutableArray *arr = dic[keyPath];
71 | if (!arr) {
72 | arr = [NSMutableArray new];
73 | dic[keyPath] = arr;
74 | }
75 | [arr addObject:target];
76 | [self addObserver:target forKeyPath:keyPath options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
77 | }
78 |
79 | - (void)removeObserverBlocksForKeyPath:(NSString *)keyPath {
80 | if (!keyPath) return;
81 | NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
82 | NSMutableArray *arr = dic[keyPath];
83 | [arr enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
84 | [self removeObserver:obj forKeyPath:keyPath];
85 | }];
86 |
87 | [dic removeObjectForKey:keyPath];
88 | }
89 |
90 | - (void)removeObserverBlocks {
91 | NSMutableDictionary *dic = [self _yy_allNSObjectObserverBlocks];
92 | [dic enumerateKeysAndObjectsUsingBlock: ^(NSString *key, NSArray *arr, BOOL *stop) {
93 | [arr enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
94 | [self removeObserver:obj forKeyPath:key];
95 | }];
96 | }];
97 |
98 | [dic removeAllObjects];
99 | }
100 |
101 | - (NSMutableDictionary *)_yy_allNSObjectObserverBlocks {
102 | NSMutableDictionary *targets = objc_getAssociatedObject(self, &block_key);
103 | if (!targets) {
104 | targets = [NSMutableDictionary new];
105 | objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
106 | }
107 | return targets;
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSThread+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSThread+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/7/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 | @interface NSThread (YYAdd)
15 |
16 | /**
17 | Add an autorelease pool to current runloop for current thread.
18 |
19 | @discussion If you create your own thread (NSThread/pthread), and you use
20 | runloop to manage your task, you may use this method to add an autorelease pool
21 | to the runloop. Its behavior is the same as the main thread's autorelease pool.
22 | */
23 | + (void)addAutoreleasePoolToCurrentRunloop;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSThread+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSThread+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/7/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 "NSThread+YYAdd.h"
13 | #import
14 |
15 | @interface NSThread_YYAdd : NSObject @end
16 | @implementation NSThread_YYAdd @end
17 |
18 | #if __has_feature(objc_arc)
19 | #error This file must be compiled without ARC. Specify the -fno-objc-arc flag to this file.
20 | #endif
21 |
22 | static NSString *const YYNSThreadAutoleasePoolKey = @"YYNSThreadAutoleasePoolKey";
23 | static NSString *const YYNSThreadAutoleasePoolStackKey = @"YYNSThreadAutoleasePoolStackKey";
24 |
25 | static const void *PoolStackRetainCallBack(CFAllocatorRef allocator, const void *value) {
26 | return value;
27 | }
28 |
29 | static void PoolStackReleaseCallBack(CFAllocatorRef allocator, const void *value) {
30 | CFRelease((CFTypeRef)value);
31 | }
32 |
33 |
34 | static inline void YYAutoreleasePoolPush() {
35 | NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
36 | NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
37 |
38 | if (!poolStack) {
39 | /*
40 | do not retain pool on push,
41 | but release on pop to avoid memory analyze warning
42 | */
43 | CFArrayCallBacks callbacks = {0};
44 | callbacks.retain = PoolStackRetainCallBack;
45 | callbacks.release = PoolStackReleaseCallBack;
46 | poolStack = (id)CFArrayCreateMutable(CFAllocatorGetDefault(), 0, &callbacks);
47 | dic[YYNSThreadAutoleasePoolStackKey] = poolStack;
48 | CFRelease(poolStack);
49 | }
50 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ///< create
51 | [poolStack addObject:pool]; // push
52 | }
53 |
54 | static inline void YYAutoreleasePoolPop() {
55 | NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
56 | NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
57 | [poolStack removeLastObject]; // pop
58 | }
59 |
60 | static void YYRunLoopAutoreleasePoolObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
61 | switch (activity) {
62 | case kCFRunLoopEntry: {
63 | YYAutoreleasePoolPush();
64 | } break;
65 | case kCFRunLoopBeforeWaiting: {
66 | YYAutoreleasePoolPop();
67 | YYAutoreleasePoolPush();
68 | } break;
69 | case kCFRunLoopExit: {
70 | YYAutoreleasePoolPop();
71 | } break;
72 | default: break;
73 | }
74 | }
75 |
76 | static void YYRunloopAutoreleasePoolSetup() {
77 | CFRunLoopRef runloop = CFRunLoopGetCurrent();
78 |
79 | CFRunLoopObserverRef pushObserver;
80 | pushObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopEntry,
81 | true, // repeat
82 | -0x7FFFFFFF, // before other observers
83 | YYRunLoopAutoreleasePoolObserverCallBack, NULL);
84 | CFRunLoopAddObserver(runloop, pushObserver, kCFRunLoopCommonModes);
85 | CFRelease(pushObserver);
86 |
87 | CFRunLoopObserverRef popObserver;
88 | popObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting | kCFRunLoopExit,
89 | true, // repeat
90 | 0x7FFFFFFF, // after other observers
91 | YYRunLoopAutoreleasePoolObserverCallBack, NULL);
92 | CFRunLoopAddObserver(runloop, popObserver, kCFRunLoopCommonModes);
93 | CFRelease(popObserver);
94 | }
95 |
96 | @implementation NSThread (YYAdd)
97 |
98 | + (void)addAutoreleasePoolToCurrentRunloop {
99 | if ([NSThread isMainThread]) return; // The main thread already has autorelease pool.
100 | NSThread *thread = [self currentThread];
101 | if (!thread) return;
102 | if (thread.threadDictionary[YYNSThreadAutoleasePoolKey]) return; // already added
103 | YYRunloopAutoreleasePoolSetup();
104 | thread.threadDictionary[YYNSThreadAutoleasePoolKey] = YYNSThreadAutoleasePoolKey; // mark the state
105 | }
106 |
107 | @end
108 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSTimer+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSTimer+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/15/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 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Provides extensions for `NSTimer`.
18 | */
19 | @interface NSTimer (YYAdd)
20 |
21 | /**
22 | Creates and returns a new NSTimer object and schedules it on the current run
23 | loop in the default mode.
24 |
25 | @discussion After seconds seconds have elapsed, the timer fires,
26 | sending the message aSelector to target.
27 |
28 | @param seconds The number of seconds between firings of the timer. If seconds
29 | is less than or equal to 0.0, this method chooses the
30 | nonnegative value of 0.1 milliseconds instead.
31 |
32 | @param block The block to invoke when the timer fires. The timer maintains
33 | a strong reference to the block until it (the timer) is invalidated.
34 |
35 | @param repeats If YES, the timer will repeatedly reschedule itself until
36 | invalidated. If NO, the timer will be invalidated after it fires.
37 |
38 | @return A new NSTimer object, configured according to the specified parameters.
39 | */
40 | + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;
41 |
42 | /**
43 | Creates and returns a new NSTimer object initialized with the specified block.
44 |
45 | @discussion You must add the new timer to a run loop, using addTimer:forMode:.
46 | Then, after seconds have elapsed, the timer fires, invoking
47 | block. (If the timer is configured to repeat, there is no need
48 | to subsequently re-add the timer to the run loop.)
49 |
50 | @param seconds The number of seconds between firings of the timer. If seconds
51 | is less than or equal to 0.0, this method chooses the
52 | nonnegative value of 0.1 milliseconds instead.
53 |
54 | @param block The block to invoke when the timer fires. The timer instructs
55 | the block to maintain a strong reference to its arguments.
56 |
57 | @param repeats If YES, the timer will repeatedly reschedule itself until
58 | invalidated. If NO, the timer will be invalidated after it fires.
59 |
60 | @return A new NSTimer object, configured according to the specified parameters.
61 | */
62 | + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats;
63 |
64 | @end
65 |
66 | NS_ASSUME_NONNULL_END
67 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Foundation/NSTimer+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSTimer+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/15/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 "NSTimer+YYAdd.h"
13 | #import "YYKitMacro.h"
14 |
15 | YYSYNTH_DUMMY_CLASS(NSTimer_YYAdd)
16 |
17 |
18 | @implementation NSTimer (YYAdd)
19 |
20 | + (void)_yy_ExecBlock:(NSTimer *)timer {
21 | if ([timer userInfo]) {
22 | void (^block)(NSTimer *timer) = (void (^)(NSTimer *timer))[timer userInfo];
23 | block(timer);
24 | }
25 | }
26 |
27 | + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
28 | return [NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(_yy_ExecBlock:) userInfo:[block copy] repeats:repeats];
29 | }
30 |
31 | + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds block:(void (^)(NSTimer *timer))block repeats:(BOOL)repeats {
32 | return [NSTimer timerWithTimeInterval:seconds target:self selector:@selector(_yy_ExecBlock:) userInfo:[block copy] repeats:repeats];
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/Quartz/CALayer+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/5/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 | NS_ASSUME_NONNULL_BEGIN
16 |
17 | /**
18 | Provides extensions for `CALayer`.
19 | */
20 | @interface CALayer (YYAdd)
21 |
22 | /**
23 | Take snapshot without transform, image's size equals to bounds.
24 | */
25 | - (nullable UIImage *)snapshotImage;
26 |
27 | /**
28 | Take snapshot without transform, PDF's page size equals to bounds.
29 | */
30 | - (nullable NSData *)snapshotPDF;
31 |
32 | /**
33 | Shortcut to set the layer's shadow
34 |
35 | @param color Shadow Color
36 | @param offset Shadow offset
37 | @param radius Shadow radius
38 | */
39 | - (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
40 |
41 | /**
42 | Remove all sublayers.
43 | */
44 | - (void)removeAllSublayers;
45 |
46 | @property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
47 | @property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
48 | @property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
49 | @property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
50 | @property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
51 | @property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
52 | @property (nonatomic) CGPoint center; ///< Shortcut for center.
53 | @property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
54 | @property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
55 | @property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
56 | @property (nonatomic, getter=frameSize, setter=setFrameSize:) CGSize size; ///< Shortcut for frame.size.
57 |
58 |
59 | @property (nonatomic) CGFloat transformRotation; ///< key path "tranform.rotation"
60 | @property (nonatomic) CGFloat transformRotationX; ///< key path "tranform.rotation.x"
61 | @property (nonatomic) CGFloat transformRotationY; ///< key path "tranform.rotation.y"
62 | @property (nonatomic) CGFloat transformRotationZ; ///< key path "tranform.rotation.z"
63 | @property (nonatomic) CGFloat transformScale; ///< key path "tranform.scale"
64 | @property (nonatomic) CGFloat transformScaleX; ///< key path "tranform.scale.x"
65 | @property (nonatomic) CGFloat transformScaleY; ///< key path "tranform.scale.y"
66 | @property (nonatomic) CGFloat transformScaleZ; ///< key path "tranform.scale.z"
67 | @property (nonatomic) CGFloat transformTranslationX; ///< key path "tranform.translation.x"
68 | @property (nonatomic) CGFloat transformTranslationY; ///< key path "tranform.translation.y"
69 | @property (nonatomic) CGFloat transformTranslationZ; ///< key path "tranform.translation.z"
70 |
71 | /**
72 | Shortcut for transform.m34, -1/1000 is a good value.
73 | It should be set before other transform shortcut.
74 | */
75 | @property (nonatomic) CGFloat transformDepth;
76 |
77 | /**
78 | Wrapper for `contentsGravity` property.
79 | */
80 | @property (nonatomic) UIViewContentMode contentMode;
81 |
82 | /**
83 | Add a fade animation to layer's contents when the contents is changed.
84 |
85 | @param duration Animation duration
86 | @param curve Animation curve.
87 | */
88 | - (void)addFadeAnimationWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve;
89 |
90 | /**
91 | Cancel fade animation which is added with "-addFadeAnimationWithDuration:curve:".
92 | */
93 | - (void)removePreviousFadeAnimation;
94 |
95 | @end
96 |
97 | NS_ASSUME_NONNULL_END
98 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIApplication+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIApplication+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/4.
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 `UIApplication`.
18 | */
19 | @interface UIApplication (YYAdd)
20 |
21 | /// "Documents" folder in this app's sandbox.
22 | @property (nonatomic, readonly) NSURL *documentsURL;
23 | @property (nonatomic, readonly) NSString *documentsPath;
24 |
25 | /// "Caches" folder in this app's sandbox.
26 | @property (nonatomic, readonly) NSURL *cachesURL;
27 | @property (nonatomic, readonly) NSString *cachesPath;
28 |
29 | /// "Library" folder in this app's sandbox.
30 | @property (nonatomic, readonly) NSURL *libraryURL;
31 | @property (nonatomic, readonly) NSString *libraryPath;
32 |
33 | /// Application's Bundle Name (show in SpringBoard).
34 | @property (nullable, nonatomic, readonly) NSString *appBundleName;
35 |
36 | /// Application's Bundle ID. e.g. "com.ibireme.MyApp"
37 | @property (nullable, nonatomic, readonly) NSString *appBundleID;
38 |
39 | /// Application's Version. e.g. "1.2.0"
40 | @property (nullable, nonatomic, readonly) NSString *appVersion;
41 |
42 | /// Application's Build number. e.g. "123"
43 | @property (nullable, nonatomic, readonly) NSString *appBuildVersion;
44 |
45 | /// Whether this app is pirated (not install from appstore).
46 | @property (nonatomic, readonly) BOOL isPirated;
47 |
48 | /// Whether this app is being debugged (debugger attached).
49 | @property (nonatomic, readonly) BOOL isBeingDebugged;
50 |
51 | /// Current thread real memory used in byte. (-1 when error occurs)
52 | @property (nonatomic, readonly) int64_t memoryUsage;
53 |
54 | /// Current thread CPU usage, 1.0 means 100%. (-1 when error occurs)
55 | @property (nonatomic, readonly) float cpuUsage;
56 |
57 |
58 | /**
59 | Increments the number of active network requests.
60 | If this number was zero before incrementing, this will start animating the
61 | status bar network activity indicator.
62 |
63 | This method is thread safe.
64 |
65 | This method has no effect in App Extension.
66 | */
67 | - (void)incrementNetworkActivityCount;
68 |
69 | /**
70 | Decrements the number of active network requests.
71 | If this number becomes zero after decrementing, this will stop animating the
72 | status bar network activity indicator.
73 |
74 | This method is thread safe.
75 |
76 | This method has no effect in App Extension.
77 | */
78 | - (void)decrementNetworkActivityCount;
79 |
80 |
81 | /// Returns YES in App Extension.
82 | + (BOOL)isAppExtension;
83 |
84 | /// Same as sharedApplication, but returns nil in App Extension.
85 | + (nullable UIApplication *)sharedExtensionApplication;
86 |
87 | @end
88 |
89 | NS_ASSUME_NONNULL_END
90 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIBarButtonItem+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarButtonItem+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/10/15.
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 `UIBarButtonItem`.
18 | */
19 | @interface UIBarButtonItem (YYAdd)
20 |
21 | /**
22 | The block that invoked when the item is selected. The objects captured by block
23 | will retained by the ButtonItem.
24 |
25 | @discussion This param is conflict with `target` and `action` property.
26 | Set this will set `target` and `action` property to some internal objects.
27 | */
28 | @property (nullable, nonatomic, copy) void (^actionBlock)(id);
29 |
30 | @end
31 |
32 | NS_ASSUME_NONNULL_END
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIBarButtonItem+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarButtonItem+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/10/15.
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 "UIBarButtonItem+YYAdd.h"
13 | #import "YYKitMacro.h"
14 | #import
15 |
16 | YYSYNTH_DUMMY_CLASS(UIBarButtonItem_YYAdd)
17 |
18 |
19 | static const int block_key;
20 |
21 | @interface _YYUIBarButtonItemBlockTarget : NSObject
22 |
23 | @property (nonatomic, copy) void (^block)(id sender);
24 |
25 | - (id)initWithBlock:(void (^)(id sender))block;
26 | - (void)invoke:(id)sender;
27 |
28 | @end
29 |
30 | @implementation _YYUIBarButtonItemBlockTarget
31 |
32 | - (id)initWithBlock:(void (^)(id sender))block{
33 | self = [super init];
34 | if (self) {
35 | _block = [block copy];
36 | }
37 | return self;
38 | }
39 |
40 | - (void)invoke:(id)sender {
41 | if (self.block) self.block(sender);
42 | }
43 |
44 | @end
45 |
46 |
47 | @implementation UIBarButtonItem (YYAdd)
48 |
49 | - (void)setActionBlock:(void (^)(id sender))block {
50 | _YYUIBarButtonItemBlockTarget *target = [[_YYUIBarButtonItemBlockTarget alloc] initWithBlock:block];
51 | objc_setAssociatedObject(self, &block_key, target, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
52 |
53 | [self setTarget:target];
54 | [self setAction:@selector(invoke:)];
55 | }
56 |
57 | - (void (^)(id)) actionBlock {
58 | _YYUIBarButtonItemBlockTarget *target = objc_getAssociatedObject(self, &block_key);
59 | return target.block;
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIBezierPath+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIBezierPath+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/30.
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 `UIBezierPath`.
18 | */
19 | @interface UIBezierPath (YYAdd)
20 |
21 | /**
22 | Creates and returns a new UIBezierPath object initialized with the text glyphs
23 | generated from the specified font.
24 |
25 | @discussion It doesnot support apple emoji. If you want get emoji image, try
26 | [UIImage imageWithEmoji:size:] in `UIImage(YYAdd)`.
27 |
28 | @param text The text to generate glyph path.
29 | @param font The font to generate glyph path.
30 |
31 | @return A new path object with the text and font, or nil if an error occurs.
32 | */
33 | + (nullable UIBezierPath *)bezierPathWithText:(NSString *)text font:(UIFont *)font;
34 |
35 | @end
36 |
37 | NS_ASSUME_NONNULL_END
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIBezierPath+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIBezierPath+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/30.
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 "UIBezierPath+YYAdd.h"
13 | #import "UIFont+YYAdd.h"
14 | #import
15 | #import "YYKitMacro.h"
16 |
17 | YYSYNTH_DUMMY_CLASS(UIBezierPath_YYAdd)
18 |
19 |
20 | @implementation UIBezierPath (YYAdd)
21 |
22 | + (UIBezierPath *)bezierPathWithText:(NSString *)text font:(UIFont *)font {
23 | CTFontRef ctFont = font.CTFontRef;
24 | if (!ctFont || !text) return nil;
25 | NSDictionary *attrs = @{ (__bridge id)kCTFontAttributeName:(__bridge id)ctFont };
26 | NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:text attributes:attrs];
27 | CFRelease(ctFont);
28 |
29 | CTLineRef line = CTLineCreateWithAttributedString((__bridge CFTypeRef)attrString);
30 | if (!line) return nil;
31 |
32 | CGMutablePathRef cgPath = CGPathCreateMutable();
33 | CFArrayRef runs = CTLineGetGlyphRuns(line);
34 | for (CFIndex iRun = 0, iRunMax = CFArrayGetCount(runs); iRun < iRunMax; iRun++) {
35 | CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, iRun);
36 | CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
37 |
38 | for (CFIndex iGlyph = 0, iGlyphMax = CTRunGetGlyphCount(run); iGlyph < iGlyphMax; iGlyph++) {
39 | CFRange glyphRange = CFRangeMake(iGlyph, 1);
40 | CGGlyph glyph;
41 | CGPoint position;
42 | CTRunGetGlyphs(run, glyphRange, &glyph);
43 | CTRunGetPositions(run, glyphRange, &position);
44 |
45 | CGPathRef glyphPath = CTFontCreatePathForGlyph(runFont, glyph, NULL);
46 | if (glyphPath) {
47 | CGAffineTransform transform = CGAffineTransformMakeTranslation(position.x, position.y);
48 | CGPathAddPath(cgPath, &transform, glyphPath);
49 | CGPathRelease(glyphPath);
50 | }
51 | }
52 | }
53 | UIBezierPath *path = [UIBezierPath bezierPathWithCGPath:cgPath];
54 | CGRect boundingBox = CGPathGetPathBoundingBox(cgPath);
55 | CFRelease(cgPath);
56 | CFRelease(line);
57 |
58 | [path applyTransform:CGAffineTransformMakeScale(1.0, -1.0)];
59 | [path applyTransform:CGAffineTransformMakeTranslation(0.0, boundingBox.size.height)];
60 |
61 | return path;
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIControl+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/5.
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 `UIControl`.
18 | */
19 | @interface UIControl (YYAdd)
20 |
21 | /**
22 | Removes all targets and actions for a particular event (or events)
23 | from an internal dispatch table.
24 | */
25 | - (void)removeAllTargets;
26 |
27 | /**
28 | Adds or replaces a target and action for a particular event (or events)
29 | to an internal dispatch table.
30 |
31 | @param target The target object—that is, the object to which the
32 | action message is sent. If this is nil, the responder
33 | chain is searched for an object willing to respond to the
34 | action message.
35 |
36 | @param action A selector identifying an action message. It cannot be NULL.
37 |
38 | @param controlEvents A bitmask specifying the control events for which the
39 | action message is sent.
40 | */
41 | - (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
42 |
43 | /**
44 | Adds a block for a particular event (or events) to an internal dispatch table.
45 | It will cause a strong reference to @a block.
46 |
47 | @param block The block which is invoked then the action message is
48 | sent (cannot be nil). The block is retained.
49 |
50 | @param controlEvents A bitmask specifying the control events for which the
51 | action message is sent.
52 | */
53 | - (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
54 |
55 | /**
56 | Adds or replaces a block for a particular event (or events) to an internal
57 | dispatch table. It will cause a strong reference to @a block.
58 |
59 | @param block The block which is invoked then the action message is
60 | sent (cannot be nil). The block is retained.
61 |
62 | @param controlEvents A bitmask specifying the control events for which the
63 | action message is sent.
64 | */
65 | - (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
66 |
67 | /**
68 | Removes all blocks for a particular event (or events) from an internal
69 | dispatch table.
70 |
71 | @param controlEvents A bitmask specifying the control events for which the
72 | action message is sent.
73 | */
74 | - (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;
75 |
76 | @end
77 |
78 | NS_ASSUME_NONNULL_END
79 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIControl+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/5.
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 "UIControl+YYAdd.h"
13 | #import "YYKitMacro.h"
14 | #import
15 |
16 | YYSYNTH_DUMMY_CLASS(UIControl_YYAdd)
17 |
18 |
19 | static const int block_key;
20 |
21 | @interface _YYUIControlBlockTarget : NSObject
22 |
23 | @property (nonatomic, copy) void (^block)(id sender);
24 | @property (nonatomic, assign) UIControlEvents events;
25 |
26 | - (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events;
27 | - (void)invoke:(id)sender;
28 |
29 | @end
30 |
31 | @implementation _YYUIControlBlockTarget
32 |
33 | - (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events {
34 | self = [super init];
35 | if (self) {
36 | _block = [block copy];
37 | _events = events;
38 | }
39 | return self;
40 | }
41 |
42 | - (void)invoke:(id)sender {
43 | if (_block) _block(sender);
44 | }
45 |
46 | @end
47 |
48 |
49 |
50 | @implementation UIControl (YYAdd)
51 |
52 | - (void)removeAllTargets {
53 | [[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) {
54 | [self removeTarget:object action:NULL forControlEvents:UIControlEventAllEvents];
55 | }];
56 | [[self _yy_allUIControlBlockTargets] removeAllObjects];
57 | }
58 |
59 | - (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
60 | if (!target || !action || !controlEvents) return;
61 | NSSet *targets = [self allTargets];
62 | for (id currentTarget in targets) {
63 | NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents];
64 | for (NSString *currentAction in actions) {
65 | [self removeTarget:currentTarget action:NSSelectorFromString(currentAction)
66 | forControlEvents:controlEvents];
67 | }
68 | }
69 | [self addTarget:target action:action forControlEvents:controlEvents];
70 | }
71 |
72 | - (void)addBlockForControlEvents:(UIControlEvents)controlEvents
73 | block:(void (^)(id sender))block {
74 | if (!controlEvents) return;
75 | _YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc]
76 | initWithBlock:block events:controlEvents];
77 | [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
78 | NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
79 | [targets addObject:target];
80 | }
81 |
82 | - (void)setBlockForControlEvents:(UIControlEvents)controlEvents
83 | block:(void (^)(id sender))block {
84 | [self removeAllBlocksForControlEvents:UIControlEventAllEvents];
85 | [self addBlockForControlEvents:controlEvents block:block];
86 | }
87 |
88 | - (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents {
89 | if (!controlEvents) return;
90 |
91 | NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
92 | NSMutableArray *removes = [NSMutableArray array];
93 | for (_YYUIControlBlockTarget *target in targets) {
94 | if (target.events & controlEvents) {
95 | UIControlEvents newEvent = target.events & (~controlEvents);
96 | if (newEvent) {
97 | [self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
98 | target.events = newEvent;
99 | [self addTarget:target action:@selector(invoke:) forControlEvents:target.events];
100 | } else {
101 | [self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
102 | [removes addObject:target];
103 | }
104 | }
105 | }
106 | [targets removeObjectsInArray:removes];
107 | }
108 |
109 | - (NSMutableArray *)_yy_allUIControlBlockTargets {
110 | NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
111 | if (!targets) {
112 | targets = [NSMutableArray array];
113 | objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
114 | }
115 | return targets;
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIGestureRecognizer+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIGestureRecognizer+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/10/13.
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 `UIGestureRecognizer`.
18 | */
19 | @interface UIGestureRecognizer (YYAdd)
20 |
21 | /**
22 | Initializes an allocated gesture-recognizer object with a action block.
23 |
24 | @param block An action block that to handle the gesture recognized by the
25 | receiver. nil is invalid. It is retained by the gesture.
26 |
27 | @return An initialized instance of a concrete UIGestureRecognizer subclass or
28 | nil if an error occurred in the attempt to initialize the object.
29 | */
30 | - (instancetype)initWithActionBlock:(void (^)(id sender))block;
31 |
32 | /**
33 | Adds an action block to a gesture-recognizer object. It is retained by the
34 | gesture.
35 |
36 | @param block A block invoked by the action message. nil is not a valid value.
37 | */
38 | - (void)addActionBlock:(void (^)(id sender))block;
39 |
40 | /**
41 | Remove all action blocks.
42 | */
43 | - (void)removeAllActionBlocks;
44 |
45 | @end
46 |
47 | NS_ASSUME_NONNULL_END
48 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIGestureRecognizer+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIGestureRecognizer+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/10/13.
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 "UIGestureRecognizer+YYAdd.h"
13 | #import "YYKitMacro.h"
14 | #import
15 |
16 | static const int block_key;
17 |
18 | @interface _YYUIGestureRecognizerBlockTarget : NSObject
19 |
20 | @property (nonatomic, copy) void (^block)(id sender);
21 |
22 | - (id)initWithBlock:(void (^)(id sender))block;
23 | - (void)invoke:(id)sender;
24 |
25 | @end
26 |
27 | @implementation _YYUIGestureRecognizerBlockTarget
28 |
29 | - (id)initWithBlock:(void (^)(id sender))block{
30 | self = [super init];
31 | if (self) {
32 | _block = [block copy];
33 | }
34 | return self;
35 | }
36 |
37 | - (void)invoke:(id)sender {
38 | if (_block) _block(sender);
39 | }
40 |
41 | @end
42 |
43 |
44 |
45 |
46 | @implementation UIGestureRecognizer (YYAdd)
47 |
48 | - (instancetype)initWithActionBlock:(void (^)(id sender))block {
49 | self = [self init];
50 | [self addActionBlock:block];
51 | return self;
52 | }
53 |
54 | - (void)addActionBlock:(void (^)(id sender))block {
55 | _YYUIGestureRecognizerBlockTarget *target = [[_YYUIGestureRecognizerBlockTarget alloc] initWithBlock:block];
56 | [self addTarget:target action:@selector(invoke:)];
57 | NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
58 | [targets addObject:target];
59 | }
60 |
61 | - (void)removeAllActionBlocks{
62 | NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
63 | [targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) {
64 | [self removeTarget:target action:@selector(invoke:)];
65 | }];
66 | [targets removeAllObjects];
67 | }
68 |
69 | - (NSMutableArray *)_yy_allUIGestureRecognizerBlockTargets {
70 | NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
71 | if (!targets) {
72 | targets = [NSMutableArray array];
73 | objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
74 | }
75 | return targets;
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIScreen+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIScreen+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/5.
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 `UIScreen`.
18 | */
19 | @interface UIScreen (YYAdd)
20 |
21 | /**
22 | Main screen's scale
23 |
24 | @return screen's scale
25 | */
26 | + (CGFloat)screenScale;
27 |
28 | /**
29 | Returns the bounds of the screen for the current device orientation.
30 |
31 | @return A rect indicating the bounds of the screen.
32 | @see boundsForOrientation:
33 | */
34 | - (CGRect)currentBounds NS_EXTENSION_UNAVAILABLE_IOS("");
35 |
36 | /**
37 | Returns the bounds of the screen for a given device orientation.
38 | `UIScreen`'s `bounds` method always returns the bounds of the
39 | screen of it in the portrait orientation.
40 |
41 | @param orientation The orientation to get the screen's bounds.
42 | @return A rect indicating the bounds of the screen.
43 | @see currentBounds
44 | */
45 | - (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation;
46 |
47 | /**
48 | The screen's real size in pixel (width is always smaller than height).
49 | This value may not be very accurate in an unknown device, or simulator.
50 | e.g. (768,1024)
51 | */
52 | @property (nonatomic, readonly) CGSize sizeInPixel;
53 |
54 | /**
55 | The screen's PPI.
56 | This value may not be very accurate in an unknown device, or simulator.
57 | Default value is 96.
58 | */
59 | @property (nonatomic, readonly) CGFloat pixelsPerInch;
60 |
61 | @end
62 |
63 | NS_ASSUME_NONNULL_END
64 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIScrollView+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/5.
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 `UIScrollView`.
18 | */
19 | @interface UIScrollView (YYAdd)
20 |
21 | /**
22 | Scroll content to top with animation.
23 | */
24 | - (void)scrollToTop;
25 |
26 | /**
27 | Scroll content to bottom with animation.
28 | */
29 | - (void)scrollToBottom;
30 |
31 | /**
32 | Scroll content to left with animation.
33 | */
34 | - (void)scrollToLeft;
35 |
36 | /**
37 | Scroll content to right with animation.
38 | */
39 | - (void)scrollToRight;
40 |
41 | /**
42 | Scroll content to top.
43 |
44 | @param animated Use animation.
45 | */
46 | - (void)scrollToTopAnimated:(BOOL)animated;
47 |
48 | /**
49 | Scroll content to bottom.
50 |
51 | @param animated Use animation.
52 | */
53 | - (void)scrollToBottomAnimated:(BOOL)animated;
54 |
55 | /**
56 | Scroll content to left.
57 |
58 | @param animated Use animation.
59 | */
60 | - (void)scrollToLeftAnimated:(BOOL)animated;
61 |
62 | /**
63 | Scroll content to right.
64 |
65 | @param animated Use animation.
66 | */
67 | - (void)scrollToRightAnimated:(BOOL)animated;
68 |
69 | @end
70 |
71 | NS_ASSUME_NONNULL_END
72 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIScrollView+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 13/4/5.
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 "UIScrollView+YYAdd.h"
13 | #import "YYKitMacro.h"
14 |
15 | YYSYNTH_DUMMY_CLASS(UIScrollView_YYAdd)
16 |
17 |
18 | @implementation UIScrollView (YYAdd)
19 |
20 | - (void)scrollToTop {
21 | [self scrollToTopAnimated:YES];
22 | }
23 |
24 | - (void)scrollToBottom {
25 | [self scrollToBottomAnimated:YES];
26 | }
27 |
28 | - (void)scrollToLeft {
29 | [self scrollToLeftAnimated:YES];
30 | }
31 |
32 | - (void)scrollToRight {
33 | [self scrollToRightAnimated:YES];
34 | }
35 |
36 | - (void)scrollToTopAnimated:(BOOL)animated {
37 | CGPoint off = self.contentOffset;
38 | off.y = 0 - self.contentInset.top;
39 | [self setContentOffset:off animated:animated];
40 | }
41 |
42 | - (void)scrollToBottomAnimated:(BOOL)animated {
43 | CGPoint off = self.contentOffset;
44 | off.y = self.contentSize.height - self.bounds.size.height + self.contentInset.bottom;
45 | [self setContentOffset:off animated:animated];
46 | }
47 |
48 | - (void)scrollToLeftAnimated:(BOOL)animated {
49 | CGPoint off = self.contentOffset;
50 | off.x = 0 - self.contentInset.left;
51 | [self setContentOffset:off animated:animated];
52 | }
53 |
54 | - (void)scrollToRightAnimated:(BOOL)animated {
55 | CGPoint off = self.contentOffset;
56 | off.x = self.contentSize.width - self.bounds.size.width + self.contentInset.right;
57 | [self setContentOffset:off animated:animated];
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UITableView+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/5/12.
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 "UITableView+YYAdd.h"
13 | #import "YYKitMacro.h"
14 |
15 | YYSYNTH_DUMMY_CLASS(UITableView_YYAdd)
16 |
17 |
18 | @implementation UITableView (YYAdd)
19 |
20 | - (void)updateWithBlock:(void (^)(UITableView *tableView))block {
21 | [self beginUpdates];
22 | block(self);
23 | [self endUpdates];
24 | }
25 |
26 | - (void)scrollToRow:(NSUInteger)row inSection:(NSUInteger)section atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated {
27 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
28 | [self scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
29 | }
30 |
31 | - (void)insertRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
32 | [self insertRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
33 | }
34 |
35 | - (void)insertRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
36 | NSIndexPath *toInsert = [NSIndexPath indexPathForRow:row inSection:section];
37 | [self insertRowAtIndexPath:toInsert withRowAnimation:animation];
38 | }
39 |
40 | - (void)reloadRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
41 | [self reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
42 | }
43 |
44 | - (void)reloadRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
45 | NSIndexPath *toReload = [NSIndexPath indexPathForRow:row inSection:section];
46 | [self reloadRowAtIndexPath:toReload withRowAnimation:animation];
47 | }
48 |
49 | - (void)deleteRowAtIndexPath:(NSIndexPath *)indexPath withRowAnimation:(UITableViewRowAnimation)animation {
50 | [self deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:animation];
51 | }
52 |
53 | - (void)deleteRow:(NSUInteger)row inSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
54 | NSIndexPath *toDelete = [NSIndexPath indexPathForRow:row inSection:section];
55 | [self deleteRowAtIndexPath:toDelete withRowAnimation:animation];
56 | }
57 |
58 | - (void)insertSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
59 | NSIndexSet *sections = [NSIndexSet indexSetWithIndex:section];
60 | [self insertSections:sections withRowAnimation:animation];
61 | }
62 |
63 | - (void)deleteSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
64 | NSIndexSet *sections = [NSIndexSet indexSetWithIndex:section];
65 | [self deleteSections:sections withRowAnimation:animation];
66 | }
67 |
68 | - (void)reloadSection:(NSUInteger)section withRowAnimation:(UITableViewRowAnimation)animation {
69 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
70 | [self reloadSections:indexSet withRowAnimation:animation];
71 | }
72 |
73 | - (void)clearSelectedRowsAnimated:(BOOL)animated {
74 | NSArray *indexs = [self indexPathsForSelectedRows];
75 | [indexs enumerateObjectsUsingBlock:^(NSIndexPath* path, NSUInteger idx, BOOL *stop) {
76 | [self deselectRowAtIndexPath:path animated:animated];
77 | }];
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UITextField+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+YYAdd.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/5/12.
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 `UITextField`.
18 | */
19 | @interface UITextField (YYAdd)
20 |
21 | /**
22 | Set all text selected.
23 | */
24 | - (void)selectAllText;
25 |
26 | /**
27 | Set text in range selected.
28 |
29 | @param range The range of selected text in a document.
30 | */
31 | - (void)setSelectedRange:(NSRange)range;
32 |
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UITextField+YYAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITextField+YYAdd.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/5/12.
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 "UITextField+YYAdd.h"
13 | #import "YYKitMacro.h"
14 |
15 | YYSYNTH_DUMMY_CLASS(UITextField_YYAdd)
16 |
17 |
18 | @implementation UITextField (YYAdd)
19 |
20 | - (void)selectAllText {
21 | UITextRange *range = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
22 | [self setSelectedTextRange:range];
23 | }
24 |
25 | - (void)setSelectedRange:(NSRange)range {
26 | UITextPosition *beginning = self.beginningOfDocument;
27 | UITextPosition *startPosition = [self positionFromPosition:beginning offset:range.location];
28 | UITextPosition *endPosition = [self positionFromPosition:beginning offset:NSMaxRange(range)];
29 | UITextRange *selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
30 | [self setSelectedTextRange:selectionRange];
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Base/UIKit/UIView+YYAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+YYAdd.h
3 | // YYKit
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 (YYAdd)
20 |
21 | /**
22 | Create a snapshot image of the complete view hierarchy.
23 | */
24 | - (nullable UIImage *)snapshotImage;
25 |
26 | /**
27 | Create a snapshot image of the complete view hierarchy.
28 | @discussion It's faster than "snapshotImage", but may cause screen updates.
29 | See -[UIView drawViewHierarchyInRect:afterScreenUpdates:] for more information.
30 | */
31 | - (nullable UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates;
32 |
33 | /**
34 | Create a snapshot PDF of the complete view hierarchy.
35 | */
36 | - (nullable NSData *)snapshotPDF;
37 |
38 | /**
39 | Shortcut to set the view.layer's shadow
40 |
41 | @param color Shadow Color
42 | @param offset Shadow offset
43 | @param radius Shadow radius
44 | */
45 | - (void)setLayerShadow:(nullable UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
46 |
47 | /**
48 | Remove all subviews.
49 |
50 | @warning Never call this method inside your view's drawRect: method.
51 | */
52 | - (void)removeAllSubviews;
53 |
54 | /**
55 | Returns the view's view controller (may be nil).
56 | */
57 | @property (nullable, nonatomic, readonly) UIViewController *viewController;
58 |
59 | /**
60 | Returns the visible alpha on screen, taking into account superview and window.
61 | */
62 | @property (nonatomic, readonly) CGFloat visibleAlpha;
63 |
64 | /**
65 | Converts a point from the receiver's coordinate system to that of the specified view or window.
66 |
67 | @param point A point specified in the local coordinate system (bounds) of the receiver.
68 | @param view The view or window into whose coordinate system point is to be converted.
69 | If view is nil, this method instead converts to window base coordinates.
70 | @return The point converted to the coordinate system of view.
71 | */
72 | - (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(nullable UIView *)view;
73 |
74 | /**
75 | Converts a point from the coordinate system of a given view or window to that of the receiver.
76 |
77 | @param point A point specified in the local coordinate system (bounds) of view.
78 | @param view The view or window with point in its coordinate system.
79 | If view is nil, this method instead converts from window base coordinates.
80 | @return The point converted to the local coordinate system (bounds) of the receiver.
81 | */
82 | - (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(nullable UIView *)view;
83 |
84 | /**
85 | Converts a rectangle from the receiver's coordinate system to that of another view or window.
86 |
87 | @param rect A rectangle specified in the local coordinate system (bounds) of the receiver.
88 | @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.
89 | @return The converted rectangle.
90 | */
91 | - (CGRect)convertRect:(CGRect)rect toViewOrWindow:(nullable UIView *)view;
92 |
93 | /**
94 | Converts a rectangle from the coordinate system of another view or window to that of the receiver.
95 |
96 | @param rect A rectangle specified in the local coordinate system (bounds) of view.
97 | @param view The view or window with rect in its coordinate system.
98 | If view is nil, this method instead converts from window base coordinates.
99 | @return The converted rectangle.
100 | */
101 | - (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(nullable UIView *)view;
102 |
103 |
104 | @property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
105 | @property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
106 | @property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
107 | @property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
108 | @property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
109 | @property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
110 | @property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
111 | @property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
112 | @property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
113 | @property (nonatomic) CGSize size; ///< Shortcut for frame.size.
114 |
115 | @end
116 |
117 | NS_ASSUME_NONNULL_END
118 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Cache/YYCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYCache.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/13.
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 "YYCache.h"
13 | #import "YYMemoryCache.h"
14 | #import "YYDiskCache.h"
15 |
16 | @implementation YYCache
17 |
18 | - (instancetype) init {
19 | NSLog(@"Use \"initWithName\" or \"initWithPath\" to create YYCache instance.");
20 | return [self initWithPath:@""];
21 | }
22 |
23 | - (instancetype)initWithName:(NSString *)name {
24 | if (name.length == 0) return nil;
25 | NSString *cacheFolder = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
26 | NSString *path = [cacheFolder stringByAppendingPathComponent:name];
27 | return [self initWithPath:path];
28 | }
29 |
30 | - (instancetype)initWithPath:(NSString *)path {
31 | if (path.length == 0) return nil;
32 | YYDiskCache *diskCache = [[YYDiskCache alloc] initWithPath:path];
33 | if (!diskCache) return nil;
34 | NSString *name = [path lastPathComponent];
35 | YYMemoryCache *memoryCache = [YYMemoryCache new];
36 | memoryCache.name = name;
37 |
38 | self = [super init];
39 | _name = name;
40 | _diskCache = diskCache;
41 | _memoryCache = memoryCache;
42 | return self;
43 | }
44 |
45 | + (instancetype)cacheWithName:(NSString *)name {
46 | return [[self alloc] initWithName:name];
47 | }
48 |
49 | + (instancetype)cacheWithPath:(NSString *)path {
50 | return [[self alloc] initWithPath:path];
51 | }
52 |
53 | - (BOOL)containsObjectForKey:(NSString *)key {
54 | return [_memoryCache containsObjectForKey:key] || [_diskCache containsObjectForKey:key];
55 | }
56 |
57 | - (void)containsObjectForKey:(NSString *)key withBlock:(void (^)(NSString *key, BOOL contains))block {
58 | if (!block) return;
59 |
60 | if ([_memoryCache containsObjectForKey:key]) {
61 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
62 | block(key, YES);
63 | });
64 | } else {
65 | [_diskCache containsObjectForKey:key withBlock:block];
66 | }
67 | }
68 |
69 | - (id)objectForKey:(NSString *)key {
70 | id object = [_memoryCache objectForKey:key];
71 | if (!object) {
72 | object = [_diskCache objectForKey:key];
73 | if (object) {
74 | [_memoryCache setObject:object forKey:key];
75 | }
76 | }
77 | return object;
78 | }
79 |
80 | - (void)objectForKey:(NSString *)key withBlock:(void (^)(NSString *key, id object))block {
81 | if (!block) return;
82 | id object = [_memoryCache objectForKey:key];
83 | if (object) {
84 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
85 | block(key, object);
86 | });
87 | } else {
88 | [_diskCache objectForKey:key withBlock:^(NSString *key, id object) {
89 | if (object && ![self->_memoryCache objectForKey:key]) {
90 | [self->_memoryCache setObject:object forKey:key];
91 | }
92 | block(key, object);
93 | }];
94 | }
95 | }
96 |
97 | - (void)setObject:(id)object forKey:(NSString *)key {
98 | [_memoryCache setObject:object forKey:key];
99 | [_diskCache setObject:object forKey:key];
100 | }
101 |
102 | - (void)setObject:(id)object forKey:(NSString *)key withBlock:(void (^)(void))block {
103 | [_memoryCache setObject:object forKey:key];
104 | [_diskCache setObject:object forKey:key withBlock:block];
105 | }
106 |
107 | - (void)removeObjectForKey:(NSString *)key {
108 | [_memoryCache removeObjectForKey:key];
109 | [_diskCache removeObjectForKey:key];
110 | }
111 |
112 | - (void)removeObjectForKey:(NSString *)key withBlock:(void (^)(NSString *key))block {
113 | [_memoryCache removeObjectForKey:key];
114 | [_diskCache removeObjectForKey:key withBlock:block];
115 | }
116 |
117 | - (void)removeAllObjects {
118 | [_memoryCache removeAllObjects];
119 | [_diskCache removeAllObjects];
120 | }
121 |
122 | - (void)removeAllObjectsWithBlock:(void(^)(void))block {
123 | [_memoryCache removeAllObjects];
124 | [_diskCache removeAllObjectsWithBlock:block];
125 | }
126 |
127 | - (void)removeAllObjectsWithProgressBlock:(void(^)(int removedCount, int totalCount))progress
128 | endBlock:(void(^)(BOOL error))end {
129 | [_memoryCache removeAllObjects];
130 | [_diskCache removeAllObjectsWithProgressBlock:progress endBlock:end];
131 |
132 | }
133 |
134 | - (NSString *)description {
135 | if (_name) return [NSString stringWithFormat:@"<%@: %p> (%@)", self.class, self, _name];
136 | else return [NSString stringWithFormat:@"<%@: %p>", self.class, self];
137 | }
138 |
139 | @end
140 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/Categories/CALayer+YYWebImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+YYWebImage.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/23.
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 "YYWebImageManager.h"
19 | #endif
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | /**
24 | Web image methods for CALayer.
25 | It will set image to layer.contents.
26 | */
27 | @interface CALayer (YYWebImage)
28 |
29 | #pragma mark - image
30 |
31 | /**
32 | Current image URL.
33 |
34 | @discussion Set a new value to this property will cancel the previous request
35 | operation and create a new request operation to fetch image. Set nil to clear
36 | the image and image URL.
37 | */
38 | @property (nullable, nonatomic, strong) NSURL *imageURL;
39 |
40 | /**
41 | Set the view's `image` with a specified URL.
42 |
43 | @param imageURL The image url (remote or local file path).
44 | @param placeholder The image to be set initially, until the image request finishes.
45 | */
46 | - (void)setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder;
47 |
48 | /**
49 | Set the view's `image` with a specified URL.
50 |
51 | @param imageURL The image url (remote or local file path).
52 | @param options The options to use when request the image.
53 | */
54 | - (void)setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options;
55 |
56 | /**
57 | Set the view's `image` with a specified URL.
58 |
59 | @param imageURL The image url (remote or local file path).
60 | @param placeholder The image to be set initially, until the image request finishes.
61 | @param options The options to use when request the image.
62 | @param completion The block invoked (on main thread) when image request completed.
63 | */
64 | - (void)setImageWithURL:(nullable NSURL *)imageURL
65 | placeholder:(nullable UIImage *)placeholder
66 | options:(YYWebImageOptions)options
67 | completion:(nullable YYWebImageCompletionBlock)completion;
68 |
69 | /**
70 | Set the view's `image` with a specified URL.
71 |
72 | @param imageURL The image url (remote or local file path).
73 | @param placeholder The image to be set initially, until the image request finishes.
74 | @param options The options to use when request the image.
75 | @param progress The block invoked (on main thread) during image request.
76 | @param transform The block invoked (on background thread) to do additional image process.
77 | @param completion The block invoked (on main thread) when image request completed.
78 | */
79 | - (void)setImageWithURL:(nullable NSURL *)imageURL
80 | placeholder:(nullable UIImage *)placeholder
81 | options:(YYWebImageOptions)options
82 | progress:(nullable YYWebImageProgressBlock)progress
83 | transform:(nullable YYWebImageTransformBlock)transform
84 | completion:(nullable YYWebImageCompletionBlock)completion;
85 |
86 | /**
87 | Set the view's `image` with a specified URL.
88 |
89 | @param imageURL The image url (remote or local file path).
90 | @param placeholder he image to be set initially, until the image request finishes.
91 | @param options The options to use when request the image.
92 | @param manager The manager to create image request operation.
93 | @param progress The block invoked (on main thread) during image request.
94 | @param transform The block invoked (on background thread) to do additional image process.
95 | @param completion The block invoked (on main thread) when image request completed.
96 | */
97 | - (void)setImageWithURL:(nullable NSURL *)imageURL
98 | placeholder:(nullable UIImage *)placeholder
99 | options:(YYWebImageOptions)options
100 | manager:(nullable YYWebImageManager *)manager
101 | progress:(nullable YYWebImageProgressBlock)progress
102 | transform:(nullable YYWebImageTransformBlock)transform
103 | completion:(nullable YYWebImageCompletionBlock)completion;
104 |
105 | /**
106 | Cancel the current image request.
107 | */
108 | - (void)cancelCurrentImageRequest;
109 |
110 | @end
111 |
112 | NS_ASSUME_NONNULL_END
113 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/Categories/MKAnnotationView+YYWebImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // MKAnnotationView+YYWebImage.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/23.
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 "YYWebImageManager.h"
19 | #endif
20 |
21 | NS_ASSUME_NONNULL_BEGIN
22 |
23 | /**
24 | Web image methods for MKAnnotationView.
25 | */
26 | @interface MKAnnotationView (YYWebImage)
27 |
28 | /**
29 | Current image URL.
30 |
31 | @discussion Set a new value to this property will cancel the previous request
32 | operation and create a new request operation to fetch image. Set nil to clear
33 | the image and image URL.
34 | */
35 | @property (nullable, nonatomic, strong) NSURL *imageURL;
36 |
37 | /**
38 | Set the view's `image` with a specified URL.
39 |
40 | @param imageURL The image url (remote or local file path).
41 | @param placeholder The image to be set initially, until the image request finishes.
42 | */
43 | - (void)setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder;
44 |
45 | /**
46 | Set the view's `image` with a specified URL.
47 |
48 | @param imageURL The image url (remote or local file path).
49 | @param options The options to use when request the image.
50 | */
51 | - (void)setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options;
52 |
53 | /**
54 | Set the view's `image` with a specified URL.
55 |
56 | @param imageURL The image url (remote or local file path).
57 | @param placeholder The image to be set initially, until the image request finishes.
58 | @param options The options to use when request the image.
59 | @param completion The block invoked (on main thread) when image request completed.
60 | */
61 | - (void)setImageWithURL:(nullable NSURL *)imageURL
62 | placeholder:(nullable UIImage *)placeholder
63 | options:(YYWebImageOptions)options
64 | completion:(nullable YYWebImageCompletionBlock)completion;
65 |
66 | /**
67 | Set the view's `image` with a specified URL.
68 |
69 | @param imageURL The image url (remote or local file path).
70 | @param placeholder The image to be set initially, until the image request finishes.
71 | @param options The options to use when request the image.
72 | @param progress The block invoked (on main thread) during image request.
73 | @param transform The block invoked (on background thread) to do additional image process.
74 | @param completion The block invoked (on main thread) when image request completed.
75 | */
76 | - (void)setImageWithURL:(nullable NSURL *)imageURL
77 | placeholder:(nullable UIImage *)placeholder
78 | options:(YYWebImageOptions)options
79 | progress:(nullable YYWebImageProgressBlock)progress
80 | transform:(nullable YYWebImageTransformBlock)transform
81 | completion:(nullable YYWebImageCompletionBlock)completion;
82 |
83 | /**
84 | Set the view's `image` with a specified URL.
85 |
86 | @param imageURL The image url (remote or local file path).
87 | @param placeholder he image to be set initially, until the image request finishes.
88 | @param options The options to use when request the image.
89 | @param manager The manager to create image request operation.
90 | @param progress The block invoked (on main thread) during image request.
91 | @param transform The block invoked (on background thread) to do additional image process.
92 | @param completion The block invoked (on main thread) when image request completed.
93 | */
94 | - (void)setImageWithURL:(nullable NSURL *)imageURL
95 | placeholder:(nullable UIImage *)placeholder
96 | options:(YYWebImageOptions)options
97 | manager:(nullable YYWebImageManager *)manager
98 | progress:(nullable YYWebImageProgressBlock)progress
99 | transform:(nullable YYWebImageTransformBlock)transform
100 | completion:(nullable YYWebImageCompletionBlock)completion;
101 |
102 | /**
103 | Cancel the current image request.
104 | */
105 | - (void)cancelCurrentImageRequest;
106 |
107 | @end
108 |
109 | NS_ASSUME_NONNULL_END
110 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/Categories/_YYWebImageSetter.h:
--------------------------------------------------------------------------------
1 | //
2 | // _YYWebImageSetter.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/7/15.
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 | #if __has_include()
13 | #import
14 | #else
15 | #import "YYWebImageManager.h"
16 | #endif
17 |
18 | NS_ASSUME_NONNULL_BEGIN
19 |
20 | extern NSString *const _YYWebImageFadeAnimationKey;
21 | extern const NSTimeInterval _YYWebImageFadeTime;
22 | extern const NSTimeInterval _YYWebImageProgressiveFadeTime;
23 |
24 | /**
25 | Private class used by web image categories.
26 | Typically, you should not use this class directly.
27 | */
28 | @interface _YYWebImageSetter : NSObject
29 | /// Current image url.
30 | @property (nullable, nonatomic, readonly) NSURL *imageURL;
31 | /// Current sentinel.
32 | @property (nonatomic, readonly) int32_t sentinel;
33 |
34 | /// Create new operation for web image and return a sentinel value.
35 | - (int32_t)setOperationWithSentinel:(int32_t)sentinel
36 | url:(nullable NSURL *)imageURL
37 | options:(YYWebImageOptions)options
38 | manager:(YYWebImageManager *)manager
39 | progress:(nullable YYWebImageProgressBlock)progress
40 | transform:(nullable YYWebImageTransformBlock)transform
41 | completion:(nullable YYWebImageCompletionBlock)completion;
42 |
43 | /// Cancel and return a sentinel value. The imageURL will be set to nil.
44 | - (int32_t)cancel;
45 |
46 | /// Cancel and return a sentinel value. The imageURL will be set to new value.
47 | - (int32_t)cancelWithNewURL:(nullable NSURL *)imageURL;
48 |
49 | /// A queue to set operation.
50 | + (dispatch_queue_t)setterQueue;
51 |
52 | @end
53 |
54 | NS_ASSUME_NONNULL_END
55 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/Categories/_YYWebImageSetter.m:
--------------------------------------------------------------------------------
1 | //
2 | // _YYWebImageSetter.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/7/15.
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 "_YYWebImageSetter.h"
13 | #import "YYWebImageOperation.h"
14 | #import
15 |
16 | NSString *const _YYWebImageFadeAnimationKey = @"YYWebImageFade";
17 | const NSTimeInterval _YYWebImageFadeTime = 0.2;
18 | const NSTimeInterval _YYWebImageProgressiveFadeTime = 0.4;
19 |
20 |
21 | @implementation _YYWebImageSetter {
22 | dispatch_semaphore_t _lock;
23 | NSURL *_imageURL;
24 | NSOperation *_operation;
25 | int32_t _sentinel;
26 | }
27 |
28 | - (instancetype)init {
29 | self = [super init];
30 | _lock = dispatch_semaphore_create(1);
31 | return self;
32 | }
33 |
34 | - (NSURL *)imageURL {
35 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
36 | NSURL *imageURL = _imageURL;
37 | dispatch_semaphore_signal(_lock);
38 | return imageURL;
39 | }
40 |
41 | - (void)dealloc {
42 | OSAtomicIncrement32(&_sentinel);
43 | [_operation cancel];
44 | }
45 |
46 | - (int32_t)setOperationWithSentinel:(int32_t)sentinel
47 | url:(NSURL *)imageURL
48 | options:(YYWebImageOptions)options
49 | manager:(YYWebImageManager *)manager
50 | progress:(YYWebImageProgressBlock)progress
51 | transform:(YYWebImageTransformBlock)transform
52 | completion:(YYWebImageCompletionBlock)completion {
53 | if (sentinel != _sentinel) {
54 | if (completion) completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageCancelled, nil);
55 | return _sentinel;
56 | }
57 |
58 | NSOperation *operation = [manager requestImageWithURL:imageURL options:options progress:progress transform:transform completion:completion];
59 | if (!operation && completion) {
60 | NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"YYWebImageOperation create failed." };
61 | completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageFinished, [NSError errorWithDomain:@"com.ibireme.yykit.webimage" code:-1 userInfo:userInfo]);
62 | }
63 |
64 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
65 | if (sentinel == _sentinel) {
66 | if (_operation) [_operation cancel];
67 | _operation = operation;
68 | sentinel = OSAtomicIncrement32(&_sentinel);
69 | } else {
70 | [operation cancel];
71 | }
72 | dispatch_semaphore_signal(_lock);
73 | return sentinel;
74 | }
75 |
76 | - (int32_t)cancel {
77 | return [self cancelWithNewURL:nil];
78 | }
79 |
80 | - (int32_t)cancelWithNewURL:(NSURL *)imageURL {
81 | int32_t sentinel;
82 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
83 | if (_operation) {
84 | [_operation cancel];
85 | _operation = nil;
86 | }
87 | _imageURL = imageURL;
88 | sentinel = OSAtomicIncrement32(&_sentinel);
89 | dispatch_semaphore_signal(_lock);
90 | return sentinel;
91 | }
92 |
93 | + (dispatch_queue_t)setterQueue {
94 | static dispatch_queue_t queue;
95 | static dispatch_once_t onceToken;
96 | dispatch_once(&onceToken, ^{
97 | queue = dispatch_queue_create("com.ibireme.yykit.webimage.setter", DISPATCH_QUEUE_SERIAL);
98 | dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
99 | });
100 | return queue;
101 | }
102 |
103 | @end
104 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYAnimatedImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYAnimatedImageView.h
3 | // YYKit
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 | /// If 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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYFrameImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYFrameImage.h
3 | // YYKit
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 | #else
17 | #import "YYAnimatedImageView.h"
18 | #endif
19 |
20 | NS_ASSUME_NONNULL_BEGIN
21 |
22 | /**
23 | An image to display frame-based animation.
24 |
25 | @discussion It is a fully compatible `UIImage` subclass.
26 | It only support system image format such as png and jpeg.
27 | The animation can be played by YYAnimatedImageView.
28 |
29 | Sample Code:
30 |
31 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"];
32 | NSArray *times = @[@0.1, @0.2, @0.1];
33 | YYFrameImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES];
34 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image];
35 | [view addSubView:imageView];
36 | */
37 | @interface YYFrameImage : UIImage
38 |
39 | /**
40 | Create a frame animated image from files.
41 |
42 | @param paths An array of NSString objects, contains the full or
43 | partial path to each image file.
44 | e.g. @[@"/ani/1.png",@"/ani/2.png",@"/ani/3.png"]
45 |
46 | @param oneFrameDuration The duration (in seconds) per frame.
47 |
48 | @param loopCount The animation loop count, 0 means infinite.
49 |
50 | @return An initialized YYFrameImage object, or nil when an error occurs.
51 | */
52 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths
53 | oneFrameDuration:(NSTimeInterval)oneFrameDuration
54 | loopCount:(NSUInteger)loopCount;
55 |
56 | /**
57 | Create a frame animated image from files.
58 |
59 | @param paths An array of NSString objects, contains the full or
60 | partial path to each image file.
61 | e.g. @[@"/ani/frame1.png",@"/ani/frame2.png",@"/ani/frame3.png"]
62 |
63 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame.
64 | e.g. @[@0.1, @0.2, @0.3];
65 |
66 | @param loopCount The animation loop count, 0 means infinite.
67 |
68 | @return An initialized YYFrameImage object, or nil when an error occurs.
69 | */
70 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths
71 | frameDurations:(NSArray *)frameDurations
72 | loopCount:(NSUInteger)loopCount;
73 |
74 | /**
75 | Create a frame animated image from an array of data.
76 |
77 | @param dataArray An array of NSData objects.
78 |
79 | @param oneFrameDuration The duration (in seconds) per frame.
80 |
81 | @param loopCount The animation loop count, 0 means infinite.
82 |
83 | @return An initialized YYFrameImage object, or nil when an error occurs.
84 | */
85 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray
86 | oneFrameDuration:(NSTimeInterval)oneFrameDuration
87 | loopCount:(NSUInteger)loopCount;
88 |
89 | /**
90 | Create a frame animated image from an array of data.
91 |
92 | @param dataArray An array of NSData objects.
93 |
94 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame.
95 | e.g. @[@0.1, @0.2, @0.3];
96 |
97 | @param loopCount The animation loop count, 0 means infinite.
98 |
99 | @return An initialized YYFrameImage object, or nil when an error occurs.
100 | */
101 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray
102 | frameDurations:(NSArray *)frameDurations
103 | loopCount:(NSUInteger)loopCount;
104 |
105 | @end
106 |
107 | NS_ASSUME_NONNULL_END
108 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYFrameImage.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYFrameImage.m
3 | // YYKit
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 "NSString+YYAdd.h"
14 | #import "UIImage+YYAdd.h"
15 | #import "YYImageCoder.h"
16 |
17 | @implementation YYFrameImage {
18 | NSUInteger _loopCount;
19 | NSUInteger _oneFrameBytes;
20 | NSArray *_imagePaths;
21 | NSArray *_imageDatas;
22 | NSArray *_frameDurations;
23 | }
24 |
25 | - (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount {
26 | NSMutableArray *durations = [NSMutableArray new];
27 | for (int i = 0, max = (int)paths.count; i < max; i++) {
28 | [durations addObject:@(oneFrameDuration)];
29 | }
30 | return [self initWithImagePaths:paths frameDurations:durations loopCount:loopCount];
31 | }
32 |
33 | - (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount {
34 | if (paths.count == 0) return nil;
35 | if (paths.count != frameDurations.count) return nil;
36 |
37 | NSString *firstPath = paths[0];
38 | NSData *firstData = [NSData dataWithContentsOfFile:firstPath];
39 | CGFloat scale = firstPath.pathScale;
40 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] imageByDecoded];
41 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp];
42 | if (!self) return nil;
43 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage);
44 | _oneFrameBytes = (NSUInteger)frameByte;
45 | _imagePaths = paths.copy;
46 | _frameDurations = frameDurations.copy;
47 | _loopCount = loopCount;
48 |
49 | return self;
50 | }
51 |
52 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount {
53 | NSMutableArray *durations = [NSMutableArray new];
54 | for (int i = 0, max = (int)dataArray.count; i < max; i++) {
55 | [durations addObject:@(oneFrameDuration)];
56 | }
57 | return [self initWithImageDataArray:dataArray frameDurations:durations loopCount:loopCount];
58 | }
59 |
60 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount {
61 | if (dataArray.count == 0) return nil;
62 | if (dataArray.count != frameDurations.count) return nil;
63 |
64 | NSData *firstData = dataArray[0];
65 | CGFloat scale = [UIScreen mainScreen].scale;
66 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] imageByDecoded];
67 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp];
68 | if (!self) return nil;
69 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage);
70 | _oneFrameBytes = (NSUInteger)frameByte;
71 | _imageDatas = dataArray.copy;
72 | _frameDurations = frameDurations.copy;
73 | _loopCount = loopCount;
74 |
75 | return self;
76 | }
77 |
78 | #pragma mark - YYAnimtedImage
79 |
80 | - (NSUInteger)animatedImageFrameCount {
81 | if (_imagePaths) {
82 | return _imagePaths.count;
83 | } else if (_imageDatas) {
84 | return _imageDatas.count;
85 | } else {
86 | return 1;
87 | }
88 | }
89 |
90 | - (NSUInteger)animatedImageLoopCount {
91 | return _loopCount;
92 | }
93 |
94 | - (NSUInteger)animatedImageBytesPerFrame {
95 | return _oneFrameBytes;
96 | }
97 |
98 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
99 | if (_imagePaths) {
100 | if (index >= _imagePaths.count) return nil;
101 | NSString *path = _imagePaths[index];
102 | CGFloat scale = [path pathScale];
103 | NSData *data = [NSData dataWithContentsOfFile:path];
104 | return [[UIImage imageWithData:data scale:scale] imageByDecoded];
105 | } else if (_imageDatas) {
106 | if (index >= _imageDatas.count) return nil;
107 | NSData *data = _imageDatas[index];
108 | return [[UIImage imageWithData:data scale:[UIScreen mainScreen].scale] imageByDecoded];
109 | } else {
110 | return index == 0 ? self : nil;
111 | }
112 | }
113 |
114 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index {
115 | if (index >= _frameDurations.count) return 0;
116 | NSNumber *num = _frameDurations[index];
117 | return [num doubleValue];
118 | }
119 |
120 | @end
121 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYImage.h
3 | // YYKit
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 | #import
16 | #import
17 | #else
18 | #import "YYAnimatedImageView.h"
19 | #import "YYImageCoder.h"
20 | #endif
21 |
22 | NS_ASSUME_NONNULL_BEGIN
23 |
24 | /**
25 | A YYImage object is a high-level way to display animated image data.
26 |
27 | @discussion It is a fully compatible `UIImage` subclass. It extends the UIImage
28 | to support animated WebP, APNG and GIF format image data decoding. It also
29 | support NSCoding protocol to archive and unarchive multi-frame image data.
30 |
31 | If the image is created from multi-frame image data, and you want to play the
32 | animation, try replace UIImageView with `YYAnimatedImageView`.
33 |
34 | Sample Code:
35 |
36 | // animation@3x.webp
37 | YYImage *image = [YYImage imageNamed:@"animation.webp"];
38 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image];
39 | [view addSubView:imageView];
40 |
41 | */
42 | @interface YYImage : UIImage
43 |
44 | + (nullable YYImage *)imageNamed:(NSString *)name; // no cache!
45 | + (nullable YYImage *)imageWithContentsOfFile:(NSString *)path;
46 | + (nullable YYImage *)imageWithData:(NSData *)data;
47 | + (nullable YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
48 |
49 | /**
50 | If the image is created from data or file, then the value indicates the data type.
51 | */
52 | @property (nonatomic, readonly) YYImageType animatedImageType;
53 |
54 | /**
55 | If the image is created from animated image data (multi-frame GIF/APNG/WebP),
56 | this property stores the original image data.
57 | */
58 | @property (nullable, nonatomic, readonly) NSData *animatedImageData;
59 |
60 | /**
61 | The total memory usage (in bytes) if all frame images was loaded into memory.
62 | The value is 0 if the image is not created from a multi-frame image data.
63 | */
64 | @property (nonatomic, readonly) NSUInteger animatedImageMemorySize;
65 |
66 | /**
67 | Preload all frame image to memory.
68 |
69 | @discussion Set this property to `YES` will block the calling thread to decode
70 | all animation frame image to memory, set to `NO` will release the preloaded frames.
71 | If the image is shared by lots of image views (such as emoticon), preload all
72 | frames will reduce the CPU cost.
73 |
74 | See `animatedImageMemorySize` for memory cost.
75 | */
76 | @property (nonatomic) BOOL preloadAllAnimatedImageFrames;
77 |
78 | @end
79 |
80 | NS_ASSUME_NONNULL_END
81 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYSpriteSheetImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYSpriteImage.h
3 | // YYKit
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 "YYAnimatedImageView.h"
18 | #endif
19 |
20 | NS_ASSUME_NONNULL_BEGIN
21 |
22 | /**
23 | An image to display sprite sheet animation.
24 |
25 | @discussion It is a fully compatible `UIImage` subclass.
26 | The animation can be played by YYAnimatedImageView.
27 |
28 | Sample Code:
29 |
30 | // 8 * 12 sprites in a single sheet image
31 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"];
32 | NSMutableArray *contentRects = [NSMutableArray new];
33 | NSMutableArray *durations = [NSMutableArray new];
34 | for (int j = 0; j < 12; j++) {
35 | for (int i = 0; i < 8; i++) {
36 | CGRect rect;
37 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12);
38 | rect.origin.x = img.size.width / 8 * i;
39 | rect.origin.y = img.size.height / 12 * j;
40 | [contentRects addObject:[NSValue valueWithCGRect:rect]];
41 | [durations addObject:@(1 / 60.0)];
42 | }
43 | }
44 | YYSpriteSheetImage *sprite;
45 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img
46 | contentRects:contentRects
47 | frameDurations:durations
48 | loopCount:0];
49 | YYAnimatedImageView *imgView = [YYAnimatedImageView new];
50 | imgView.size = CGSizeMake(img.size.width / 8, img.size.height / 12);
51 | imgView.image = sprite;
52 |
53 |
54 |
55 | @discussion It can also be used to display single frame in sprite sheet image.
56 | Sample Code:
57 |
58 | YYSpriteSheetImage *sheet = ...;
59 | UIImageView *imageView = ...;
60 | imageView.image = sheet;
61 | imageView.layer.contentsRect = [sheet contentsRectForCALayerAtIndex:6];
62 |
63 | */
64 | @interface YYSpriteSheetImage : UIImage
65 |
66 | /**
67 | Creates and returns an image object.
68 |
69 | @param image The sprite sheet image (contains all frames).
70 |
71 | @param contentRects The sprite sheet image frame rects in the image coordinates.
72 | The rectangle should not outside the image's bounds. The objects in this array
73 | should be created with [NSValue valueWithCGRect:].
74 |
75 | @param frameDurations The sprite sheet image frame's durations in seconds.
76 | The objects in this array should be NSNumber.
77 |
78 | @param loopCount Animation loop count, 0 means infinite looping.
79 |
80 | @return An image object, or nil if an error occurs.
81 | */
82 | - (nullable instancetype)initWithSpriteSheetImage:(UIImage *)image
83 | contentRects:(NSArray *)contentRects
84 | frameDurations:(NSArray *)frameDurations
85 | loopCount:(NSUInteger)loopCount;
86 |
87 | @property (nonatomic, readonly) NSArray *contentRects;
88 | @property (nonatomic, readonly) NSArray *frameDurations;
89 | @property (nonatomic, readonly) NSUInteger loopCount;
90 |
91 | /**
92 | Get the contents rect for CALayer.
93 | See "contentsRect" property in CALayer for more information.
94 |
95 | @param index Index of frame.
96 | @return Contents Rect.
97 | */
98 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index;
99 |
100 | @end
101 |
102 | NS_ASSUME_NONNULL_END
103 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYSpriteSheetImage.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYSpriteImage.m
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYWebImageManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYWebImageManager.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/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 "YYWebImageManager.h"
13 | #import "YYImageCache.h"
14 | #import "YYWebImageOperation.h"
15 | #import "YYImageCoder.h"
16 |
17 | @implementation YYWebImageManager
18 |
19 | + (instancetype)sharedManager {
20 | static YYWebImageManager *manager;
21 | static dispatch_once_t onceToken;
22 | dispatch_once(&onceToken, ^{
23 | YYImageCache *cache = [YYImageCache sharedCache];
24 | NSOperationQueue *queue = [NSOperationQueue new];
25 | if ([queue respondsToSelector:@selector(setQualityOfService:)]) {
26 | queue.qualityOfService = NSQualityOfServiceBackground;
27 | }
28 | manager = [[self alloc] initWithCache:cache queue:queue];
29 | });
30 | return manager;
31 | }
32 |
33 | - (instancetype)init {
34 | @throw [NSException exceptionWithName:@"YYWebImageManager init error" reason:@"Use the designated initializer to init." userInfo:nil];
35 | return [self initWithCache:nil queue:nil];
36 | }
37 |
38 | - (instancetype)initWithCache:(YYImageCache *)cache queue:(NSOperationQueue *)queue{
39 | self = [super init];
40 | if (!self) return nil;
41 | _cache = cache;
42 | _queue = queue;
43 | _timeout = 15.0;
44 | if (YYImageWebPAvailable()) {
45 | _headers = @{ @"Accept" : @"image/webp,image/*;q=0.8" };
46 | } else {
47 | _headers = @{ @"Accept" : @"image/*;q=0.8" };
48 | }
49 | return self;
50 | }
51 |
52 | - (YYWebImageOperation *)requestImageWithURL:(NSURL *)url
53 | options:(YYWebImageOptions)options
54 | progress:(YYWebImageProgressBlock)progress
55 | transform:(YYWebImageTransformBlock)transform
56 | completion:(YYWebImageCompletionBlock)completion {
57 |
58 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
59 | request.timeoutInterval = _timeout;
60 | request.HTTPShouldHandleCookies = (options & YYWebImageOptionHandleCookies) != 0;
61 | request.allHTTPHeaderFields = [self headersForURL:url];
62 | request.HTTPShouldUsePipelining = YES;
63 | request.cachePolicy = (options & YYWebImageOptionUseNSURLCache) ?
64 | NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData;
65 |
66 | YYWebImageOperation *operation = [[YYWebImageOperation alloc] initWithRequest:request
67 | options:options
68 | cache:_cache
69 | cacheKey:[self cacheKeyForURL:url]
70 | progress:progress
71 | transform:transform ? transform : _sharedTransformBlock
72 | completion:completion];
73 |
74 | if (_username && _password) {
75 | operation.credential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceForSession];
76 | }
77 | if (operation) {
78 | NSOperationQueue *queue = _queue;
79 | if (queue) {
80 | [queue addOperation:operation];
81 | } else {
82 | [operation start];
83 | }
84 | }
85 | return operation;
86 | }
87 |
88 | - (NSDictionary *)headersForURL:(NSURL *)url {
89 | if (!url) return nil;
90 | return _headersFilter ? _headersFilter(url, _headers) : _headers;
91 | }
92 |
93 | - (NSString *)cacheKeyForURL:(NSURL *)url {
94 | if (!url) return nil;
95 | return _cacheKeyFilter ? _cacheKeyFilter(url) : url.absoluteString;
96 | }
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Image/YYWebImageOperation.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYWebImageOperation.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/15.
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 "YYImageCache.h"
19 | #import "YYWebImageManager.h"
20 | #endif
21 |
22 | NS_ASSUME_NONNULL_BEGIN
23 |
24 | /**
25 | The YYWebImageOperation class is an NSOperation subclass used to fetch image
26 | from URL request.
27 |
28 | @discussion It's an asynchronous operation. You typically execute it by adding
29 | it to an operation queue, or calls 'start' to execute it manually. When the
30 | operation is started, it will:
31 |
32 | 1. Get the image from the cache, if exist, return it with `completion` block.
33 | 2. Start an URL connection to fetch image from the request, invoke the `progress`
34 | to notify request progress (and invoke `completion` block to return the
35 | progressive image if enabled by progressive option).
36 | 3. Process the image by invoke the `transform` block.
37 | 4. Put the image to cache and return it with `completion` block.
38 |
39 | */
40 | @interface YYWebImageOperation : NSOperation
41 |
42 | @property (nonatomic, strong, readonly) NSURLRequest *request; ///< The image URL request.
43 | @property (nullable, nonatomic, strong, readonly) NSURLResponse *response; ///< The response for request.
44 | @property (nullable, nonatomic, strong, readonly) YYImageCache *cache; ///< The image cache.
45 | @property (nonatomic, strong, readonly) NSString *cacheKey; ///< The image cache key.
46 | @property (nonatomic, readonly) YYWebImageOptions options; ///< The operation's option.
47 |
48 | /**
49 | Whether the URL connection should consult the credential storage for authenticating
50 | the connection. Default is YES.
51 |
52 | @discussion This is the value that is returned in the `NSURLConnectionDelegate`
53 | method `-connectionShouldUseCredentialStorage:`.
54 | */
55 | @property (nonatomic) BOOL shouldUseCredentialStorage;
56 |
57 | /**
58 | The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`.
59 |
60 | @discussion This will be overridden by any shared credentials that exist for the
61 | username or password of the request URL, if present.
62 | */
63 | @property (nullable, nonatomic, strong) NSURLCredential *credential;
64 |
65 | /**
66 | Creates and returns a new operation.
67 |
68 | You should call `start` to execute this operation, or you can add the operation
69 | to an operation queue.
70 |
71 | @param request The Image request. This value should not be nil.
72 | @param options A mask to specify options to use for this operation.
73 | @param cache An image cache. Pass nil to avoid image cache.
74 | @param cacheKey An image cache key. Pass nil to avoid image cache.
75 | @param progress A block invoked in image fetch progress.
76 | The block will be invoked in background thread. Pass nil to avoid it.
77 | @param transform A block invoked before image fetch finished to do additional image process.
78 | The block will be invoked in background thread. Pass nil to avoid it.
79 | @param completion A block invoked when image fetch finished or cancelled.
80 | The block will be invoked in background thread. Pass nil to avoid it.
81 |
82 | @return The image request opeartion, or nil if an error occurs.
83 | */
84 | - (instancetype)initWithRequest:(NSURLRequest *)request
85 | options:(YYWebImageOptions)options
86 | cache:(nullable YYImageCache *)cache
87 | cacheKey:(nullable NSString *)cacheKey
88 | progress:(nullable YYWebImageProgressBlock)progress
89 | transform:(nullable YYWebImageTransformBlock)transform
90 | completion:(nullable YYWebImageCompletionBlock)completion NS_DESIGNATED_INITIALIZER;
91 |
92 | - (instancetype)init UNAVAILABLE_ATTRIBUTE;
93 | + (instancetype)new UNAVAILABLE_ATTRIBUTE;
94 |
95 | @end
96 |
97 | NS_ASSUME_NONNULL_END
98 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextContainerView.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextContainerView.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextDebugOption.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextDebugOption.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextDebugOption.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextDebugOption.m
3 | // YYKit
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 "YYKitMacro.h"
14 | #import "UIColor+YYAdd.h"
15 | #import "YYWeakProxy.h"
16 |
17 |
18 | static pthread_mutex_t _sharedDebugLock;
19 | static CFMutableSetRef _sharedDebugTargets = nil;
20 | static YYTextDebugOption *_sharedDebugOption = nil;
21 |
22 | static const void* _sharedDebugSetRetain(CFAllocatorRef allocator, const void *value) {
23 | return value;
24 | }
25 |
26 | static void _sharedDebugSetRelease(CFAllocatorRef allocator, const void *value) {
27 | }
28 |
29 | void _sharedDebugSetFunction(const void *value, void *context) {
30 | id target = (__bridge id)(value);
31 | [target setDebugOption:_sharedDebugOption];
32 | }
33 |
34 | static void _initSharedDebug() {
35 | static dispatch_once_t onceToken;
36 | dispatch_once(&onceToken, ^{
37 | pthread_mutex_init(&_sharedDebugLock, NULL);
38 | CFSetCallBacks callbacks = kCFTypeSetCallBacks;
39 | callbacks.retain = _sharedDebugSetRetain;
40 | callbacks.release = _sharedDebugSetRelease;
41 | _sharedDebugTargets = CFSetCreateMutable(CFAllocatorGetDefault(), 0, &callbacks);
42 | });
43 | }
44 |
45 | static void _setSharedDebugOption(YYTextDebugOption *option) {
46 | _initSharedDebug();
47 | pthread_mutex_lock(&_sharedDebugLock);
48 | _sharedDebugOption = option.copy;
49 | CFSetApplyFunction(_sharedDebugTargets, _sharedDebugSetFunction, NULL);
50 | pthread_mutex_unlock(&_sharedDebugLock);
51 | }
52 |
53 | static YYTextDebugOption *_getSharedDebugOption() {
54 | _initSharedDebug();
55 | pthread_mutex_lock(&_sharedDebugLock);
56 | YYTextDebugOption *op = _sharedDebugOption;
57 | pthread_mutex_unlock(&_sharedDebugLock);
58 | return op;
59 | }
60 |
61 | static void _addDebugTarget(id target) {
62 | _initSharedDebug();
63 | pthread_mutex_lock(&_sharedDebugLock);
64 | CFSetAddValue(_sharedDebugTargets, (__bridge const void *)(target));
65 | pthread_mutex_unlock(&_sharedDebugLock);
66 | }
67 |
68 | static void _removeDebugTarget(id target) {
69 | _initSharedDebug();
70 | pthread_mutex_lock(&_sharedDebugLock);
71 | CFSetRemoveValue(_sharedDebugTargets, (__bridge const void *)(target));
72 | pthread_mutex_unlock(&_sharedDebugLock);
73 | }
74 |
75 |
76 | @implementation YYTextDebugOption
77 |
78 | - (id)copyWithZone:(NSZone *)zone {
79 | YYTextDebugOption *op = [self.class new];
80 | op.baselineColor = self.baselineColor;
81 | op.CTFrameBorderColor = self.CTFrameBorderColor;
82 | op.CTFrameFillColor = self.CTFrameFillColor;
83 | op.CTLineBorderColor = self.CTLineBorderColor;
84 | op.CTLineFillColor = self.CTLineFillColor;
85 | op.CTLineNumberColor = self.CTLineNumberColor;
86 | op.CTRunBorderColor = self.CTRunBorderColor;
87 | op.CTRunFillColor = self.CTRunFillColor;
88 | op.CTRunNumberColor = self.CTRunNumberColor;
89 | op.CGGlyphBorderColor = self.CGGlyphBorderColor;
90 | op.CGGlyphFillColor = self.CGGlyphFillColor;
91 | return op;
92 | }
93 |
94 | - (BOOL)needDrawDebug {
95 | if (self.baselineColor ||
96 | self.CTFrameBorderColor ||
97 | self.CTFrameFillColor ||
98 | self.CTLineBorderColor ||
99 | self.CTLineFillColor ||
100 | self.CTLineNumberColor ||
101 | self.CTRunBorderColor ||
102 | self.CTRunFillColor ||
103 | self.CTRunNumberColor ||
104 | self.CGGlyphBorderColor ||
105 | self.CGGlyphFillColor) return YES;
106 | return NO;
107 | }
108 |
109 | - (void)clear {
110 | self.baselineColor = nil;
111 | self.CTFrameBorderColor = nil;
112 | self.CTFrameFillColor = nil;
113 | self.CTLineBorderColor = nil;
114 | self.CTLineFillColor = nil;
115 | self.CTLineNumberColor = nil;
116 | self.CTRunBorderColor = nil;
117 | self.CTRunFillColor = nil;
118 | self.CTRunNumberColor = nil;
119 | self.CGGlyphBorderColor = nil;
120 | self.CGGlyphFillColor = nil;
121 | }
122 |
123 | + (void)addDebugTarget:(id)target {
124 | if (target) _addDebugTarget(target);
125 | }
126 |
127 | + (void)removeDebugTarget:(id)target {
128 | if (target) _removeDebugTarget(target);
129 | }
130 |
131 | + (YYTextDebugOption *)sharedDebugOption {
132 | return _getSharedDebugOption();
133 | }
134 |
135 | + (void)setSharedDebugOption:(YYTextDebugOption *)option {
136 | YYAssertMainThread();
137 | _setSharedDebugOption(option);
138 | }
139 |
140 | @end
141 |
142 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextEffectWindow.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextEffectWindow.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextInput.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextInput.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextInput.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextInput.m
3 | // YYKit
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 "YYKitMacro.h"
14 |
15 | @implementation YYTextPosition
16 |
17 | + (instancetype)positionWithOffset:(NSInteger)offset {
18 | return [self positionWithOffset:offset affinity:YYTextAffinityForward];
19 | }
20 |
21 | + (instancetype)positionWithOffset:(NSInteger)offset affinity:(YYTextAffinity)affinity {
22 | YYTextPosition *p = [self new];
23 | p->_offset = offset;
24 | p->_affinity = affinity;
25 | return p;
26 | }
27 |
28 | - (instancetype)copyWithZone:(NSZone *)zone {
29 | return [self.class positionWithOffset:_offset affinity:_affinity];
30 | }
31 |
32 | - (NSString *)description {
33 | return [NSString stringWithFormat:@"<%@: %p> (%@%@)", self.class, self, @(_offset), _affinity == YYTextAffinityForward ? @"F":@"B"];
34 | }
35 |
36 | - (NSUInteger)hash {
37 | return _offset * 2 + (_affinity == YYTextAffinityForward ? 1 : 0);
38 | }
39 |
40 | - (BOOL)isEqual:(YYTextPosition *)object {
41 | if (!object) return NO;
42 | return _offset == object.offset && _affinity == object.affinity;
43 | }
44 |
45 | - (NSComparisonResult)compare:(YYTextPosition *)otherPosition {
46 | if (!otherPosition) return NSOrderedAscending;
47 | if (_offset < otherPosition.offset) return NSOrderedAscending;
48 | if (_offset > otherPosition.offset) return NSOrderedDescending;
49 | if (_affinity == YYTextAffinityBackward && otherPosition.affinity == YYTextAffinityForward) return NSOrderedAscending;
50 | if (_affinity == YYTextAffinityForward && otherPosition.affinity == YYTextAffinityBackward) return NSOrderedDescending;
51 | return NSOrderedSame;
52 | }
53 |
54 | @end
55 |
56 |
57 |
58 | @implementation YYTextRange {
59 | YYTextPosition *_start;
60 | YYTextPosition *_end;
61 | }
62 |
63 | - (instancetype)init {
64 | self = [super init];
65 | if (!self) return nil;
66 | _start = [YYTextPosition positionWithOffset:0];
67 | _end = [YYTextPosition positionWithOffset:0];
68 | return self;
69 | }
70 |
71 | - (YYTextPosition *)start {
72 | return _start;
73 | }
74 |
75 | - (YYTextPosition *)end {
76 | return _end;
77 | }
78 |
79 | - (BOOL)isEmpty {
80 | return _start.offset == _end.offset;
81 | }
82 |
83 | - (NSRange)asRange {
84 | return NSMakeRange(_start.offset, _end.offset - _start.offset);
85 | }
86 |
87 | + (instancetype)rangeWithRange:(NSRange)range {
88 | return [self rangeWithRange:range affinity:YYTextAffinityForward];
89 | }
90 |
91 | + (instancetype)rangeWithRange:(NSRange)range affinity:(YYTextAffinity)affinity {
92 | YYTextPosition *start = [YYTextPosition positionWithOffset:range.location affinity:affinity];
93 | YYTextPosition *end = [YYTextPosition positionWithOffset:range.location + range.length affinity:affinity];
94 | return [self rangeWithStart:start end:end];
95 | }
96 |
97 | + (instancetype)rangeWithStart:(YYTextPosition *)start end:(YYTextPosition *)end {
98 | if (!start || !end) return nil;
99 | if ([start compare:end] == NSOrderedDescending) {
100 | YY_SWAP(start, end);
101 | }
102 | YYTextRange *range = [YYTextRange new];
103 | range->_start = start;
104 | range->_end = end;
105 | return range;
106 | }
107 |
108 | + (instancetype)defaultRange {
109 | return [self new];
110 | }
111 |
112 | - (instancetype)copyWithZone:(NSZone *)zone {
113 | return [self.class rangeWithStart:_start end:_end];
114 | }
115 |
116 | - (NSString *)description {
117 | return [NSString stringWithFormat:@"<%@: %p> (%@, %@)%@", self.class, self, @(_start.offset), @(_end.offset - _start.offset), _end.affinity == YYTextAffinityForward ? @"F":@"B"];
118 | }
119 |
120 | - (NSUInteger)hash {
121 | return (sizeof(NSUInteger) == 8 ? OSSwapInt64(_start.hash) : OSSwapInt32(_start.hash)) + _end.hash;
122 | }
123 |
124 | - (BOOL)isEqual:(YYTextRange *)object {
125 | if (!object) return NO;
126 | return [_start isEqual:object.start] && [_end isEqual:object.end];
127 | }
128 |
129 | @end
130 |
131 |
132 |
133 | @implementation YYTextSelectionRect
134 |
135 | @synthesize rect = _rect;
136 | @synthesize writingDirection = _writingDirection;
137 | @synthesize containsStart = _containsStart;
138 | @synthesize containsEnd = _containsEnd;
139 | @synthesize isVertical = _isVertical;
140 |
141 | - (id)copyWithZone:(NSZone *)zone {
142 | YYTextSelectionRect *one = [self.class new];
143 | one.rect = _rect;
144 | one.writingDirection = _writingDirection;
145 | one.containsStart = _containsStart;
146 | one.containsEnd = _containsEnd;
147 | one.isVertical = _isVertical;
148 | return one;
149 | }
150 |
151 | @end
152 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextKeyboardManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextKeyboardManager.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextLine.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextLine.h
3 | // YYKit
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 (nullable, nonatomic, readonly) NSArray *attachments; ///< YYTextAttachment
57 | @property (nullable, nonatomic, readonly) NSArray *attachmentRanges; ///< NSRange(NSValue)
58 | @property (nullable, 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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextMagnifier.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextMagnifier.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/Component/YYTextSelectionView.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextSelectionView.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/NSParagraphStyle+YYText.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSParagraphStyle+YYText.h
3 | // YYKit
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 *)styleWithCTStyle:(CTParagraphStyleRef)CTStyle;
29 |
30 | /**
31 | Creates and returns a CoreText Paragraph Style. (need call CFRelease() after used)
32 | */
33 | - (nullable CTParagraphStyleRef)CTStyle CF_RETURNS_RETAINED;
34 |
35 | @end
36 |
37 | NS_ASSUME_NONNULL_END
38 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/UIPasteboard+YYText.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIPasteboard+YYText.h
3 | // YYKit
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 *PNGData; ///< PNG file data
22 | @property (nullable, nonatomic, copy) NSData *JPEGData; ///< JPEG file data
23 | @property (nullable, nonatomic, copy) NSData *GIFData; ///< GIF file data
24 | @property (nullable, nonatomic, copy) NSData *WEBPData; ///< WebP file data
25 | @property (nullable, nonatomic, copy) NSData *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 *attributedString;
31 |
32 | @end
33 |
34 |
35 | /// The name identifying the attributed string in pasteboard.
36 | UIKIT_EXTERN NSString *const YYPasteboardTypeAttributedString;
37 |
38 | /// The UTI Type identifying WebP data in pasteboard.
39 | UIKIT_EXTERN NSString *const YYUTTypeWEBP;
40 |
41 | NS_ASSUME_NONNULL_END
42 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextArchiver.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextArchiver.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextParser.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextRubyAnnotation.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextRubyAnnotation.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextRubyAnnotation.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextRubyAnnotation.m
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextRunDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextRunDelegate.h
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextRunDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextRunDelegate.m
3 | // YYKit
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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Text/String/YYTextUtilities.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTextUtilities.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/4/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 "YYTextUtilities.h"
13 |
14 | NSCharacterSet *YYTextVerticalFormRotateCharacterSet() {
15 | static NSMutableCharacterSet *set;
16 | static dispatch_once_t onceToken;
17 | dispatch_once(&onceToken, ^{
18 | set = [NSMutableCharacterSet new];
19 | [set addCharactersInRange:NSMakeRange(0x1100, 256)]; // Hangul Jamo
20 | [set addCharactersInRange:NSMakeRange(0x2460, 160)]; // Enclosed Alphanumerics
21 | [set addCharactersInRange:NSMakeRange(0x2600, 256)]; // Miscellaneous Symbols
22 | [set addCharactersInRange:NSMakeRange(0x2700, 192)]; // Dingbats
23 | [set addCharactersInRange:NSMakeRange(0x2E80, 128)]; // CJK Radicals Supplement
24 | [set addCharactersInRange:NSMakeRange(0x2F00, 224)]; // Kangxi Radicals
25 | [set addCharactersInRange:NSMakeRange(0x2FF0, 16)]; // Ideographic Description Characters
26 | [set addCharactersInRange:NSMakeRange(0x3000, 64)]; // CJK Symbols and Punctuation
27 | [set removeCharactersInRange:NSMakeRange(0x3008, 10)];
28 | [set removeCharactersInRange:NSMakeRange(0x3014, 12)];
29 | [set addCharactersInRange:NSMakeRange(0x3040, 96)]; // Hiragana
30 | [set addCharactersInRange:NSMakeRange(0x30A0, 96)]; // Katakana
31 | [set addCharactersInRange:NSMakeRange(0x3100, 48)]; // Bopomofo
32 | [set addCharactersInRange:NSMakeRange(0x3130, 96)]; // Hangul Compatibility Jamo
33 | [set addCharactersInRange:NSMakeRange(0x3190, 16)]; // Kanbun
34 | [set addCharactersInRange:NSMakeRange(0x31A0, 32)]; // Bopomofo Extended
35 | [set addCharactersInRange:NSMakeRange(0x31C0, 48)]; // CJK Strokes
36 | [set addCharactersInRange:NSMakeRange(0x31F0, 16)]; // Katakana Phonetic Extensions
37 | [set addCharactersInRange:NSMakeRange(0x3200, 256)]; // Enclosed CJK Letters and Months
38 | [set addCharactersInRange:NSMakeRange(0x3300, 256)]; // CJK Compatibility
39 | [set addCharactersInRange:NSMakeRange(0x3400, 2582)]; // CJK Unified Ideographs Extension A
40 | [set addCharactersInRange:NSMakeRange(0x4E00, 20941)]; // CJK Unified Ideographs
41 | [set addCharactersInRange:NSMakeRange(0xAC00, 11172)]; // Hangul Syllables
42 | [set addCharactersInRange:NSMakeRange(0xD7B0, 80)]; // Hangul Jamo Extended-B
43 | [set addCharactersInString:@""]; // U+F8FF (Private Use Area)
44 | [set addCharactersInRange:NSMakeRange(0xF900, 512)]; // CJK Compatibility Ideographs
45 | [set addCharactersInRange:NSMakeRange(0xFE10, 16)]; // Vertical Forms
46 | [set addCharactersInRange:NSMakeRange(0xFF00, 240)]; // Halfwidth and Fullwidth Forms
47 | [set addCharactersInRange:NSMakeRange(0x1F200, 256)]; // Enclosed Ideographic Supplement
48 | [set addCharactersInRange:NSMakeRange(0x1F300, 768)]; // Enclosed Ideographic Supplement
49 | [set addCharactersInRange:NSMakeRange(0x1F600, 80)]; // Emoticons (Emoji)
50 | [set addCharactersInRange:NSMakeRange(0x1F680, 128)]; // Transport and Map Symbols
51 |
52 | // See http://unicode-table.com/ for more information.
53 | });
54 | return set;
55 | }
56 |
57 | NSCharacterSet *YYTextVerticalFormRotateAndMoveCharacterSet() {
58 | static NSMutableCharacterSet *set;
59 | static dispatch_once_t onceToken;
60 | dispatch_once(&onceToken, ^{
61 | set = [NSMutableCharacterSet new];
62 | [set addCharactersInString:@",。、."];
63 | });
64 | return set;
65 | }
66 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYAsyncLayer.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYAsyncLayer.h
3 | // YYKit
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 YYAsyncLayerDisplayTask;
16 |
17 | NS_ASSUME_NONNULL_BEGIN
18 |
19 | /**
20 | The YYAsyncLayer 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 YYAsyncLayer : CALayer
26 | /// Whether the render code is executed in background. Default is YES.
27 | @property BOOL displaysAsynchronously;
28 | @end
29 |
30 |
31 | /**
32 | The YYAsyncLayer's delegate protocol. The delegate of the YYAsyncLayer (typically a UIView)
33 | must implements the method in this protocol.
34 | */
35 | @protocol YYAsyncLayerDelegate
36 | @required
37 | /// This method is called to return a new display task when the layer's contents need update.
38 | - (YYAsyncLayerDisplayTask *)newAsyncDisplayTask;
39 | @end
40 |
41 |
42 | /**
43 | A display task used by YYAsyncLayer to render the contents in background queue.
44 | */
45 | @interface YYAsyncLayerDisplayTask : 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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYDispatchQueuePool.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYDispatchQueueManager.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/7/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 | #ifndef YYDispatchQueuePool_h
15 | #define YYDispatchQueuePool_h
16 |
17 | NS_ASSUME_NONNULL_BEGIN
18 |
19 | /**
20 | A dispatch queue pool holds multiple serial queues.
21 | Use this class to control queue's thread count (instead of concurrent queue).
22 | */
23 | @interface YYDispatchQueuePool : NSObject
24 | - (instancetype)init UNAVAILABLE_ATTRIBUTE;
25 | + (instancetype)new UNAVAILABLE_ATTRIBUTE;
26 |
27 | /**
28 | Creates and returns a dispatch queue pool.
29 | @param name The name of the pool.
30 | @param queueCount Maxmium queue count, should in range (1, 32).
31 | @param qos Queue quality of service (QOS).
32 | @return A new pool, or nil if an error occurs.
33 | */
34 | - (instancetype)initWithName:(nullable NSString *)name queueCount:(NSUInteger)queueCount qos:(NSQualityOfService)qos;
35 |
36 | /// Pool's name.
37 | @property (nullable, nonatomic, readonly) NSString *name;
38 |
39 | /// Get a serial queue from pool.
40 | - (dispatch_queue_t)queue;
41 |
42 | + (instancetype)defaultPoolForQOS:(NSQualityOfService)qos;
43 |
44 | @end
45 |
46 | /// Get a serial queue from global queue pool with a specified qos.
47 | extern dispatch_queue_t YYDispatchQueueGetForQOS(NSQualityOfService qos);
48 |
49 | NS_ASSUME_NONNULL_END
50 |
51 | #endif
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYGestureRecognizer.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYGestureRecognizer.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/26.
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 | /// State of the gesture
17 | typedef NS_ENUM(NSUInteger, YYGestureRecognizerState) {
18 | YYGestureRecognizerStateBegan, ///< gesture start
19 | YYGestureRecognizerStateMoved, ///< gesture moved
20 | YYGestureRecognizerStateEnded, ///< gesture end
21 | YYGestureRecognizerStateCancelled, ///< gesture cancel
22 | };
23 |
24 | /**
25 | A simple UIGestureRecognizer subclass for receive touch events.
26 | */
27 | @interface YYGestureRecognizer : UIGestureRecognizer
28 |
29 | @property (nonatomic, readonly) CGPoint startPoint; ///< start point
30 | @property (nonatomic, readonly) CGPoint lastPoint; ///< last move point.
31 | @property (nonatomic, readonly) CGPoint currentPoint; ///< current move point.
32 |
33 | /// The action block invoked by every gesture event.
34 | @property (nullable, nonatomic, copy) void (^action)(YYGestureRecognizer *gesture, YYGestureRecognizerState state);
35 |
36 | /// Cancel the gesture for current touch.
37 | - (void)cancel;
38 |
39 | @end
40 |
41 | NS_ASSUME_NONNULL_END
42 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYGestureRecognizer.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYGestureRecognizer.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/26.
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 "YYGestureRecognizer.h"
13 | #import
14 |
15 | @implementation YYGestureRecognizer
16 |
17 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
18 | self.state = UIGestureRecognizerStateBegan;
19 | _startPoint = [(UITouch *)[touches anyObject] locationInView:self.view];
20 | _lastPoint = _currentPoint;
21 | _currentPoint = _startPoint;
22 | if (_action) _action(self, YYGestureRecognizerStateBegan);
23 | }
24 |
25 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
26 | UITouch *touch = (UITouch *)[touches anyObject];
27 | CGPoint currentPoint = [touch locationInView:self.view];
28 | self.state = UIGestureRecognizerStateChanged;
29 | _currentPoint = currentPoint;
30 | if (_action) _action(self, YYGestureRecognizerStateMoved);
31 | _lastPoint = _currentPoint;
32 | }
33 |
34 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
35 | self.state = UIGestureRecognizerStateEnded;
36 | if (_action) _action(self, YYGestureRecognizerStateEnded);
37 | }
38 |
39 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
40 | self.state = UIGestureRecognizerStateCancelled;
41 | if (_action) _action(self, YYGestureRecognizerStateCancelled);
42 | }
43 |
44 | - (void)reset {
45 | self.state = UIGestureRecognizerStatePossible;
46 | }
47 |
48 | - (void)cancel {
49 | if (self.state == UIGestureRecognizerStateBegan || self.state == UIGestureRecognizerStateChanged) {
50 | self.state = UIGestureRecognizerStateCancelled;
51 | if (_action) _action(self, YYGestureRecognizerStateCancelled);
52 | }
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYReachability.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYReachability.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/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 | #import
14 | #import
15 |
16 | NS_ASSUME_NONNULL_BEGIN
17 |
18 | typedef NS_ENUM(NSUInteger, YYReachabilityStatus) {
19 | YYReachabilityStatusNone = 0, ///< Not Reachable
20 | YYReachabilityStatusWWAN = 1, ///< Reachable via WWAN (2G/3G/4G)
21 | YYReachabilityStatusWiFi = 2, ///< Reachable via WiFi
22 | };
23 |
24 | typedef NS_ENUM(NSUInteger, YYReachabilityWWANStatus) {
25 | YYReachabilityWWANStatusNone = 0, ///< Not Reachable vis WWAN
26 | YYReachabilityWWANStatus2G = 2, ///< Reachable via 2G (GPRS/EDGE) 10~100Kbps
27 | YYReachabilityWWANStatus3G = 3, ///< Reachable via 3G (WCDMA/HSDPA/...) 1~10Mbps
28 | YYReachabilityWWANStatus4G = 4, ///< Reachable via 4G (eHRPD/LTE) 100Mbps
29 | };
30 |
31 |
32 | /**
33 | `YYReachability` can used to monitor the network status of an iOS device.
34 | */
35 | @interface YYReachability : NSObject
36 |
37 | @property (nonatomic, readonly) SCNetworkReachabilityFlags flags; ///< Current flags.
38 | @property (nonatomic, readonly) YYReachabilityStatus status; ///< Current status.
39 | @property (nonatomic, readonly) YYReachabilityWWANStatus wwanStatus NS_AVAILABLE_IOS(7_0); ///< Current WWAN status.
40 | @property (nonatomic, readonly, getter=isReachable) BOOL reachable; ///< Current reachable status.
41 |
42 | /// Notify block which will be called on main thread when network changed.
43 | @property (nullable, nonatomic, copy) void (^notifyBlock)(YYReachability *reachability);
44 |
45 | /// Create an object to check the reachability of the default route.
46 | + (instancetype)reachability;
47 |
48 | /// Create an object to check the reachability of the local WI-FI.
49 | + (instancetype)reachabilityForLocalWifi DEPRECATED_MSG_ATTRIBUTE("unnecessary and potentially harmful");
50 |
51 | /// Create an object to check the reachability of a given host name.
52 | + (nullable instancetype)reachabilityWithHostname:(NSString *)hostname;
53 |
54 | /// Create an object to check the reachability of a given IP address
55 | /// @param hostAddress You may pass `struct sockaddr_in` for IPv4 address or `struct sockaddr_in6` for IPv6 address.
56 | + (nullable instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
57 |
58 | @end
59 |
60 | NS_ASSUME_NONNULL_END
61 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYSentinel.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYSentinel.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/4/13.
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 | YYSentinel is a thread safe incrementing counter.
18 | It may be used in some multi-threaded situation.
19 | */
20 | @interface YYSentinel : NSObject
21 |
22 | /// Returns the current value of the counter.
23 | @property (readonly) int32_t value;
24 |
25 | /// Increase the value atomically.
26 | /// @return The new value.
27 | - (int32_t)increase;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYSentinel.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYSentinel.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/4/13.
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 "YYSentinel.h"
13 | #import
14 |
15 | @implementation YYSentinel {
16 | int32_t _value;
17 | }
18 |
19 | - (int32_t)value {
20 | return _value;
21 | }
22 |
23 | - (int32_t)increase {
24 | #pragma clang diagnostic push
25 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
26 | return OSAtomicIncrement32(&_value);
27 | #pragma clang diagnostic pop
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYThreadSafeArray.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYThreadSafeArray.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/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 | /**
15 | A simple implementation of thread safe mutable array.
16 |
17 | @discussion Generally, access performance is lower than NSMutableArray,
18 | but higher than using @synchronized, NSLock, or pthread_mutex_t.
19 |
20 | @discussion It's also compatible with the custom methods in `NSArray(YYAdd)`
21 | and `NSMutableArray(YYAdd)`
22 |
23 | @warning Fast enumerate(for..in) and enumerator is not thread safe,
24 | use enumerate using block instead. When enumerate or sort with block/callback,
25 | do *NOT* send message to the array inside the block/callback.
26 | */
27 | @interface YYThreadSafeArray : NSMutableArray
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYThreadSafeDictionary.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYThreadSafeDictionary.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 14/10/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 | /**
15 | A simple implementation of thread safe mutable dictionary.
16 |
17 | @discussion Generally, access performance is lower than NSMutableDictionary,
18 | but higher than using @synchronized, NSLock, or pthread_mutex_t.
19 |
20 | @discussion It's also compatible with the custom methods in `NSDictionary(YYAdd)`
21 | and `NSMutableDictionary(YYAdd)`
22 |
23 | @warning Fast enumerate(for...in) and enumerator is not thread safe,
24 | use enumerate using block instead. When enumerate or sort with block/callback,
25 | do *NOT* send message to the dictionary inside the block/callback.
26 | */
27 | @interface YYThreadSafeDictionary : NSMutableDictionary
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYTimer.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTimer.h
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/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 | YYTimer is a thread-safe timer based on GCD. It has similar API with `NSTimer`.
18 | YYTimer object differ from NSTimer in a few ways:
19 |
20 | * It use GCD to produce timer tick, and won't be affected by runLoop.
21 | * It make a weak reference to the target, so it can avoid retain cycles.
22 | * It always fire on main thread.
23 |
24 | */
25 | @interface YYTimer : NSObject
26 |
27 | + (YYTimer *)timerWithTimeInterval:(NSTimeInterval)interval
28 | target:(id)target
29 | selector:(SEL)selector
30 | repeats:(BOOL)repeats;
31 |
32 | - (instancetype)initWithFireTime:(NSTimeInterval)start
33 | interval:(NSTimeInterval)interval
34 | target:(id)target
35 | selector:(SEL)selector
36 | repeats:(BOOL)repeats NS_DESIGNATED_INITIALIZER;
37 |
38 | @property (readonly) BOOL repeats;
39 | @property (readonly) NSTimeInterval timeInterval;
40 | @property (readonly, getter=isValid) BOOL valid;
41 |
42 | - (void)invalidate;
43 |
44 | - (void)fire;
45 |
46 | @end
47 |
48 | NS_ASSUME_NONNULL_END
49 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYTimer.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTimer.m
3 | // YYKit
4 | //
5 | // Created by ibireme on 15/2/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 "YYTimer.h"
13 | #import
14 |
15 | #define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
16 | __VA_ARGS__; \
17 | dispatch_semaphore_signal(_lock);
18 |
19 |
20 | @implementation YYTimer {
21 | BOOL _valid;
22 | NSTimeInterval _timeInterval;
23 | BOOL _repeats;
24 | __weak id _target;
25 | SEL _selector;
26 | dispatch_source_t _source;
27 | dispatch_semaphore_t _lock;
28 | }
29 |
30 | + (YYTimer *)timerWithTimeInterval:(NSTimeInterval)interval
31 | target:(id)target
32 | selector:(SEL)selector
33 | repeats:(BOOL)repeats {
34 | return [[self alloc] initWithFireTime:interval interval:interval target:target selector:selector repeats:repeats];
35 | }
36 |
37 | - (instancetype)init {
38 | @throw [NSException exceptionWithName:@"YYTimer init error" reason:@"Use the designated initializer to init." userInfo:nil];
39 | return [self initWithFireTime:0 interval:0 target:self selector:@selector(invalidate) repeats:NO];
40 | }
41 |
42 | - (instancetype)initWithFireTime:(NSTimeInterval)start
43 | interval:(NSTimeInterval)interval
44 | target:(id)target
45 | selector:(SEL)selector
46 | repeats:(BOOL)repeats {
47 | self = [super init];
48 | _repeats = repeats;
49 | _timeInterval = interval;
50 | _valid = YES;
51 | _target = target;
52 | _selector = selector;
53 |
54 | __weak typeof(self) _self = self;
55 | _lock = dispatch_semaphore_create(1);
56 | _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
57 | dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);
58 | dispatch_source_set_event_handler(_source, ^{[_self fire];});
59 | dispatch_resume(_source);
60 | return self;
61 | }
62 |
63 | - (void)invalidate {
64 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
65 | if (_valid) {
66 | dispatch_source_cancel(_source);
67 | _source = NULL;
68 | _target = nil;
69 | _valid = NO;
70 | }
71 | dispatch_semaphore_signal(_lock);
72 | }
73 |
74 | - (void)fire {
75 | #pragma clang diagnostic push
76 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
77 | dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
78 | id target = _target;
79 | if (!_repeats || !target) {
80 | dispatch_semaphore_signal(_lock);
81 | [self invalidate];
82 | } else {
83 | dispatch_semaphore_signal(_lock);
84 | [target performSelector:_selector withObject:self];
85 | }
86 | #pragma clang diagnostic pop
87 | }
88 |
89 | - (BOOL)repeats {
90 | LOCK(BOOL repeat = _repeats); return repeat;
91 | }
92 |
93 | - (NSTimeInterval)timeInterval {
94 | LOCK(NSTimeInterval t = _timeInterval) return t;
95 | }
96 |
97 | - (BOOL)isValid {
98 | LOCK(BOOL valid = _valid) return valid;
99 | }
100 |
101 | - (void)dealloc {
102 | [self invalidate];
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYTransaction.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYTransaction.h
3 | // YYKit
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 | YYTransaction let you perform a selector once before current runloop sleep.
18 | */
19 | @interface YYTransaction : 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 | + (YYTransaction *)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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYTransaction.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYTransaction.m
3 | // YYKit
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 "YYTransaction.h"
13 |
14 |
15 | @interface YYTransaction()
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:^(YYTransaction *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 YYTransactionSetup() {
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 YYTransaction
53 |
54 | + (YYTransaction *)transactionWithTarget:(id)target selector:(SEL)selector{
55 | if (!target || !selector) return nil;
56 | YYTransaction *t = [YYTransaction new];
57 | t.target = target;
58 | t.selector = selector;
59 | return t;
60 | }
61 |
62 | - (void)commit {
63 | if (!_target || !_selector) return;
64 | YYTransactionSetup();
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 | YYTransaction *other = object;
78 | return other.selector == _selector && other.target == _target;
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYWeakProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // YYWeakProxy.h
3 | // YYKit
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 | YYWeakProxy *proxy = [YYWeakProxy 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 YYWeakProxy : 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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/YYKit/Utility/YYWeakProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // YYWeakProxy.m
3 | // YYKit
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 "YYWeakProxy.h"
13 |
14 |
15 | @implementation YYWeakProxy
16 |
17 | - (instancetype)initWithTarget:(id)target {
18 | _target = target;
19 | return self;
20 | }
21 |
22 | + (instancetype)proxyWithTarget:(id)target {
23 | return [[YYWeakProxy 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 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/ar.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Label"; ObjectID = "56U-0r-1bF"; */
3 | "56U-0r-1bF.text" = "Label";
4 |
5 | /* Class = "UILabel"; text = "Xib布局,炫彩流动,超出范围省略显示"; ObjectID = "5IF-wz-Gkv"; */
6 | "5IF-wz-Gkv.text" = "Xib布局,炫彩流动,超出范围省略显示";
7 |
8 | /* Class = "UILabel"; text = "Xib布局,炫彩流动,超出范围自动滚动"; ObjectID = "Lgz-a1-oJn"; */
9 | "Lgz-a1-oJn.text" = "Xib布局,炫彩流动,超出范围自动滚动";
10 |
11 | /* Class = "UILabel"; text = "Label"; ObjectID = "XDX-x9-Ydi"; */
12 | "XDX-x9-Ydi.text" = "Label";
13 |
--------------------------------------------------------------------------------
/JKRShimmeringLabel/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // JKRShimmeringLabel
4 | //
5 | // Created by 胡怀刈 on 2023/4/11.
6 | //
7 |
8 | #import
9 | #import "AppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | NSString * appDelegateClassName;
13 | @autoreleasepool {
14 | // Setup code that might create autoreleased objects goes here.
15 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
16 | }
17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
18 | }
19 |
--------------------------------------------------------------------------------
/LTR.GIF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Joker-388/JKRShimmeringLabel/d613b3d2ce70c5bebe70017a192cbfe19a20742f/LTR.GIF
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JKRShimmeringLabel
2 |
3 | ## 特征
4 |
5 | [](https://www.jianshu.com/p/d81725130936?v=1681198297299)
6 |
7 |
8 | [](https://www.jianshu.com/p/d81725130936?v=1681198297299)
9 |
10 |
11 | 1. 支持炫彩字
12 | 2. 支持炫彩流动字
13 | 3. 支持超出显示范围自动滚动文本
14 | 4. 支持RTL下的对称显示和滚动
15 | 5. 支持Frame布局
16 | 6. 支持Xib和StoryBoard内使用
17 | 7. 支持AutoLayout布局
18 |
19 | ## 使用
20 |
21 | 和原生UILabel一样用,只需要设置mask属性(一张彩色的图片遮罩)即可。
22 |
23 | ### 原有项目的UILabel替换
24 |
25 | 因为JKRAutoScrollLabel和JKRShimmeringLabel本身就是继承UILabel,可以直接把原有项目的UILabel类,替换成JKRAutoScrollLabel或JKRShimmeringLabel即可。
26 |
27 | ### JKRAutoScrollLabel
28 |
29 | 超出范围自动滚动的Lable,需要设置attributedText,不能设置text。要同时支持流动彩字,设置mask即可。不需要彩色可以不设置mask,只有自动滚动的特性。
30 |
31 | ```
32 | // Frame布局,字体支持炫彩闪动,同时超出显示范围自动滚动
33 | NSMutableAttributedString *textForFrameAttr = [[NSMutableAttributedString alloc] initWithString:@"我是滚动测试文本Frame布局,看看我的效果" attributes:@{NSForegroundColorAttributeName: UIColorHex(FFFFFF), NSFontAttributeName: [UIFont systemFontOfSize:19 weight:UIFontWeightBold]}];
34 | self.autoScrollLabelForFrame = [[JKRAutoScrollLabel alloc] initWithFrame:CGRectMake(isRTL ? kScreenWidth - 10 - 300 : 10, CGRectGetMaxY(title0.frame) + 10, 300, 24)];
35 | // 滚动文本需要设置 attributedText 才能生效
36 | self.autoScrollLabelForFrame.attributedText = textForFrameAttr;
37 | // 设置文字颜色的mask图片遮罩,如果不需要字体炫彩,不设置即可
38 | self.autoScrollLabelForFrame.mask = [self maskImage];
39 | [self.view addSubview:self.autoScrollLabelForFrame];
40 | ```
41 |
42 | ### JKRShimmeringLabel
43 |
44 | 支持流动彩字,设置mask即可,如果还需要超出范围自动滚动,需要使用JKRAutoScrollLabel。
45 |
46 | ```
47 | // Frame布局,字体支持炫彩闪动
48 | self.shimmerLabelForFrame = [[JKRShimmeringLabel alloc] initWithFrame:CGRectMake(isRTL ? kScreenWidth - 10 - 300 : 10, CGRectGetMaxY(title1.frame) + 10, 300, 24)];
49 | self.shimmerLabelForFrame.text = @"我是彩色不滚动文本Frame布局,看看我的效果";
50 | self.shimmerLabelForFrame.font = [UIFont systemFontOfSize:19];
51 | // 设置文字颜色的mask图片遮罩,如果不需要字体炫彩,不设置即可
52 | self.shimmerLabelForFrame.mask = [self maskImage];
53 | [self.view addSubview:self.shimmerLabelForFrame];
54 | ```
55 |
56 | ### Xib使用
57 |
58 | 控件支持xib和autolayout的场景,和UILabel一样设置约束即可,自动滚动和彩色动画,会自动支持。只需要正常配置约束,然后设置mask彩色遮罩即可。
59 |
60 | 同时,因为JKRShimmeringLabel和JKRAutoScrollLabel本身就是继承UILabel的,所以UILabel在Xib中的文本自动填充宽度、约束优先级等等特性,也都可以正常使用。
--------------------------------------------------------------------------------
/RTL.GIF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Joker-388/JKRShimmeringLabel/d613b3d2ce70c5bebe70017a192cbfe19a20742f/RTL.GIF
--------------------------------------------------------------------------------