Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

267 lines (206 sloc) 9.749 kb
//
// Copyright 2009-2011 Facebook
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "Three20UI/private/TTLauncherHighlightView.h"
// UI
#import "Three20UI/TTLauncherButton.h"
#import "Three20UI/TTLauncherView.h"
// UICommon
#import "Three20UICommon/TTGlobalUICommon.h"
// Core
#import "Three20Core/TTCorePreprocessorMacros.h"
static const CGFloat kHighlightOverlayAlpha = 0.7f;
static const CGFloat kSpotlightScaleFactor = 2.5f;
static const CGFloat kSpotlightBlurInnerAlpha = 0.43f;
static const CGFloat kSpotlightBlurOuterAlpha = 0.7f; // same as kHighlightOverlayAlpha; grr const
static const CGFloat kSpotlightBlurRadius = 120.0f;
static const CGFloat kHighlightTextPadding = 20.0f;
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
@implementation TTLauncherHighlightView
@synthesize highlightRect = _highlightRect;
@synthesize parentView = _parentView;
///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.alpha = 0.0;
_textLabel = [[UILabel alloc] init];
_textLabel.lineBreakMode = UILineBreakModeWordWrap;
_textLabel.numberOfLines = 0;
_textLabel.backgroundColor = [UIColor clearColor];
_textLabel.textAlignment = UITextAlignmentCenter;
_textLabel.textColor = [UIColor whiteColor];
_textLabel.font = [UIFont boldSystemFontOfSize:17.0f];
_textLabel.shadowColor = [UIColor blackColor];
_textLabel.shadowOffset = CGSizeMake(1, 1);
[self addSubview:_textLabel];
CGRect coverFrame = [UIApplication sharedApplication].statusBarFrame;
_statusBarCover = [[UIWindow alloc] initWithFrame:coverFrame];
_statusBarCover.backgroundColor = [UIColor colorWithWhite:0.0 alpha:kHighlightOverlayAlpha];
_statusBarCover.windowLevel = UIWindowLevelStatusBar;
_statusBarCover.alpha = 0.0;
_statusBarCover.hidden = NO;
}
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)dealloc {
TT_RELEASE_SAFELY(_textLabel);
TT_RELEASE_SAFELY(_statusBarCover);
self.parentView = nil;
[super dealloc];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)animateTextIn {
_textLabel.alpha = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:TT_FAST_TRANSITION_DURATION];
_textLabel.alpha = 1.0;
[UIView commitAnimations];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)layoutLabel {
CGSize superviewSize = self.superview.bounds.size;
CGFloat width = superviewSize.width - 2 * kHighlightTextPadding;
CGFloat height = [_textLabel.text sizeWithFont:_textLabel.font
constrainedToSize:CGSizeMake(width, superviewSize.height)].height;
// If the highlighted rect is above center, put the text below it; otherwise, above it.
CGFloat y = 0.0f;
if (_highlightRect.origin.y + (_highlightRect.size.height / 2) < superviewSize.height / 2) {
y = _highlightRect.origin.y + _highlightRect.size.height + kHighlightTextPadding;
} else {
y = _highlightRect.origin.y - height - kHighlightTextPadding;
}
_textLabel.frame = CGRectMake(kHighlightTextPadding, y, width, height);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setHighlightRect:(CGRect)rect {
_highlightRect = rect;
[self layoutLabel];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (NSString*)text {
return _textLabel.text;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setText:(NSString*)text {
_textLabel.text = text;
[self layoutLabel];
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setAlpha:(CGFloat)alpha {
[super setAlpha:alpha];
_statusBarCover.alpha = alpha;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)appear:(BOOL)animated {
// The expanded frame needs to be 3.5 times the original size, and the expansion needs to emanate
// from the same center as the highlighted rect
CGRect expandedFrame = self.superview.bounds;
expandedFrame.origin.x = -(_highlightRect.origin.x + _highlightRect.size.width / 2)
* (kSpotlightScaleFactor - 1);
expandedFrame.origin.y = -(_highlightRect.origin.y + _highlightRect.size.height / 2)
* (kSpotlightScaleFactor - 1);
expandedFrame.size.width *= kSpotlightScaleFactor;
expandedFrame.size.height *= kSpotlightScaleFactor;
self.frame = expandedFrame;
self.alpha = 0.0;
_textLabel.alpha = 0.0;
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:TT_TRANSITION_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animateTextIn)];
}
self.alpha = 1.0;
self.frame = self.superview.bounds;
_statusBarCover.alpha = 1.0;
if (animated) {
[UIView commitAnimations];
} else {
_textLabel.alpha = 1.0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)isOpaque {
return NO;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:kHighlightOverlayAlpha] set];
UIRectFillUsingBlendMode(rect, kCGBlendModeOverlay);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(context, kCGBlendModeCopy);
// Draw the spotlight (more of a Fresnel lens effect but okay I'll stop now)
const CGFloat components[] = {0, 0, 0, kSpotlightBlurInnerAlpha,
0, 0, 0, kSpotlightBlurOuterAlpha};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, NULL, 2);
CGPoint center = CGPointMake(floor(_highlightRect.origin.x + _highlightRect.size.width / 2),
floor(_highlightRect.origin.y + _highlightRect.size.height / 2));
CGFloat startRadius = MIN(_highlightRect.size.width, _highlightRect.size.height) / 2;
CGFloat endRadius = startRadius + kSpotlightBlurRadius;
CGContextDrawRadialGradient(context,
gradient,
center, startRadius,
center, endRadius,
kCGGradientDrawsAfterEndLocation);
CGColorSpaceRelease(colorSpace);
CGGradientRelease(gradient);
// Draw the clear circle
CGContextSetRGBFillColor(context, 0, 0, 0, 0);
CGContextFillEllipseInRect(context, _highlightRect);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Overridden so that -hitTest:withEvent: doesn't catch this subview. We can distinguish a user-
* initiated tap from a programmatic hit test by event being nil in the programmatic case.
*/
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
if (event) {
return [super pointInside:point withEvent:event];
}
return NO;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UIResponder
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event {
UITouch* touch = [touches anyObject];
// If the user tapped within the highlighted rect, we want to pass the event through to the
// launcher button.
if (CGRectContainsPoint(_highlightRect, [touch locationInView:self])) {
UIView *targetButton = [self.superview hitTest:[touch locationInView:self] withEvent:nil];
// This condition should always be true, but just to be safe
if ([targetButton isKindOfClass:[TTLauncherButton class]]) {
[(TTLauncherButton *)targetButton sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
// This will take care of removing the view
[_parentView endHighlightItem:nil];
}
@end
Jump to Line
Something went wrong with that request. Please try again.