├── MTStatusBarOverlay_Prefix.pch ├── LICENSE ├── Readme.mdown ├── MTStatusBarOverlay.h ├── MTStatusBarOverlay.xcodeproj └── project.pbxproj └── MTStatusBarOverlay.m /MTStatusBarOverlay_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2010, Matthias Tretter 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Readme.mdown: -------------------------------------------------------------------------------- 1 | Read Me 2 | ===================== 3 | 4 | This class provides a custom iOS status bar overlay window known from Apps like Reeder. 5 | 6 | ![Reeder Status Bar on Flickr](http://farm5.static.flickr.com/4074/4754736484_8fc1ef9639_o.png "Reeder Status Bar on Flickr") 7 | 8 | It currently supports touch-handling to shrink and expand and also black and gray status bar styles. 9 | 10 | You can use the custom status bar like this: 11 | 12 | MTStatusBarOverlay overlay = [MTStatusBarOverlay sharedInstance]; 13 | overlay.animation = MTStatusBarOverlayAnimationShrink; 14 | [overlay showWithMessage:@"Following @myell0w on Twitter..."]; 15 | // ... 16 | [overlay showWithMessage:@"Following myell0w on Github..."]; 17 | // ... 18 | [overlay finishWithMessage:@"Following was a good idea!" duration:2.0]; 19 | 20 | if you call showWithMessage when the custom status bar is already visible, the new text is set animated. 21 | 22 | Known Limitations: 23 | 24 | * During animation of new text, the custom status bar can't be shrinked. 25 | * Device-Rotation currently only works on iPhone, not iPad 26 | * Only MTStatusBarOverlayAnimationShrink is currently implemented -------------------------------------------------------------------------------- /MTStatusBarOverlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // MTStatusBarOverlay.m 3 | // 4 | // Created by Matthias Tretter on 27.09.10. 5 | // Copyright (c) 2009-2010 Matthias Tretter, @myell0w. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 13 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | // 15 | // Credits go to: 16 | // ------------------------------- 17 | // http://stackoverflow.com/questions/2833724/adding-view-on-statusbar-in-iphone 18 | // http://cocoabyss.com/2010/ios-custom-status-bar/ 19 | // @reederapp 20 | // ------------------------------- 21 | 22 | #import 23 | 24 | // Animation that happens, when the user touches the status bar overlay 25 | typedef enum MTStatusBarOverlayAnimation { 26 | // nothing happens 27 | MTStatusBarOverlayAnimationNone, 28 | // the status bar shrinks to the right side and only shows the activity indicator 29 | MTStatusBarOverlayAnimationShrink, 30 | // the status bar falls down and displays more information 31 | MTStatusBarOverlayAnimationFallDown 32 | } MTStatusBarOverlayAnimation; 33 | 34 | 35 | // This class provides an overlay over the iOS Status Bar that can display information 36 | // and perform an animation when you touch it 37 | @interface MTStatusBarOverlay : UIWindow { 38 | // holds all subviews, is touchable to change size of Status Bar 39 | UIControl *backgroundView_; 40 | 41 | // background of Status Bar Black or gray 42 | UIImageView *statusBarBackgroundImageView_; 43 | // for displaying Text information 44 | UILabel *statusLabel1_; 45 | UILabel *statusLabel2_; 46 | UILabel *hiddenStatusLabel_; 47 | // for displaying activity indication 48 | UIActivityIndicatorView *activityIndicator_; 49 | UILabel *finishedLabel_; 50 | 51 | // Image of gray Status Bar 52 | UIImage *grayStatusBarImage_; 53 | UIImage *grayStatusBarImageSmall_; 54 | 55 | // Animation-Type 56 | MTStatusBarOverlayAnimation animation_; 57 | // Small size of Status Bar 58 | CGRect smallFrame_; 59 | // temporary variable used for rotation 60 | CGRect oldBackgroundViewFrame_; 61 | 62 | // Queue stuff 63 | NSMutableArray *queuedMessages; 64 | NSTimer *queueTimer; 65 | 66 | BOOL hideInProgress_; 67 | } 68 | 69 | //=========================================================== 70 | #pragma mark - 71 | #pragma mark Properties 72 | //=========================================================== 73 | @property (nonatomic, retain) UIControl *backgroundView; 74 | @property (nonatomic, assign) CGRect smallFrame; 75 | @property (nonatomic, assign) MTStatusBarOverlayAnimation animation; 76 | @property (nonatomic, retain) UILabel *finishedLabel; 77 | 78 | //=========================================================== 79 | #pragma mark - 80 | #pragma mark Class Methods 81 | //=========================================================== 82 | 83 | // convenience-constructor 84 | + (MTStatusBarOverlay *)sharedInstance; 85 | 86 | //=========================================================== 87 | #pragma mark - 88 | #pragma mark Instance Methods 89 | //=========================================================== 90 | 91 | // for customizing appearance, automatically disabled userInteractionEnabled on view 92 | - (void)addSubviewToBackgroundView:(UIView *)view; 93 | 94 | // shows the status bar overlay 95 | - (void)show; 96 | // hides the status bar overlay 97 | - (void)hide; 98 | // convenience-method, set Message and show 99 | - (void)showWithMessage:(NSString *)message; 100 | // shows a checkmark instead of the activity indicator and hides the status bar after the specified duration 101 | - (void)finishWithMessage:(NSString *)message duration:(NSTimeInterval)duration; 102 | // enables you to change the display Message on the status bar animated or w/o animation 103 | - (void)setMessage:(NSString *)message animated:(BOOL)animated; 104 | // shows the message for a specified interval before displaying the next queued item, or hiding the overlay if none are left 105 | - (void)queueMessage:(NSString *)message forInterval:(NSTimeInterval)interval animated:(BOOL)animated; 106 | - (void)queueFinalMessage:(NSString *)message forInterval:(NSTimeInterval)interval animated:(BOOL)animated; 107 | // shows if finishWithMessage was currently called 108 | - (BOOL)isHideInProgress; 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /MTStatusBarOverlay.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 39847F2412B2CE5E006F8A53 /* MTStatusBarOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 39847F2212B2CE5E006F8A53 /* MTStatusBarOverlay.h */; }; 11 | 39847F2512B2CE5E006F8A53 /* MTStatusBarOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 39847F2312B2CE5E006F8A53 /* MTStatusBarOverlay.m */; }; 12 | AA747D9F0F9514B9006C5449 /* MTStatusBarOverlay_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* MTStatusBarOverlay_Prefix.pch */; }; 13 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | 39847F2212B2CE5E006F8A53 /* MTStatusBarOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTStatusBarOverlay.h; sourceTree = ""; }; 18 | 39847F2312B2CE5E006F8A53 /* MTStatusBarOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTStatusBarOverlay.m; sourceTree = ""; }; 19 | AA747D9E0F9514B9006C5449 /* MTStatusBarOverlay_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTStatusBarOverlay_Prefix.pch; sourceTree = SOURCE_ROOT; }; 20 | AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 21 | D2AAC07E0554694100DB518D /* libMTStatusBarOverlay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMTStatusBarOverlay.a; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | /* End PBXFileReference section */ 23 | 24 | /* Begin PBXFrameworksBuildPhase section */ 25 | D2AAC07C0554694100DB518D /* Frameworks */ = { 26 | isa = PBXFrameworksBuildPhase; 27 | buildActionMask = 2147483647; 28 | files = ( 29 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, 30 | ); 31 | runOnlyForDeploymentPostprocessing = 0; 32 | }; 33 | /* End PBXFrameworksBuildPhase section */ 34 | 35 | /* Begin PBXGroup section */ 36 | 034768DFFF38A50411DB9C8B /* Products */ = { 37 | isa = PBXGroup; 38 | children = ( 39 | D2AAC07E0554694100DB518D /* libMTStatusBarOverlay.a */, 40 | ); 41 | name = Products; 42 | sourceTree = ""; 43 | }; 44 | 0867D691FE84028FC02AAC07 /* MTStatusBarOverlay */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 08FB77AEFE84172EC02AAC07 /* Classes */, 48 | 32C88DFF0371C24200C91783 /* Other Sources */, 49 | 0867D69AFE84028FC02AAC07 /* Frameworks */, 50 | 034768DFFF38A50411DB9C8B /* Products */, 51 | ); 52 | name = MTStatusBarOverlay; 53 | sourceTree = ""; 54 | }; 55 | 0867D69AFE84028FC02AAC07 /* Frameworks */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | AACBBE490F95108600F1A2B1 /* Foundation.framework */, 59 | ); 60 | name = Frameworks; 61 | sourceTree = ""; 62 | }; 63 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 39847F2212B2CE5E006F8A53 /* MTStatusBarOverlay.h */, 67 | 39847F2312B2CE5E006F8A53 /* MTStatusBarOverlay.m */, 68 | ); 69 | name = Classes; 70 | sourceTree = ""; 71 | }; 72 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | AA747D9E0F9514B9006C5449 /* MTStatusBarOverlay_Prefix.pch */, 76 | ); 77 | name = "Other Sources"; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXHeadersBuildPhase section */ 83 | D2AAC07A0554694100DB518D /* Headers */ = { 84 | isa = PBXHeadersBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | AA747D9F0F9514B9006C5449 /* MTStatusBarOverlay_Prefix.pch in Headers */, 88 | 39847F2412B2CE5E006F8A53 /* MTStatusBarOverlay.h in Headers */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXHeadersBuildPhase section */ 93 | 94 | /* Begin PBXNativeTarget section */ 95 | D2AAC07D0554694100DB518D /* MTStatusBarOverlay */ = { 96 | isa = PBXNativeTarget; 97 | buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "MTStatusBarOverlay" */; 98 | buildPhases = ( 99 | D2AAC07A0554694100DB518D /* Headers */, 100 | D2AAC07B0554694100DB518D /* Sources */, 101 | D2AAC07C0554694100DB518D /* Frameworks */, 102 | ); 103 | buildRules = ( 104 | ); 105 | dependencies = ( 106 | ); 107 | name = MTStatusBarOverlay; 108 | productName = MTStatusBarOverlay; 109 | productReference = D2AAC07E0554694100DB518D /* libMTStatusBarOverlay.a */; 110 | productType = "com.apple.product-type.library.static"; 111 | }; 112 | /* End PBXNativeTarget section */ 113 | 114 | /* Begin PBXProject section */ 115 | 0867D690FE84028FC02AAC07 /* Project object */ = { 116 | isa = PBXProject; 117 | buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "MTStatusBarOverlay" */; 118 | compatibilityVersion = "Xcode 3.1"; 119 | developmentRegion = English; 120 | hasScannedForEncodings = 1; 121 | knownRegions = ( 122 | English, 123 | Japanese, 124 | French, 125 | German, 126 | ); 127 | mainGroup = 0867D691FE84028FC02AAC07 /* MTStatusBarOverlay */; 128 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 129 | projectDirPath = ""; 130 | projectRoot = ""; 131 | targets = ( 132 | D2AAC07D0554694100DB518D /* MTStatusBarOverlay */, 133 | ); 134 | }; 135 | /* End PBXProject section */ 136 | 137 | /* Begin PBXSourcesBuildPhase section */ 138 | D2AAC07B0554694100DB518D /* Sources */ = { 139 | isa = PBXSourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | 39847F2512B2CE5E006F8A53 /* MTStatusBarOverlay.m in Sources */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXSourcesBuildPhase section */ 147 | 148 | /* Begin XCBuildConfiguration section */ 149 | 1DEB921F08733DC00010E9CD /* Debug */ = { 150 | isa = XCBuildConfiguration; 151 | buildSettings = { 152 | ALWAYS_SEARCH_USER_PATHS = NO; 153 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 154 | COPY_PHASE_STRIP = NO; 155 | DSTROOT = /tmp/MTStatusBarOverlay.dst; 156 | GCC_DYNAMIC_NO_PIC = NO; 157 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 158 | GCC_MODEL_TUNING = G5; 159 | GCC_OPTIMIZATION_LEVEL = 0; 160 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 161 | GCC_PREFIX_HEADER = MTStatusBarOverlay_Prefix.pch; 162 | INSTALL_PATH = /usr/local/lib; 163 | PRODUCT_NAME = MTStatusBarOverlay; 164 | }; 165 | name = Debug; 166 | }; 167 | 1DEB922008733DC00010E9CD /* Release */ = { 168 | isa = XCBuildConfiguration; 169 | buildSettings = { 170 | ALWAYS_SEARCH_USER_PATHS = NO; 171 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 172 | DSTROOT = /tmp/MTStatusBarOverlay.dst; 173 | GCC_MODEL_TUNING = G5; 174 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 175 | GCC_PREFIX_HEADER = MTStatusBarOverlay_Prefix.pch; 176 | INSTALL_PATH = /usr/local/lib; 177 | PRODUCT_NAME = MTStatusBarOverlay; 178 | }; 179 | name = Release; 180 | }; 181 | 1DEB922308733DC00010E9CD /* Debug */ = { 182 | isa = XCBuildConfiguration; 183 | buildSettings = { 184 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 185 | GCC_C_LANGUAGE_STANDARD = c99; 186 | GCC_OPTIMIZATION_LEVEL = 0; 187 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 188 | GCC_WARN_UNUSED_VARIABLE = YES; 189 | OTHER_LDFLAGS = "-ObjC"; 190 | PREBINDING = NO; 191 | SDKROOT = iphoneos; 192 | }; 193 | name = Debug; 194 | }; 195 | 1DEB922408733DC00010E9CD /* Release */ = { 196 | isa = XCBuildConfiguration; 197 | buildSettings = { 198 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 199 | GCC_C_LANGUAGE_STANDARD = c99; 200 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 201 | GCC_WARN_UNUSED_VARIABLE = YES; 202 | OTHER_LDFLAGS = "-ObjC"; 203 | PREBINDING = NO; 204 | SDKROOT = iphoneos; 205 | }; 206 | name = Release; 207 | }; 208 | /* End XCBuildConfiguration section */ 209 | 210 | /* Begin XCConfigurationList section */ 211 | 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "MTStatusBarOverlay" */ = { 212 | isa = XCConfigurationList; 213 | buildConfigurations = ( 214 | 1DEB921F08733DC00010E9CD /* Debug */, 215 | 1DEB922008733DC00010E9CD /* Release */, 216 | ); 217 | defaultConfigurationIsVisible = 0; 218 | defaultConfigurationName = Release; 219 | }; 220 | 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "MTStatusBarOverlay" */ = { 221 | isa = XCConfigurationList; 222 | buildConfigurations = ( 223 | 1DEB922308733DC00010E9CD /* Debug */, 224 | 1DEB922408733DC00010E9CD /* Release */, 225 | ); 226 | defaultConfigurationIsVisible = 0; 227 | defaultConfigurationName = Release; 228 | }; 229 | /* End XCConfigurationList section */ 230 | }; 231 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 232 | } 233 | -------------------------------------------------------------------------------- /MTStatusBarOverlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // MTStatusBarOverlay.m 3 | // 4 | // Created by Matthias Tretter on 27.09.10. 5 | // Copyright (c) 2009-2010 Matthias Tretter, @myell0w. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 13 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | // 15 | // Credits go to: 16 | // ------------------------------- 17 | // http://stackoverflow.com/questions/2833724/adding-view-on-statusbar-in-iphone 18 | // http://cocoabyss.com/2010/ios-custom-status-bar/ 19 | // @reederapp 20 | // ------------------------------- 21 | 22 | #import "MTStatusBarOverlay.h" 23 | 24 | //=========================================================== 25 | #pragma mark - 26 | #pragma mark Customize Section 27 | //=========================================================== 28 | 29 | // Text color for UIStatusBarStyleDefault 30 | #define kStatusBarStyleDefaultTextColor [UIColor blackColor] 31 | // Activity Indicator Style for UIStatusBarStyleDefault 32 | #define kStatusBarStyleDefaultActivityIndicatorViewStyle UIActivityIndicatorViewStyleGray 33 | // Text color for UIStatusBarStyleBlackOpaque 34 | #define kStatusBarStyleBlackTextColor [UIColor colorWithRed:0.749 green:0.749 blue:0.749 alpha:1.0] 35 | // Activity Indicator Style for UIStatusBarStyleBlackOpaque 36 | #define kStatusBarStyleBlackActivityIndicatorViewStyle UIActivityIndicatorViewStyleWhite 37 | 38 | // duration of the animation to show next status message in seconds 39 | #define kNextStatusAnimationDuration 0.8 40 | // x-offset of the child-views of the background when status bar is in small mode 41 | #define kSmallXOffset 50 42 | // default-width of the small-mode 43 | #define kWidthSmall 80 44 | 45 | //=========================================================== 46 | #pragma mark - 47 | #pragma mark Defines 48 | //=========================================================== 49 | 50 | #define IsIPad UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad 51 | #define kStatusBarHeight 20 52 | #define kScreenWidth [UIScreen mainScreen].bounds.size.width 53 | #define kScreenHeight [UIScreen mainScreen].bounds.size.height 54 | 55 | 56 | 57 | //=========================================================== 58 | #pragma mark - 59 | #pragma mark Encoded Images 60 | //=========================================================== 61 | 62 | unsigned char statusBarBackgroundGrey_png[] = { 63 | 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 64 | 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 65 | 0x08, 0x02, 0x00, 0x00, 0x00, 0xe4, 0xc2, 0x41, 0x1e, 0x00, 0x00, 0x00, 66 | 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 67 | 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 68 | 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00, 69 | 0x00, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xbc, 0xd2, 0xcd, 0x0a, 70 | 0x40, 0x40, 0x14, 0x05, 0xe0, 0x99, 0xf2, 0x10, 0x92, 0xbc, 0x1f, 0xe1, 71 | 0x61, 0xa4, 0xec, 0xcc, 0x53, 0x59, 0x58, 0x28, 0x69, 0xf2, 0xd3, 0x94, 72 | 0x88, 0xac, 0xe6, 0xde, 0xbc, 0x82, 0x73, 0x17, 0xce, 0xfe, 0xeb, 0x9c, 73 | 0x6e, 0x57, 0x67, 0x79, 0x91, 0xe6, 0x65, 0x9c, 0x24, 0xea, 0x43, 0xec, 74 | 0x34, 0x35, 0x75, 0xa5, 0xbb, 0x7e, 0x08, 0xe3, 0x48, 0x7d, 0xce, 0x6a, 75 | 0x67, 0xed, 0xae, 0x47, 0x81, 0xd1, 0xdb, 0x71, 0xc3, 0x66, 0xd9, 0x4f, 76 | 0xd8, 0x58, 0xb7, 0xc3, 0x66, 0x5c, 0x1d, 0x6a, 0x02, 0x26, 0x82, 0x0d, 77 | 0x79, 0xdc, 0x78, 0x41, 0x8f, 0x67, 0x81, 0x11, 0x6c, 0x63, 0x81, 0x21, 78 | 0xf2, 0x78, 0x0f, 0xff, 0x73, 0x37, 0x62, 0x16, 0xfc, 0x81, 0xc0, 0x08, 79 | 0x7a, 0x4c, 0x6b, 0x50, 0xf3, 0x0a, 0x30, 0x00, 0x1d, 0xed, 0x40, 0x55, 80 | 0xe5, 0xd4, 0x12, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 81 | 0xae, 0x42, 0x60, 0x82 82 | }; 83 | unsigned int statusBarBackgroundGrey_png_len = 220; 84 | 85 | unsigned char statusBarBackgroundGreySmall_png[] = { 86 | 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 87 | 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 88 | 0x08, 0x02, 0x00, 0x00, 0x00, 0xe4, 0xc2, 0x41, 0x1e, 0x00, 0x00, 0x00, 89 | 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 90 | 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 91 | 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00, 92 | 0x03, 0x22, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 93 | 0x6d, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 95 | 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x22, 0xef, 0xbb, 0xbf, 96 | 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70, 97 | 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54, 98 | 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x22, 0x3f, 0x3e, 0x20, 0x3c, 0x78, 99 | 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 100 | 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 101 | 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20, 0x78, 0x3a, 102 | 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x41, 0x64, 0x6f, 0x62, 0x65, 103 | 0x20, 0x58, 0x4d, 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 104 | 0x30, 0x2d, 0x63, 0x30, 0x36, 0x30, 0x20, 0x36, 0x31, 0x2e, 0x31, 0x33, 105 | 0x34, 0x37, 0x37, 0x37, 0x2c, 0x20, 0x32, 0x30, 0x31, 0x30, 0x2f, 0x30, 106 | 0x32, 0x2f, 0x31, 0x32, 0x2d, 0x31, 0x37, 0x3a, 0x33, 0x32, 0x3a, 0x30, 107 | 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3e, 0x20, 108 | 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 109 | 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 110 | 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 111 | 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 112 | 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 113 | 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 114 | 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 115 | 0x64, 0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x20, 116 | 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x6d, 0x70, 0x3d, 0x22, 0x68, 117 | 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 118 | 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 119 | 0x2e, 0x30, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 120 | 0x6d, 0x70, 0x4d, 0x4d, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 121 | 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 122 | 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x6d, 0x6d, 123 | 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x73, 0x74, 0x52, 124 | 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 125 | 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 126 | 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x73, 0x54, 0x79, 0x70, 127 | 0x65, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 128 | 0x66, 0x23, 0x22, 0x20, 0x78, 0x6d, 0x70, 0x3a, 0x43, 0x72, 0x65, 0x61, 129 | 0x74, 0x6f, 0x72, 0x54, 0x6f, 0x6f, 0x6c, 0x3d, 0x22, 0x41, 0x64, 0x6f, 130 | 0x62, 0x65, 0x20, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 131 | 0x20, 0x43, 0x53, 0x35, 0x20, 0x4d, 0x61, 0x63, 0x69, 0x6e, 0x74, 0x6f, 132 | 0x73, 0x68, 0x22, 0x20, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x49, 0x6e, 133 | 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 134 | 0x70, 0x2e, 0x69, 0x69, 0x64, 0x3a, 0x32, 0x31, 0x44, 0x36, 0x33, 0x46, 135 | 0x43, 0x37, 0x46, 0x43, 0x44, 0x46, 0x31, 0x31, 0x44, 0x46, 0x38, 0x42, 136 | 0x31, 0x34, 0x44, 0x35, 0x30, 0x33, 0x33, 0x33, 0x38, 0x39, 0x45, 0x43, 137 | 0x42, 0x45, 0x22, 0x20, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 138 | 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 139 | 0x70, 0x2e, 0x64, 0x69, 0x64, 0x3a, 0x32, 0x31, 0x44, 0x36, 0x33, 0x46, 140 | 0x43, 0x38, 0x46, 0x43, 0x44, 0x46, 0x31, 0x31, 0x44, 0x46, 0x38, 0x42, 141 | 0x31, 0x34, 0x44, 0x35, 0x30, 0x33, 0x33, 0x33, 0x38, 0x39, 0x45, 0x43, 142 | 0x42, 0x45, 0x22, 0x3e, 0x20, 0x3c, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 143 | 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x20, 144 | 0x73, 0x74, 0x52, 0x65, 0x66, 0x3a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 145 | 0x63, 0x65, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x69, 0x69, 146 | 0x64, 0x3a, 0x32, 0x31, 0x44, 0x36, 0x33, 0x46, 0x43, 0x35, 0x46, 0x43, 147 | 0x44, 0x46, 0x31, 0x31, 0x44, 0x46, 0x38, 0x42, 0x31, 0x34, 0x44, 0x35, 148 | 0x30, 0x33, 0x33, 0x33, 0x38, 0x39, 0x45, 0x43, 0x42, 0x45, 0x22, 0x20, 149 | 0x73, 0x74, 0x52, 0x65, 0x66, 0x3a, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 150 | 0x6e, 0x74, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x64, 0x69, 151 | 0x64, 0x3a, 0x32, 0x31, 0x44, 0x36, 0x33, 0x46, 0x43, 0x36, 0x46, 0x43, 152 | 0x44, 0x46, 0x31, 0x31, 0x44, 0x46, 0x38, 0x42, 0x31, 0x34, 0x44, 0x35, 153 | 0x30, 0x33, 0x33, 0x33, 0x38, 0x39, 0x45, 0x43, 0x42, 0x45, 0x22, 0x2f, 154 | 0x3e, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 155 | 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x20, 0x3c, 0x2f, 0x72, 156 | 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x20, 0x3c, 0x2f, 0x78, 0x3a, 157 | 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x20, 0x3c, 0x3f, 0x78, 158 | 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x22, 159 | 0x72, 0x22, 0x3f, 0x3e, 0x3a, 0x34, 0xd4, 0x3b, 0x00, 0x00, 0x00, 0x6b, 160 | 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xbc, 0xd2, 0x4b, 0x0a, 0x80, 0x30, 161 | 0x0c, 0x04, 0xd0, 0x06, 0xbc, 0xff, 0x42, 0x04, 0x77, 0xf6, 0x6e, 0xa5, 162 | 0xf8, 0xa1, 0x58, 0x15, 0xb5, 0x22, 0x24, 0xc1, 0x2b, 0x38, 0x59, 0x74, 163 | 0xf6, 0x8f, 0x19, 0x42, 0x68, 0x2b, 0xaf, 0xfb, 0x9d, 0x18, 0x42, 0xdf, 164 | 0xb5, 0xb4, 0xde, 0x8f, 0x43, 0x32, 0xc7, 0x91, 0xd2, 0x59, 0x1c, 0x18, 165 | 0x5a, 0xf6, 0x0b, 0x36, 0x53, 0x3e, 0x60, 0x13, 0x53, 0x46, 0x4d, 0xc3, 166 | 0x22, 0xb0, 0x51, 0x83, 0x11, 0x96, 0x2a, 0xdb, 0x58, 0x0d, 0xc6, 0xb0, 167 | 0x4d, 0x0d, 0x46, 0x84, 0xf1, 0x1e, 0xad, 0x73, 0x37, 0x51, 0x35, 0xfc, 168 | 0x81, 0xc1, 0x18, 0x7a, 0xfc, 0xe0, 0x51, 0xf3, 0x09, 0x30, 0x00, 0xeb, 169 | 0x44, 0x40, 0x9b, 0xbe, 0x24, 0xcf, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x49, 170 | 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 171 | }; 172 | unsigned int statusBarBackgroundGreySmall_png_len = 1015; 173 | 174 | 175 | 176 | //=========================================================== 177 | #pragma mark - 178 | #pragma mark Private Class Extension 179 | //=========================================================== 180 | 181 | @interface MTStatusBarOverlay () 182 | 183 | @property (nonatomic, retain) UIActivityIndicatorView *activityIndicator; 184 | @property (nonatomic, retain) UIImageView *statusBarBackgroundImageView; 185 | @property (nonatomic, retain) UIImage *grayStatusBarImage; 186 | @property (nonatomic, retain) UIImage *grayStatusBarImageSmall; 187 | @property (nonatomic, retain) UILabel *statusLabel1; 188 | @property (nonatomic, retain) UILabel *statusLabel2; 189 | @property (nonatomic, assign) UILabel *hiddenStatusLabel; 190 | @property (nonatomic, assign) CGRect oldBackgroundViewFrame; 191 | @property (nonatomic, assign, getter=isHideInProgress) BOOL hideInProgress; 192 | 193 | // is called when the user touches the statusbar 194 | - (IBAction)contentViewClicked:(id)sender; 195 | // updates the current status bar background image for the given size and style 196 | - (void)setStatusBarBackgroundForSize:(CGRect)size statusBarStyle:(UIStatusBarStyle)style; 197 | // updates the text-colors of the labels for the given style 198 | - (void)setLabelUIForStatusBarStyle:(UIStatusBarStyle)style; 199 | // tries to retrieve the current visible view controller of the app and returns it, used for rotation 200 | - (UIViewController *)currentVisibleViewController; 201 | 202 | @end 203 | 204 | 205 | 206 | @implementation MTStatusBarOverlay 207 | 208 | //=========================================================== 209 | #pragma mark - 210 | #pragma mark Synthesizing 211 | //=========================================================== 212 | @synthesize backgroundView = backgroundView_; 213 | @synthesize statusBarBackgroundImageView = statusBarBackgroundImageView_; 214 | @synthesize statusLabel1 = statusLabel1_; 215 | @synthesize statusLabel2 = statusLabel2_; 216 | @synthesize hiddenStatusLabel = hiddenStatusLabel_; 217 | @synthesize activityIndicator = activityIndicator_; 218 | @synthesize finishedLabel = finishedLabel_; 219 | @synthesize grayStatusBarImage = grayStatusBarImage_; 220 | @synthesize grayStatusBarImageSmall = grayStatusBarImageSmall_; 221 | @synthesize smallFrame = smallFrame_; 222 | @synthesize oldBackgroundViewFrame = oldBackgroundViewFrame_; 223 | @synthesize animation = animation_; 224 | @synthesize hideInProgress = hideInProgress_; 225 | 226 | //=========================================================== 227 | #pragma mark - 228 | #pragma mark Lifecycle 229 | //=========================================================== 230 | 231 | - (id)initWithFrame:(CGRect)frame { 232 | if ((self = [super initWithFrame:frame])) { 233 | // Place the window on the correct level and position 234 | self.windowLevel = UIWindowLevelStatusBar+1.0f; 235 | self.frame = [UIApplication sharedApplication].statusBarFrame; 236 | 237 | // Default Small size: just show Activity Indicator 238 | smallFrame_ = CGRectMake(self.frame.size.width - kWidthSmall, 0.0f, kWidthSmall, self.frame.size.height); 239 | // Default Animation-Mode 240 | animation_ = MTStatusBarOverlayAnimationNone; 241 | 242 | // Create view that stores all the content 243 | backgroundView_ = [[UIControl alloc] initWithFrame:self.frame]; 244 | [backgroundView_ addTarget:self action:@selector(contentViewClicked:) forControlEvents:UIControlEventTouchUpInside]; 245 | backgroundView_.clipsToBounds = YES; 246 | backgroundView_.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 247 | 248 | // Image of gray status bar 249 | NSData *pngData = [NSData dataWithBytesNoCopy:statusBarBackgroundGrey_png length:statusBarBackgroundGrey_png_len freeWhenDone:NO]; 250 | grayStatusBarImage_ = [[UIImage imageWithData:pngData] retain]; 251 | 252 | NSData *pngDataSmall = [NSData dataWithBytesNoCopy:statusBarBackgroundGreySmall_png length:statusBarBackgroundGreySmall_png_len freeWhenDone:NO]; 253 | grayStatusBarImageSmall_ = [[UIImage imageWithData:pngDataSmall] retain]; 254 | 255 | // Background-Image of the Content View 256 | statusBarBackgroundImageView_ = [[UIImageView alloc] initWithFrame:self.frame]; 257 | statusBarBackgroundImageView_.backgroundColor = [UIColor blackColor]; 258 | statusBarBackgroundImageView_.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 259 | [self addSubviewToBackgroundView:statusBarBackgroundImageView_]; 260 | 261 | // Activity Indicator 262 | activityIndicator_ = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 263 | activityIndicator_.frame = CGRectMake(8.0f, 3.0f, self.frame.size.height - 6, self.frame.size.height - 6); 264 | activityIndicator_.hidesWhenStopped = YES; 265 | [self addSubviewToBackgroundView:activityIndicator_]; 266 | 267 | // Finished-Label 268 | finishedLabel_ = [[UILabel alloc] initWithFrame:CGRectMake(8,0,self.frame.size.height, self.frame.size.height)]; 269 | finishedLabel_.backgroundColor = [UIColor clearColor]; 270 | finishedLabel_.hidden = YES; 271 | finishedLabel_.text = @"✔"; 272 | finishedLabel_.font = [UIFont boldSystemFontOfSize:14.f]; 273 | [self addSubviewToBackgroundView:finishedLabel_]; 274 | 275 | // Status Label 1 is first visible 276 | statusLabel1_ = [[UILabel alloc] initWithFrame:CGRectMake(30.0f, 0.0f, self.frame.size.width - 60.0f, self.frame.size.height-1)]; 277 | statusLabel1_.backgroundColor = [UIColor clearColor]; 278 | statusLabel1_.font = [UIFont boldSystemFontOfSize:12.0f]; 279 | statusLabel1_.textAlignment = UITextAlignmentCenter; 280 | statusLabel1_.lineBreakMode = UILineBreakModeTailTruncation; 281 | statusLabel1_.autoresizingMask = UIViewAutoresizingFlexibleWidth; 282 | [self addSubviewToBackgroundView:statusLabel1_]; 283 | 284 | // Status Label 2 is hidden 285 | statusLabel2_ = [[UILabel alloc] initWithFrame:CGRectMake(30.0f, self.frame.size.height,self.frame.size.width - 60.0f , self.frame.size.height-1)]; 286 | statusLabel2_.backgroundColor = [UIColor clearColor]; 287 | statusLabel2_.font = [UIFont boldSystemFontOfSize:12.0f]; 288 | statusLabel2_.textAlignment = UITextAlignmentCenter; 289 | statusLabel2_.lineBreakMode = UILineBreakModeTailTruncation; 290 | statusLabel2_.autoresizingMask = UIViewAutoresizingFlexibleWidth; 291 | [self addSubviewToBackgroundView:statusLabel2_]; 292 | 293 | // the hidden status label at the beggining 294 | hiddenStatusLabel_ = statusLabel2_; 295 | 296 | queuedMessages = [[[NSMutableArray alloc] init] retain]; 297 | 298 | [self addSubview:backgroundView_]; 299 | 300 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 301 | [[NSNotificationCenter defaultCenter] addObserver:self 302 | selector:@selector(didRotate:) 303 | name:UIDeviceOrientationDidChangeNotification object:nil]; 304 | } 305 | 306 | return self; 307 | } 308 | 309 | 310 | - (void)dealloc { 311 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 312 | 313 | [backgroundView_ release], backgroundView_ = nil; 314 | [statusBarBackgroundImageView_ release], statusBarBackgroundImageView_ = nil; 315 | [statusLabel1_ release], statusLabel1_ = nil; 316 | [statusLabel2_ release], statusLabel2_ = nil; 317 | [activityIndicator_ release], activityIndicator_ = nil; 318 | [finishedLabel_ release], finishedLabel_ = nil; 319 | [grayStatusBarImage_ release], grayStatusBarImage_ = nil; 320 | [grayStatusBarImageSmall_ release], grayStatusBarImageSmall_ = nil; 321 | [queuedMessages release], queuedMessages = nil; 322 | [queueTimer release], queueTimer = nil; 323 | 324 | [super dealloc]; 325 | } 326 | 327 | //=========================================================== 328 | #pragma mark - 329 | #pragma mark Change status bar appearance and behavior 330 | //=========================================================== 331 | 332 | - (void)addSubviewToBackgroundView:(UIView *)view { 333 | view.userInteractionEnabled = NO; 334 | [self.backgroundView addSubview:view]; 335 | } 336 | 337 | - (void)show { 338 | // don't show if status bar is hidden 339 | if ([UIApplication sharedApplication].statusBarHidden) { 340 | return; 341 | } 342 | 343 | // start activity indicator 344 | [self.activityIndicator startAnimating]; 345 | // show status bar overlay 346 | self.hidden = NO; 347 | } 348 | 349 | - (void)hide { 350 | [self.activityIndicator stopAnimating]; 351 | self.hidden = YES; 352 | self.hideInProgress = NO; 353 | } 354 | 355 | - (void)setMessage:(NSString *)message animated:(BOOL)animated { 356 | // don't show if status bar is hidden 357 | if ([UIApplication sharedApplication].statusBarHidden) { 358 | return; 359 | } 360 | 361 | 362 | //DDLogInfo(@"message: %@", message); 363 | self.hideInProgress = NO; 364 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil]; 365 | self.finishedLabel.hidden = YES; 366 | self.activityIndicator.hidden = NO; 367 | 368 | // status bar not visible in the moment, just show it 369 | if (self.hidden) { 370 | [self showWithMessage:message]; 371 | return; 372 | } 373 | 374 | if (animated) { 375 | // set text of currently not visible label to new text 376 | if (self.hiddenStatusLabel == self.statusLabel1) { 377 | self.statusLabel1.text = message; 378 | 379 | // position under visible status label 380 | self.statusLabel1.frame = CGRectMake(self.statusLabel1.frame.origin.x, 381 | self.frame.size.height, 382 | self.statusLabel1.frame.size.width, 383 | self.statusLabel1.frame.size.height); 384 | } else { 385 | self.statusLabel2.text = message; 386 | 387 | // position under visible status label 388 | self.statusLabel2.frame = CGRectMake(self.statusLabel2.frame.origin.x, 389 | self.frame.size.height, 390 | self.statusLabel2.frame.size.width, 391 | self.statusLabel2.frame.size.height); 392 | } 393 | 394 | // animate not visible label into user view 395 | [UIView animateWithDuration:kNextStatusAnimationDuration 396 | delay:0 397 | options:UIViewAnimationOptionCurveEaseInOut 398 | animations:^{ 399 | // move both status labels up 400 | self.statusLabel1.frame = CGRectMake(self.statusLabel1.frame.origin.x, 401 | self.statusLabel1.frame.origin.y - self.frame.size.height, 402 | self.statusLabel1.frame.size.width, 403 | self.statusLabel1.frame.size.height); 404 | self.statusLabel2.frame = CGRectMake(self.statusLabel2.frame.origin.x, 405 | self.statusLabel2.frame.origin.y - self.frame.size.height, 406 | self.statusLabel2.frame.size.width, 407 | self.statusLabel2.frame.size.height); 408 | } 409 | completion:^(BOOL finished) { 410 | // after animation, set new hidden status label indicator 411 | if (self.hiddenStatusLabel == self.statusLabel1) { 412 | self.hiddenStatusLabel = self.statusLabel2; 413 | } else { 414 | self.hiddenStatusLabel = self.statusLabel1; 415 | } 416 | }]; 417 | } 418 | 419 | // w/o animation 420 | else { 421 | if (self.hiddenStatusLabel == self.statusLabel1) { 422 | self.statusLabel2.text = message; 423 | } else { 424 | self.statusLabel1.text = message; 425 | } 426 | } 427 | } 428 | 429 | - (void)showWithMessage:(NSString *)message { 430 | // don't duplicate animation if already displaying with text 431 | if (message == nil || (!self.hidden && [self.statusLabel1.text isEqualToString:message])) { 432 | return; 433 | } 434 | 435 | // Kill any queued messages 436 | [queueTimer invalidate]; 437 | 438 | // update status bar background 439 | UIStatusBarStyle statusBarStyle = [UIApplication sharedApplication].statusBarStyle; 440 | [self setStatusBarBackgroundForSize:self.backgroundView.frame statusBarStyle:statusBarStyle]; 441 | // update label-UI depending on status bar style 442 | [self setLabelUIForStatusBarStyle:statusBarStyle]; 443 | 444 | // if status bar is currently hidden, show it 445 | if (self.hidden) { 446 | // set text of visible status label 447 | self.statusLabel1.text = message; 448 | 449 | [self show]; 450 | } 451 | 452 | // already visible, animate to new text 453 | else { 454 | [self setMessage:message animated:YES]; 455 | } 456 | } 457 | 458 | - (void)queueMessage:(NSString *)message forInterval:(NSTimeInterval)interval animated:(BOOL)animated { 459 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:message, @"message", [NSNumber numberWithDouble:interval], @"interval", [NSNumber numberWithBool:animated], @"animated", [NSNumber numberWithBool:NO], @"final", nil]; 460 | [queuedMessages insertObject:dict atIndex:0]; 461 | 462 | if([queuedMessages count] == 1) { 463 | [self setMessage:message animated:animated]; 464 | queueTimer = [NSTimer timerWithTimeInterval:interval target:self selector:@selector(queuedMessageDidExpire:) userInfo:nil repeats:NO]; 465 | [[NSRunLoop mainRunLoop] addTimer:queueTimer forMode:NSDefaultRunLoopMode]; 466 | } 467 | } 468 | 469 | - (void)queueFinalMessage:(NSString *)message forInterval:(NSTimeInterval)interval animated:(BOOL)animated { 470 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:message, @"message", [NSNumber numberWithDouble:interval], @"interval", [NSNumber numberWithBool:animated], @"animated", [NSNumber numberWithBool:YES], @"final", nil]; 471 | [queuedMessages insertObject:dict atIndex:0]; 472 | 473 | if([queuedMessages count] == 1) { 474 | [self finishWithMessage:message duration:interval]; 475 | } 476 | } 477 | 478 | - (void)queuedMessageDidExpire:(NSTimer *)theTimer { 479 | [queuedMessages removeLastObject]; 480 | if([queuedMessages count] == 0) { 481 | [self hide]; 482 | } else { 483 | NSDictionary *nextDict = [queuedMessages lastObject]; 484 | 485 | if([[nextDict valueForKey:@"final"] boolValue]) { 486 | [self finishWithMessage:[nextDict valueForKey:@"message"] duration:[[nextDict valueForKey:@"interval"] doubleValue]]; 487 | } else { 488 | [self setMessage:[nextDict valueForKey:@"message"] animated:[[nextDict valueForKey:@"animated"] boolValue]]; 489 | queueTimer = [NSTimer timerWithTimeInterval:[[nextDict valueForKey:@"interval"] doubleValue] target:self selector:@selector(queuedMessageDidExpire:) userInfo:nil repeats:NO]; 490 | [[NSRunLoop mainRunLoop] addTimer:queueTimer forMode:NSDefaultRunLoopMode]; 491 | } 492 | } 493 | } 494 | 495 | - (void)finishWithMessage:(NSString *)message duration:(NSTimeInterval)duration { 496 | [self showWithMessage:message]; 497 | 498 | self.activityIndicator.hidden = YES; 499 | self.finishedLabel.hidden = NO; 500 | 501 | self.hideInProgress = YES; 502 | [self performSelector:@selector(hide) withObject:nil afterDelay:duration]; 503 | } 504 | 505 | //=========================================================== 506 | #pragma mark - 507 | #pragma mark Rotation Notification 508 | //=========================================================== 509 | 510 | - (void) didRotate:(NSNotification *)notification { 511 | // current device orientation 512 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 513 | // current visible view controller 514 | UIViewController *visibleViewController = [self currentVisibleViewController]; 515 | 516 | // check if we should rotate 517 | if (visibleViewController == nil || 518 | ![visibleViewController respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)] || 519 | ![visibleViewController shouldAutorotateToInterfaceOrientation:orientation]) { 520 | return; 521 | } 522 | 523 | // store a flag, if the StatusBar is currently shrinked 524 | BOOL currentlyShrinked = CGRectEqualToRect(self.backgroundView.frame, self.smallFrame); 525 | 526 | if (orientation == UIDeviceOrientationPortrait) { 527 | self.transform = CGAffineTransformIdentity; 528 | self.frame = CGRectMake(0,0,kScreenWidth,kStatusBarHeight); 529 | self.smallFrame = CGRectMake(self.frame.size.width - kWidthSmall, 0.0f, kWidthSmall, self.frame.size.height); 530 | }else if (orientation == UIDeviceOrientationLandscapeLeft) { 531 | self.transform = CGAffineTransformMakeRotation(M_PI * (90) / 180.0); 532 | self.frame = CGRectMake(kScreenWidth - kStatusBarHeight,0, kStatusBarHeight, 480); 533 | self.smallFrame = CGRectMake(kScreenHeight-kWidthSmall,0,kWidthSmall,kStatusBarHeight); 534 | } else if (orientation == UIDeviceOrientationLandscapeRight) { 535 | self.transform = CGAffineTransformMakeRotation(M_PI * (-90) / 180.0); 536 | self.frame = CGRectMake(0,0, kStatusBarHeight, kScreenHeight); 537 | self.smallFrame = CGRectMake(kScreenHeight-kWidthSmall,0, kWidthSmall, kStatusBarHeight); 538 | } else if (orientation == UIDeviceOrientationPortraitUpsideDown) { 539 | self.transform = CGAffineTransformMakeRotation(M_PI); 540 | self.frame = CGRectMake(0,kScreenHeight - kStatusBarHeight,kScreenWidth,kStatusBarHeight); 541 | self.smallFrame = CGRectMake(self.frame.size.width - kWidthSmall, 0.0f, kWidthSmall, self.frame.size.height); 542 | } 543 | 544 | // if the statusBar is currently shrinked, update the frames for the new rotation state 545 | if (currentlyShrinked) { 546 | // the oldBackgroundViewFrame is the frame of the whole StatusBar 547 | self.oldBackgroundViewFrame = CGRectMake(0,0,UIInterfaceOrientationIsPortrait(orientation) ? kScreenWidth : kScreenHeight,kStatusBarHeight); 548 | // the backgroundView gets the newly computed smallFrame 549 | self.backgroundView.frame = self.smallFrame; 550 | } 551 | } 552 | 553 | //=========================================================== 554 | #pragma mark - 555 | #pragma mark Private Methods 556 | //=========================================================== 557 | 558 | - (IBAction)contentViewClicked:(id)sender { 559 | switch (self.animation) { 560 | case MTStatusBarOverlayAnimationShrink: 561 | [UIView animateWithDuration:0.3 animations:^{ 562 | // update status bar background 563 | [self setStatusBarBackgroundForSize:self.backgroundView.frame statusBarStyle:[UIApplication sharedApplication].statusBarStyle]; 564 | 565 | // if size is small size, make it bigger 566 | if (CGRectEqualToRect(self.backgroundView.frame, self.smallFrame)) { 567 | self.backgroundView.frame = self.oldBackgroundViewFrame; 568 | 569 | // move activity indicator and statusLabel to the left 570 | self.activityIndicator.frame = CGRectMake(self.activityIndicator.frame.origin.x - kSmallXOffset, self.activityIndicator.frame.origin.y, 571 | self.activityIndicator.frame.size.width, self.activityIndicator.frame.size.height); 572 | self.statusLabel1.frame = CGRectMake(self.statusLabel1.frame.origin.x - kSmallXOffset, self.statusLabel1.frame.origin.y, 573 | self.statusLabel1.frame.size.width, self.statusLabel1.frame.size.height); 574 | self.statusLabel2.frame = CGRectMake(self.statusLabel2.frame.origin.x - kSmallXOffset, self.statusLabel2.frame.origin.y, 575 | self.statusLabel2.frame.size.width, self.statusLabel2.frame.size.height); 576 | } 577 | // else make it smaller 578 | else { 579 | self.oldBackgroundViewFrame = self.backgroundView.frame; 580 | self.backgroundView.frame = self.smallFrame; 581 | 582 | // move activity indicator and statusLabel to the right 583 | self.activityIndicator.frame = CGRectMake(self.activityIndicator.frame.origin.x + kSmallXOffset, self.activityIndicator.frame.origin.y, 584 | self.activityIndicator.frame.size.width, self.activityIndicator.frame.size.height); 585 | self.statusLabel1.frame = CGRectMake(self.statusLabel1.frame.origin.x + kSmallXOffset, self.statusLabel1.frame.origin.y, 586 | self.statusLabel1.frame.size.width, self.statusLabel1.frame.size.height); 587 | self.statusLabel2.frame = CGRectMake(self.statusLabel2.frame.origin.x + kSmallXOffset, self.statusLabel2.frame.origin.y, 588 | self.statusLabel2.frame.size.width, self.statusLabel2.frame.size.height); 589 | } 590 | }]; 591 | break; 592 | 593 | case MTStatusBarOverlayAnimationFallDown: 594 | // TODO: implement, display another UIView that shows further information (like Android StatusBar) 595 | break; 596 | case MTStatusBarOverlayAnimationNone: 597 | // ignore 598 | break; 599 | } 600 | } 601 | 602 | - (void)setStatusBarBackgroundForSize:(CGRect)size statusBarStyle:(UIStatusBarStyle)style { 603 | // gray status bar? 604 | // on iPad the Default Status Bar Style is black too 605 | if (style == UIStatusBarStyleDefault && !IsIPad) { 606 | // choose image depending on size 607 | if (CGRectEqualToRect(size, self.smallFrame)) { 608 | self.statusBarBackgroundImageView.image = [self.grayStatusBarImage stretchableImageWithLeftCapWidth:2.0f topCapHeight:0.0f]; 609 | } else { 610 | self.statusBarBackgroundImageView.image = [self.grayStatusBarImageSmall stretchableImageWithLeftCapWidth:2.0f topCapHeight:0.0f]; 611 | } 612 | } 613 | 614 | // black status bar? -> no image 615 | else { 616 | self.statusBarBackgroundImageView.image = nil; 617 | } 618 | } 619 | 620 | - (void)setLabelUIForStatusBarStyle:(UIStatusBarStyle)style { 621 | // gray status bar? 622 | // on iPad the Default Status Bar Style is black too 623 | if (style == UIStatusBarStyleDefault && !IsIPad) { 624 | self.statusLabel1.textColor = kStatusBarStyleDefaultTextColor; 625 | self.statusLabel2.textColor = kStatusBarStyleDefaultTextColor; 626 | self.finishedLabel.textColor = kStatusBarStyleDefaultTextColor; 627 | self.activityIndicator.activityIndicatorViewStyle = kStatusBarStyleDefaultActivityIndicatorViewStyle; 628 | } else { 629 | self.statusLabel1.textColor = kStatusBarStyleBlackTextColor; 630 | self.statusLabel2.textColor = kStatusBarStyleBlackTextColor; 631 | self.finishedLabel.textColor = kStatusBarStyleBlackTextColor; 632 | self.activityIndicator.activityIndicatorViewStyle = kStatusBarStyleBlackActivityIndicatorViewStyle; 633 | } 634 | } 635 | 636 | - (UIViewController *)currentVisibleViewController { 637 | // Credits go to ShareKit: https://github.com/ideashower/ShareKit 638 | 639 | // Try to find the root view controller programmically 640 | // Find the top window (that is not an alert view or other window) 641 | UIWindow *topWindow = [[UIApplication sharedApplication] keyWindow]; 642 | 643 | if (topWindow.windowLevel != UIWindowLevelNormal) { 644 | NSArray *windows = [[UIApplication sharedApplication] windows]; 645 | 646 | for(topWindow in windows) { 647 | if (topWindow.windowLevel == UIWindowLevelNormal) 648 | break; 649 | } 650 | } 651 | 652 | UIView *rootView = [[topWindow subviews] objectAtIndex:0]; 653 | id nextResponder = [rootView nextResponder]; 654 | 655 | if ([nextResponder isKindOfClass:[UIViewController class]]) { 656 | return nextResponder; 657 | } else { 658 | NSLog(@"MTStatusBarOverlay: Could not find a root view controller, will not rotate!"); 659 | return nil; 660 | } 661 | } 662 | 663 | //=========================================================== 664 | #pragma mark - 665 | #pragma mark Singleton definitons 666 | //=========================================================== 667 | 668 | static MTStatusBarOverlay *sharedMTStatusBarOverlay = nil; 669 | 670 | + (MTStatusBarOverlay *)sharedInstance { 671 | @synchronized(self) { 672 | if (sharedMTStatusBarOverlay == nil) { 673 | sharedMTStatusBarOverlay = [[self alloc] initWithFrame:CGRectZero]; 674 | } 675 | } 676 | 677 | return sharedMTStatusBarOverlay; 678 | } 679 | 680 | + (id)allocWithZone:(NSZone *)zone { 681 | @synchronized(self) { 682 | if (sharedMTStatusBarOverlay == nil) { 683 | sharedMTStatusBarOverlay = [super allocWithZone:zone]; 684 | 685 | return sharedMTStatusBarOverlay; 686 | } 687 | } 688 | 689 | return nil; 690 | } 691 | 692 | - (id)copyWithZone:(NSZone *)zone { 693 | return self; 694 | } 695 | 696 | - (id)retain { 697 | return self; 698 | } 699 | 700 | - (NSUInteger)retainCount { 701 | return NSUIntegerMax; 702 | } 703 | 704 | - (void)release { 705 | } 706 | 707 | - (id)autorelease { 708 | return self; 709 | } 710 | 711 | @end 712 | --------------------------------------------------------------------------------