Added an example for TUIControl tracking with sliding tabs!
It's pretty fun to play with sliding tabs…. :D
This commit is contained in:
@@ -16,35 +16,89 @@
|
||||
|
||||
#import "ExampleTabBar.h"
|
||||
|
||||
@interface ExampleTab : TUIView
|
||||
@interface ExampleTab : TUIControl
|
||||
|
||||
@property (nonatomic, assign) CGFloat originalPosition;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ExampleTab
|
||||
|
||||
- (ExampleTabBar *)tabBar
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
[super mouseDown:event]; // always call super when overriding mouseXXX: methods - lots of plumbing happens in TUIView
|
||||
// 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;
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)event
|
||||
{
|
||||
[super mouseUp:event];
|
||||
// Find the tab that was being dragged- although this isn't the
|
||||
// most efficient way, this will suffice for now.
|
||||
- (BOOL)continueTrackingWithEvent:(NSEvent *)event {
|
||||
|
||||
// rather than a simple -setNeedsDisplay, let's fade it back out
|
||||
[TUIView animateWithDuration:0.5 animations:^{
|
||||
[self redraw]; // -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
|
||||
// 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;
|
||||
}];
|
||||
|
||||
if([self eventInside:event]) { // only perform the action if the mouse up happened inside our bounds - ignores mouse down, drag-out, mouse up
|
||||
[[self tabBar].delegate tabBar:[self tabBar] didSelectTab:self.tag];
|
||||
}
|
||||
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
|
||||
@@ -61,7 +115,7 @@
|
||||
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 width = (b.size.width / nTabs);
|
||||
float x = i * width;
|
||||
return CGRectMake(roundf(x), 0, roundf(width), b.size.height);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user