Files
Aditya Nrusimha a433398d43 Added an example for TUIControl tracking with sliding tabs!
It's pretty fun to play with sliding tabs…. :D
2012-09-25 18:18:55 -07:00

152 lines
4.8 KiB
Objective-C

/*
Copyright 2011 Twitter, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this work except in compliance with the License.
You may obtain a copy of the License in the LICENSE file, or 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 "ExampleTabBar.h"
@interface ExampleTab : TUIControl
@property (nonatomic, assign) CGFloat originalPosition;
@end
@implementation ExampleTab
// Convinience to call delegate methods, since by default, our
// superview SHOULD be a tab bar, and nothing else. This will
// horribly crash if you add an ExampleTab to anything but a tab bar.
- (ExampleTabBar *)tabBar {
return (ExampleTabBar *)self.superview;
}
// If a tracking event occurs within a tab, we want to move the
// tab around, so return YES.
- (BOOL)beginTrackingWithEvent:(NSEvent *)event {
[self setNeedsDisplay];
// So the tab doesn't move over just on mouse pressed.
self.originalPosition = [self convertPoint:[event locationInWindow] fromView:nil].x;
return YES;
}
// Find the tab that was being dragged- although this isn't the
// most efficient way, this will suffice for now.
- (BOOL)continueTrackingWithEvent:(NSEvent *)event {
// Offset the tab's x origin by whatever we dragged by.
// Animating it makes it fun if the drag goes pretty far.
CGFloat currentPosition = [self convertPoint:[event locationInWindow] fromView:nil].x;
[TUIView animateWithDuration:0.1 animations:^{
// Setting an ease-in-out animation curve slows down
// the animation at the start and finish, but speeds it up
// during the middle. Just for that "don't slide me!" fun.
[TUIView setAnimationCurve:TUIViewAnimationCurveEaseInOut];
CGRect draggedRect = self.frame;
draggedRect.origin.x += roundf(currentPosition - self.originalPosition);
self.frame = draggedRect;
}];
return YES;
}
// Restore tabs to their original condition.
- (void)endTrackingWithEvent:(NSEvent *)event {
// By nature, the event *must* be inside the tab's bounds, otherwise the
// tracking process will not be invoked. If we were dragged, we were NOT
// pressed, so don't call the delegate.
CGFloat currentPosition = [self convertPoint:[event locationInWindow] fromView:nil].x;
if(self.originalPosition == currentPosition)
[[self tabBar].delegate tabBar:[self tabBar] didSelectTab:self.tag];
// Since tracking is done, move the tab back. This whole ordeal lets us
// "stretch" our tabs around.
float originalPoint = self.tag * (self.tabBar.bounds.size.width / self.tabBar.tabViews.count);
[TUIView animateWithDuration:0.2 animations:^{
CGRect draggedRect = self.frame;
draggedRect.origin.x = roundf(originalPoint);
self.frame = draggedRect;
}];
// Rather than a simple -setNeedsDisplay, let's fade it back out.
[TUIView animateWithDuration:0.3 animations:^{
// -redraw forces a .contents update immediately based on drawRect,
// and it happens inside an animation block, so CoreAnimation gives
// us a cross-fade for free.
[self redraw];
}];
}
@end
@interface ExampleTabBar ()
@property (nonatomic, assign) ExampleTab *draggingTab;
@end
@implementation ExampleTabBar
@synthesize delegate;
@synthesize tabViews;
- (id)initWithNumberOfTabs:(NSInteger)nTabs
{
if((self = [super initWithFrame:CGRectZero])) {
NSMutableArray *_tabViews = [NSMutableArray arrayWithCapacity:nTabs];
for(int i = 0; i < nTabs; ++i) {
ExampleTab *t = [[ExampleTab alloc] initWithFrame:CGRectZero];
t.tag = i;
t.layout = ^(TUIView *v) { // the layout of an individual tab is a function of the superview bounds, the number of tabs, and the current tab index
CGRect b = v.superview.bounds; // reference the passed-in 'v' rather than 't' to avoid a retain cycle
float width = (b.size.width / nTabs);
float x = i * width;
return CGRectMake(roundf(x), 0, roundf(width), b.size.height);
};
[self addSubview:t];
[_tabViews addObject:t];
}
tabViews = [[NSArray alloc] initWithArray:_tabViews];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// draw tab bar background
CGRect b = self.bounds;
CGContextRef ctx = TUIGraphicsGetCurrentContext();
// gray gradient
CGFloat colorA[] = { 0.85, 0.85, 0.85, 1.0 };
CGFloat colorB[] = { 0.71, 0.71, 0.71, 1.0 };
CGContextDrawLinearGradientBetweenPoints(ctx, CGPointMake(0, b.size.height), colorA, CGPointMake(0, 0), colorB);
// top emboss
CGContextSetRGBFillColor(ctx, 1, 1, 1, 0.5);
CGContextFillRect(ctx, CGRectMake(0, b.size.height-2, b.size.width, 1));
CGContextSetRGBFillColor(ctx, 0, 0, 0, 0.3);
CGContextFillRect(ctx, CGRectMake(0, b.size.height-1, b.size.width, 1));
}
@end