Skip to content

Instantly share code, notes, and snippets.

@yomybaby
Last active August 3, 2016 18:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yomybaby/31af49cbb46784da3f3fe99bdec4cfed to your computer and use it in GitHub Desktop.
Save yomybaby/31af49cbb46784da3f3fe99bdec4cfed to your computer and use it in GitHub Desktop.
iOS hidesBarsOnSwipe on Titanium
Ti.UI.setBackgroundColor('#000');
var win = Ti.UI.createWindow({
backgroundColor: 'black',
exitOnClose: true,
fullscreen: false,
title: 'TableView Demo 1',
hidesBarsOnSwipe : true // THIS IS THAT!
});
// generate random number, used to make each row appear distinct for this example
function randomInt(max){
return Math.floor(Math.random() * max) + 1;
}
var IMG_BASE = 'https://github.com/appcelerator/titanium_mobile/raw/master/demos/KitchenSink/Resources/images/';
var defaultFontSize = Ti.Platform.name === 'android' ? 16 : 14;
var tableData = [];
for (var i=1; i<=20; i++){
var row = Ti.UI.createTableViewRow({
className:'forumEvent', // used to improve table performance
selectedBackgroundColor:'white',
rowIndex:i, // custom property, useful for determining the row during events
height:110
});
var imageAvatar = Ti.UI.createImageView({
image: IMG_BASE + 'custom_tableview/user.png',
left:10, top:5,
width:50, height:50
});
row.add(imageAvatar);
var labelUserName = Ti.UI.createLabel({
color:'#576996',
font:{fontFamily:'Arial', fontSize:defaultFontSize+6, fontWeight:'bold'},
text:'Fred Smith ' + i,
left:70, top: 6,
width:200, height: 30
});
row.add(labelUserName);
var labelDetails = Ti.UI.createLabel({
color:'#222',
font:{fontFamily:'Arial', fontSize:defaultFontSize+2, fontWeight:'normal'},
text:'Replied to post with id ' + randomInt(1000) + '.',
left:70, top:44,
width:360
});
row.add(labelDetails);
var imageCalendar = Ti.UI.createImageView({
image:IMG_BASE + 'custom_tableview/eventsButton.png',
left:70, bottom: 2,
width:32, height: 32
});
row.add(imageCalendar);
var labelDate = Ti.UI.createLabel({
color:'#999',
font:{fontFamily:'Arial', fontSize:defaultFontSize, fontWeight:'normal'},
text:'on ' + randomInt(30) + ' Nov 2012',
left:105, bottom:10,
width:200, height:20
});
row.add(labelDate);
tableData.push(row);
}
var tableView = Ti.UI.createTableView({
backgroundColor:'white',
data:tableData
});
win.add(tableView);
win.open();
var win1 = Titanium.UI.iOS.createNavigationWindow({
window: win
});
win1.open()
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
* WARNING: This is generated code. Modify at your own risk and without support.
*/
#ifdef USE_TI_UIWINDOW
#import "TiUIWindowProxy.h"
#import "Webcolor.h"
#import "TiUIViewProxy.h"
#import "ImageLoader.h"
#import "TiComplexValue.h"
#import "TiApp.h"
#import "TiLayoutQueue.h"
// this is how long we should wait on the new JS context to be loaded
// holding the UI thread before we return during an window open. we
// attempt to hold it for a small period of time to allow the window
// to loaded before we return from the open such that the paint will be
// much smoother on the new window during a tab transition
#define EXTERNAL_JS_WAIT_TIME (150/1000)
/**
* This class is a helper that will be used when we have an external
* window w/ JS so that we can attempt to wait for the window context
* to be fully loaded on the UI thread (since JS runs in a different
* thread) and attempt to wait up til EXTERNAL_JS_WAIT_TIME before
* timing out. If timed out, will go ahead and start opening the window
* and as the JS context finishes, will continue opening from there -
* this has a nice effect of immediately opening if fast but not delaying
* if slow (so you get weird button delay effects for example)
*
*/
@interface TiUIWindowProxyLatch : NSObject
{
NSCondition *lock;
TiUIWindowProxy* window;
id args;
BOOL completed;
BOOL timeout;
}
@end
@implementation TiUIWindowProxyLatch
-(id)initWithTiWindow:(id)window_ args:(id)args_
{
if (self = [super init])
{
window = [window_ retain];
args = [args_ retain];
lock = [[NSCondition alloc] init];
}
return self;
}
-(void)dealloc
{
RELEASE_TO_NIL(lock);
RELEASE_TO_NIL(window);
RELEASE_TO_NIL(args);
[super dealloc];
}
-(void)booted:(id)arg
{
[lock lock];
completed = YES;
[lock signal];
if (timeout)
{
[window boot:YES args:args];
}
[lock unlock];
}
-(BOOL)waitForBoot
{
BOOL yn = NO;
[lock lock];
if(completed)
{
yn = YES;
}
else
{
if ([lock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:EXTERNAL_JS_WAIT_TIME]]==NO)
{
timeout = YES;
}
else
{
yn = YES;
}
}
[lock unlock];
return yn;
}
@end
@implementation TiUIWindowProxy
-(void)_destroy
{
if (!closing && opened) {
TiThreadPerformOnMainThread(^{[self close:nil];}, YES);
}
#ifdef TI_USE_KROLL_THREAD
TiThreadRemoveFromSuperviewOnMainThread(barImageView, NO);
TiThreadReleaseOnMainThread(barImageView, NO);
barImageView = nil;
#else
TiThreadPerformOnMainThread(^{
[barImageView removeFromSuperview];
RELEASE_TO_NIL(barImageView);
}, YES);
#endif
if (context!=nil)
{
[context shutdown:nil];
RELEASE_TO_NIL(context);
}
RELEASE_TO_NIL(oldBaseURL);
RELEASE_TO_NIL(latch);
[super _destroy];
}
-(void)_configure
{
[self replaceValue:nil forKey:@"barColor" notification:NO];
[self replaceValue:nil forKey:@"navTintColor" notification:NO];
[self replaceValue:nil forKey:@"barImage" notification:NO];
[self replaceValue:nil forKey:@"translucent" notification:NO];
[self replaceValue:nil forKey:@"titleAttributes" notification:NO];
[self replaceValue:NUMBOOL(NO) forKey:@"tabBarHidden" notification:NO];
[self replaceValue:NUMBOOL(NO) forKey:@"navBarHidden" notification:NO];
[self replaceValue:NUMBOOL(NO) forKey:@"hidesBarsOnSwipe" notification:NO];
[super _configure];
}
-(NSString*)apiName
{
return @"Ti.UI.Window";
}
-(void)dealloc
{
RELEASE_TO_NIL(barImageView);
[super dealloc];
}
-(void)boot:(BOOL)timeout args:args
{
RELEASE_TO_NIL(latch);
if (timeout) {
if (![context evaluationError]) {
contextReady = YES;
[self open:args];
} else {
DebugLog(@"Could not boot context. Context has evaluation error");
}
}
}
-(BOOL)optimizeSubviewInsertion
{
return YES;
}
-(NSMutableDictionary*)langConversionTable
{
return [NSMutableDictionary dictionaryWithObjectsAndKeys:@"title",@"titleid",@"titlePrompt",@"titlepromptid",nil];
}
#pragma mark - TiWindowProtocol overrides
-(UIViewController*)hostingController;
{
if (controller == nil) {
UIViewController* theController = [super hostingController];
[theController setHidesBottomBarWhenPushed:[TiUtils boolValue:[self valueForUndefinedKey:@"tabBarHidden"] def:NO]];
return theController;
}
return [super hostingController];
}
-(BOOL)_handleOpen:(id)args
{
// this is a special case that calls open again above to cause the event lifecycle to
// happen after the JS context is fully up and ready
if (contextReady && context!=nil)
{
return [super _handleOpen:args];
}
//
// at this level, open is top-level since this is a window. if you want
// to open a window within a tab, you'll need to call tab.open(window)
//
NSURL *url = [TiUtils toURL:[self valueForKey:@"url"] proxy:self];
if (url!=nil)
{
DebugLog(@"[WARN] The Ti.Window.url property is deprecated and will be remove on the next release");
// Window based JS can only be loaded from local filesystem within app resources
if ([url isFileURL] && [[[url absoluteString] lastPathComponent] hasSuffix:@".js"])
{
// since this function is recursive, only do this if we haven't already created the context
if (context==nil)
{
RELEASE_TO_NIL(context);
// remember our base url so we can restore on close
oldBaseURL = [[self _baseURL] retain];
// set our new base
[self _setBaseURL:url];
contextReady=NO;
context = [[KrollBridge alloc] initWithHost:[self _host]];
id theTabGroup = [tab tabGroup];
id theTab = (theTabGroup == nil)?nil:tab;
NSDictionary *values = [NSDictionary dictionaryWithObjectsAndKeys:self,@"currentWindow",theTabGroup,@"currentTabGroup",theTab,@"currentTab",nil];
NSDictionary *preload = [NSDictionary dictionaryWithObjectsAndKeys:values,@"UI",nil];
latch = [[TiUIWindowProxyLatch alloc] initWithTiWindow:self args:args];
[context boot:latch url:url preload:preload];
if ([latch waitForBoot])
{
if ([context evaluationError]) {
DebugLog(@"Could not boot context. Context has evaluation error");
return NO;
}
contextReady = YES;
return [super _handleOpen:args];
}
else
{
return NO;
}
}
}
else
{
DebugLog(@"[ERROR] Url not supported in a window. %@",url);
}
}
return [super _handleOpen:args];
}
-(void) windowDidClose
{
// Because other windows or proxies we have open and wish to continue functioning might be relying
// on our created context, we CANNOT explicitly shut down here. Instead we should memory-manage
// contexts better so they stop when they're no longer in use.
// Sadly, today is not that day. Without shutdown, we leak all over the place.
if (context!=nil) {
NSMutableArray* childrenToRemove = [[NSMutableArray alloc] init];
pthread_rwlock_rdlock(&childrenLock);
for (TiViewProxy* child in children) {
if ([child belongsToContext:context]) {
[childrenToRemove addObject:child];
}
}
pthread_rwlock_unlock(&childrenLock);
[context performSelector:@selector(shutdown:) withObject:nil afterDelay:1.0];
RELEASE_TO_NIL(context);
for (TiViewProxy* child in childrenToRemove) {
[self remove:child];
}
[childrenToRemove release];
}
[super windowDidClose];
}
-(BOOL)_handleClose:(id)args
{
if (oldBaseURL!=nil)
{
[self _setBaseURL:oldBaseURL];
}
RELEASE_TO_NIL(oldBaseURL);
return [super _handleClose:args];
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self willChangeSize];
}
- (void)viewWillAppear:(BOOL)animated; // Called when the view is about to made visible. Default does nothing
{
shouldUpdateNavBar = YES;
[self setupWindowDecorations];
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated; // Called when the view has been fully transitioned onto the screen. Default does nothing
{
[self updateTitleView];
[self updateHidesBarsOnSwipe];
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing
{
shouldUpdateNavBar = NO;
[self cleanupWindowDecorations];
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated; // Called after the view was dismissed, covered or otherwise hidden. Default does nothing
{
[super viewDidDisappear:animated];
}
#pragma mark - UINavController, NavItem UI
-(void)setNavTintColor:(id)colorString
{
NSString *color = [TiUtils stringValue:colorString];
[self replaceValue:color forKey:@"navTintColor" notification:NO];
TiThreadPerformOnMainThread(^{
if(controller != nil) {
TiColor * newColor = [TiUtils colorValue:color];
if (newColor == nil) {
//Get from TabGroup
newColor = [TiUtils colorValue:[[self tabGroup] valueForKey:@"navTintColor"]];
}
UINavigationBar * navBar = [[controller navigationController] navigationBar];
[navBar setTintColor:[newColor color]];
[self performSelector:@selector(refreshBackButton) withObject:nil afterDelay:0.0];
}
}, NO);
}
-(void)setBarColor:(id)colorString
{
ENSURE_UI_THREAD(setBarColor,colorString);
NSString *color = [TiUtils stringValue:colorString];
[self replaceValue:color forKey:@"barColor" notification:NO];
if (shouldUpdateNavBar && controller!=nil && [controller navigationController] != nil)
{
TiColor * newColor = [TiUtils colorValue:color];
if (newColor == nil)
{
newColor =[TiUtils colorValue:[[self tabGroup] valueForKey:@"barColor"]];
}
UIColor * barColor = [TiUtils barColorForColor:newColor];
UIBarStyle navBarStyle = [TiUtils barStyleForColor:newColor];
UINavigationBar * navBar = [[controller navigationController] navigationBar];
[navBar setBarStyle:navBarStyle];
[navBar setBarTintColor:barColor];
[self performSelector:@selector(refreshBackButton) withObject:nil afterDelay:0.0];
}
}
-(void)setTitleAttributes:(id)args
{
ENSURE_UI_THREAD(setTitleAttributes,args);
ENSURE_SINGLE_ARG_OR_NIL(args, NSDictionary);
[self replaceValue:args forKey:@"titleAttributes" notification:NO];
if (args == nil) {
args = [[self tabGroup] valueForUndefinedKey:@"titleAttributes"];
}
NSMutableDictionary* theAttributes = nil;
if (args != nil) {
theAttributes = [NSMutableDictionary dictionary];
if ([args objectForKey:@"color"] != nil) {
UIColor* theColor = [[TiUtils colorValue:@"color" properties:args] _color];
if (theColor != nil) {
[theAttributes setObject:theColor forKey:NSForegroundColorAttributeName];
}
}
if ([args objectForKey:@"shadow"] != nil) {
NSShadow* shadow = [TiUtils shadowValue:[args objectForKey:@"shadow"]];
if (shadow != nil) {
[theAttributes setObject:shadow forKey:NSShadowAttributeName];
}
}
if ([args objectForKey:@"font"] != nil) {
UIFont* theFont = [[TiUtils fontValue:[args objectForKey:@"font"] def:nil] font];
if (theFont != nil) {
[theAttributes setObject:theFont forKey:NSFontAttributeName];
}
}
if ([theAttributes count] == 0) {
theAttributes = nil;
}
}
if (shouldUpdateNavBar && ([controller navigationController] != nil)) {
[[[controller navigationController] navigationBar] setTitleTextAttributes:theAttributes];
}
}
-(void)updateBarImage
{
if (controller == nil || [controller navigationController] == nil || !shouldUpdateNavBar) {
return;
}
id barImageValue = [self valueForUndefinedKey:@"barImage"];
UINavigationBar* ourNB = [[controller navigationController] navigationBar];
UIImage* theImage = nil;
theImage = [TiUtils toImage:barImageValue proxy:self];
if (theImage == nil) {
[ourNB setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
} else {
UIImage* resizableImage = [theImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeStretch];
[ourNB setBackgroundImage:resizableImage forBarMetrics:UIBarMetricsDefault];
//You can only set up the shadow image with a custom background image.
id shadowImageValue = [self valueForUndefinedKey:@"shadowImage"];
theImage = [TiUtils toImage:shadowImageValue proxy:self];
if (theImage != nil) {
UIImage* resizableImage = [theImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0) resizingMode:UIImageResizingModeStretch];
ourNB.shadowImage = resizableImage;
} else {
BOOL clipValue = [TiUtils boolValue:[self valueForUndefinedKey:@"hideShadow"] def:NO];
if (clipValue) {
//Set an empty Image.
ourNB.shadowImage = [[[UIImage alloc] init] autorelease];
} else {
ourNB.shadowImage = nil;
}
}
}
}
-(void)setBarImage:(id)value
{
[self replaceValue:value forKey:@"barImage" notification:NO];
if (controller!=nil)
{
TiThreadPerformOnMainThread(^{[self updateBarImage];}, NO);
}
}
-(void)setShadowImage:(id)value
{
[self replaceValue:value forKey:@"shadowImage" notification:NO];
if (controller!=nil)
{
TiThreadPerformOnMainThread(^{[self updateBarImage];}, NO);
}
}
-(void)setHideShadow:(id)value
{
[self replaceValue:value forKey:@"hideShadow" notification:NO];
if (controller!=nil)
{
TiThreadPerformOnMainThread(^{[self updateBarImage];}, NO);
}
}
-(void)setTranslucent:(id)value
{
ENSURE_UI_THREAD(setTranslucent,value);
[self replaceValue:value forKey:@"translucent" notification:NO];
if (controller!=nil)
{
[controller navigationController].navigationBar.translucent = [TiUtils boolValue:value def:YES];
}
}
-(void)updateNavButtons
{
//Update LeftNavButton
NSDictionary* lProperties = [self valueForUndefinedKey:@"leftNavSettings"];
id leftNavButtons = [self valueForUndefinedKey:@"leftNavButtons"];
if (!IS_NULL_OR_NIL(leftNavButtons)) {
[self setLeftNavButtons:leftNavButtons withObject:lProperties];
} else {
leftNavButtons = [self valueForUndefinedKey:@"leftNavButton"];
[self setLeftNavButton:leftNavButtons withObject:lProperties];
}
//Update RightNavButton
NSDictionary* rProperties = [self valueForUndefinedKey:@"rightNavSettings"];
id rightNavButtons = [self valueForUndefinedKey:@"rightNavButtons"];
if (!IS_NULL_OR_NIL(rightNavButtons)) {
[self setRightNavButtons:rightNavButtons withObject:rProperties];
} else {
rightNavButtons = [self valueForUndefinedKey:@"rightNavButton"];
[self setRightNavButton:rightNavButtons withObject:rProperties];
}
}
-(void)refreshRightNavButtons:(id)unused
{
if (controller == nil || [controller navigationController] == nil) {
return; // No need to refresh
}
NSArray* theObjects = [self valueForUndefinedKey:@"rightNavButtons"];
NSDictionary* theProperties = [self valueForUndefinedKey:@"rightNavSettings"];
ENSURE_TYPE_OR_NIL(theObjects, NSArray);
ENSURE_TYPE_OR_NIL(theProperties, NSDictionary);
NSMutableArray* theItems = [[NSMutableArray alloc] init];
for (TiViewProxy* theProxy in theObjects) {
if ([theProxy supportsNavBarPositioning]) {
[theItems addObject:[theProxy barButtonItem]];
} else {
DebugLog(@"%@ does not support nav bar positioning", theProxy);
}
}
BOOL animated = [TiUtils boolValue:@"animated" properties:theProperties def:NO];
if ([theItems count] > 0) {
[controller.navigationItem setRightBarButtonItems:theItems animated:animated];
} else {
[controller.navigationItem setRightBarButtonItems:nil animated:animated];
}
[theItems release];
}
-(void)setRightNavButtons:(id)arg withObject:(id)properties
{
ENSURE_TYPE_OR_NIL(arg, NSArray);
ENSURE_TYPE_OR_NIL(properties, NSDictionary);
NSArray* curValues = [self valueForUndefinedKey:@"rightNavButtons"];
ENSURE_TYPE_OR_NIL(curValues, NSArray);
//Clean up current values
for (TiViewProxy* curProxy in curValues) {
if (![(NSArray*)arg containsObject:curProxy]) {
[curProxy removeBarButtonView];
[self forgetProxy:curProxy];
}
}
for(TiViewProxy* proxy in arg) {
if([proxy isKindOfClass:[TiViewProxy class]]) {
[self rememberProxy:proxy];
}
}
[self replaceValue:arg forKey:@"rightNavButtons" notification:NO];
[self replaceValue:properties forKey:@"rightNavSettings" notification:NO];
TiThreadPerformOnMainThread(^{
[self refreshRightNavButtons:nil];
}, NO);
}
-(void)setRightNavButton:(id)proxy withObject:(id)properties
{
[self replaceValue:proxy forKey:@"rightNavButton" notification:NO];
if (IS_NULL_OR_NIL(proxy)) {
[self setRightNavButtons:nil withObject:properties];
} else {
[self setRightNavButtons:[NSArray arrayWithObject:proxy] withObject:properties];
}
}
-(void)refreshLeftNavButtons:(id)unused
{
if (controller == nil || [controller navigationController] == nil) {
return; // No need to refresh
}
NSArray* theObjects = [self valueForUndefinedKey:@"leftNavButtons"];
NSDictionary* theProperties = [self valueForUndefinedKey:@"leftNavSettings"];
ENSURE_TYPE_OR_NIL(theObjects, NSArray);
ENSURE_TYPE_OR_NIL(theProperties, NSDictionary);
NSMutableArray* theItems = [[NSMutableArray alloc] init];
for (TiViewProxy* theProxy in theObjects) {
if ([theProxy supportsNavBarPositioning]) {
[theItems addObject:[theProxy barButtonItem]];
} else {
DebugLog(@"%@ does not support nav bar positioning", theProxy);
}
}
BOOL animated = [TiUtils boolValue:@"animated" properties:theProperties def:NO];
if ([theItems count] > 0) {
[controller.navigationItem setLeftBarButtonItems:theItems animated:animated];
} else {
[controller.navigationItem setLeftBarButtonItems:nil animated:animated];
}
[theItems release];
}
-(void)setLeftNavButtons:(id)arg withObject:(id)properties
{
ENSURE_TYPE_OR_NIL(arg, NSArray);
ENSURE_TYPE_OR_NIL(properties, NSDictionary);
NSArray* curValues = [self valueForUndefinedKey:@"leftNavButtons"];
ENSURE_TYPE_OR_NIL(curValues, NSArray);
//Clean up current values
for (TiViewProxy* curProxy in curValues) {
if (![(NSArray*)arg containsObject:curProxy]) {
[curProxy removeBarButtonView];
[self forgetProxy:curProxy];
}
}
for(TiViewProxy* proxy in arg) {
if([proxy isKindOfClass:[TiViewProxy class]]) {
[self rememberProxy:proxy];
}
}
[self replaceValue:arg forKey:@"leftNavButtons" notification:NO];
[self replaceValue:properties forKey:@"leftNavSettings" notification:NO];
TiThreadPerformOnMainThread(^{
[self refreshLeftNavButtons:nil];
}, NO);
}
-(void)setLeftNavButton:(id)proxy withObject:(id)properties
{
[self replaceValue:proxy forKey:@"leftNavButton" notification:NO];
if (IS_NULL_OR_NIL(proxy)) {
[self setLeftNavButtons:nil withObject:properties];
} else {
[self setLeftNavButtons:[NSArray arrayWithObject:proxy] withObject:properties];
}
}
-(void)setTabBarHidden:(id)value
{
[self replaceValue:value forKey:@"tabBarHidden" notification:NO];
TiThreadPerformOnMainThread(^{
if (controller != nil) {
[controller setHidesBottomBarWhenPushed:[TiUtils boolValue:value]];
}
}, NO);
}
-(void)hideTabBar:(id)value
{
[self setTabBarHidden:[NSNumber numberWithBool:YES]];
}
-(void)showTabBar:(id)value
{
[self setTabBarHidden:[NSNumber numberWithBool:NO]];
}
-(void)refreshBackButton
{
ENSURE_UI_THREAD_0_ARGS;
if (controller == nil || [controller navigationController] == nil) {
return; // No need to refresh
}
NSArray * controllerArray = [[controller navigationController] viewControllers];
NSUInteger controllerPosition = [controllerArray indexOfObject:controller];
if ((controllerPosition == 0) || (controllerPosition == NSNotFound))
{
return;
}
UIViewController * prevController = [controllerArray objectAtIndex:controllerPosition-1];
UIBarButtonItem * backButton = nil;
UIImage * backImage = [TiUtils image:[self valueForKey:@"backButtonTitleImage"] proxy:self];
if (backImage != nil)
{
backButton = [[UIBarButtonItem alloc] initWithImage:backImage style:UIBarButtonItemStylePlain target:nil action:nil];
}
else
{
NSString * backTitle = [TiUtils stringValue:[self valueForKey:@"backButtonTitle"]];
if ((backTitle == nil) && [prevController isKindOfClass:[TiViewController class]])
{
id tc = [(TiViewController*)prevController proxy];
backTitle = [TiUtils stringValue:[tc valueForKey:@"title"]];
}
if (backTitle != nil)
{
backButton = [[UIBarButtonItem alloc] initWithTitle:backTitle style:UIBarButtonItemStylePlain target:nil action:nil];
}
}
[[prevController navigationItem] setBackBarButtonItem:backButton];
[backButton release];
}
-(void)setBackButtonTitle:(id)proxy
{
ENSURE_UI_THREAD_1_ARG(proxy);
[self replaceValue:proxy forKey:@"backButtonTitle" notification:NO];
if (controller!=nil)
{
[self refreshBackButton]; //Because this is actually a property of a DIFFERENT view controller,
//we can't attach this until we're in the navbar stack.
}
}
-(void)setBackButtonTitleImage:(id)proxy
{
ENSURE_UI_THREAD_1_ARG(proxy);
[self replaceValue:proxy forKey:@"backButtonTitleImage" notification:NO];
if (controller!=nil)
{
[self refreshBackButton]; //Because this is actually a property of a DIFFERENT view controller,
//we can't attach this until we're in the navbar stack.
}
}
-(void)updateNavBar
{
//Called from the view when the screen rotates.
//Resize titleControl and barImage based on navbar bounds
if (!shouldUpdateNavBar || controller == nil || [controller navigationController] == nil) {
return; // No need to update the title if not in a nav controller
}
TiThreadPerformOnMainThread(^{
if ([[self valueForKey:@"titleControl"] isKindOfClass:[TiViewProxy class]]) {
[self updateTitleView];
}
}, NO);
}
-(void)updateTitleView
{
UIView * newTitleView = nil;
if (!shouldUpdateNavBar || controller == nil || [controller navigationController] == nil) {
return; // No need to update the title if not in a nav controller
}
UINavigationItem * ourNavItem = [controller navigationItem];
UINavigationBar * ourNB = [[controller navigationController] navigationBar];
CGRect barFrame = [ourNB bounds];
CGSize availableTitleSize = CGSizeZero;
availableTitleSize.width = barFrame.size.width - (2*TI_NAVBAR_BUTTON_WIDTH);
availableTitleSize.height = barFrame.size.height;
//Check for titlePrompt. Ugly hack. Assuming 50% for prompt height.
if (ourNavItem.prompt != nil) {
availableTitleSize.height /= 2.0f;
barFrame.origin.y = barFrame.size.height = availableTitleSize.height;
}
TiViewProxy * titleControl = [self valueForKey:@"titleControl"];
UIView * oldView = [ourNavItem titleView];
if ([oldView isKindOfClass:[TiUIView class]]) {
TiViewProxy * oldProxy = (TiViewProxy *)[(TiUIView *)oldView proxy];
if (oldProxy == titleControl) {
//relayout titleControl
CGRect barBounds;
barBounds.origin = CGPointZero;
#ifndef TI_USE_AUTOLAYOUT
barBounds.size = SizeConstraintViewWithSizeAddingResizing(titleControl.layoutProperties, titleControl, availableTitleSize, NULL);
#endif
[TiUtils setView:oldView positionRect:[TiUtils centerRect:barBounds inRect:barFrame]];
[oldView setAutoresizingMask:UIViewAutoresizingNone];
//layout the titleControl children
[titleControl layoutChildren:NO];
return;
}
[oldProxy removeBarButtonView];
}
if ([titleControl isKindOfClass:[TiViewProxy class]])
{
newTitleView = [titleControl barButtonViewForSize:availableTitleSize];
}
else
{
NSURL * path = [TiUtils toURL:[self valueForKey:@"titleImage"] proxy:self];
//Todo: This should be [TiUtils navBarTitleViewSize] with the thumbnail scaling. For now, however, we'll go with auto.
UIImage *image = [[ImageLoader sharedLoader] loadImmediateImage:path withSize:CGSizeZero];
if (image!=nil) {
if ([oldView isKindOfClass:[UIImageView class]]) {
[(UIImageView*)oldView setImage:image];
newTitleView = oldView;
} else {
newTitleView = [[[UIImageView alloc] initWithImage:image] autorelease];
}
}
}
if (oldView != newTitleView) {
[ourNavItem setTitleView:newTitleView];
}
}
-(void)setTitleControl:(id)proxy
{
ENSURE_UI_THREAD(setTitleControl,proxy);
[self replaceValue:proxy forKey:@"titleControl" notification:NO];
if (controller!=nil)
{
[self updateTitleView];
}
}
-(void)setTitleImage:(id)image
{
ENSURE_UI_THREAD(setTitleImage,image);
NSURL *path = [TiUtils toURL:image proxy:self];
[self replaceValue:[path absoluteString] forKey:@"titleImage" notification:NO];
if (controller!=nil)
{
[self updateTitleView];
}
}
-(void)setTitle:(NSString*)title_
{
NSString *title = [TiUtils stringValue:title_];
[self replaceValue:title forKey:@"title" notification:NO];
TiThreadPerformOnMainThread(^{
if (shouldUpdateNavBar && controller != nil && [controller navigationController] != nil) {
controller.navigationItem.title = title;
}
}, [NSThread isMainThread]);
}
-(void)setTitlePrompt:(NSString*)title_
{
ENSURE_UI_THREAD(setTitlePrompt,title_);
NSString *title = [TiUtils stringValue:title_];
[self replaceValue:title forKey:@"titlePrompt" notification:NO];
if (controller!=nil && [controller navigationController] != nil)
{
controller.navigationItem.prompt = title;
}
}
-(void)setToolbar:(id)items withObject:(id)properties
{
ENSURE_TYPE_OR_NIL(items,NSArray);
if (properties == nil)
{
properties = [self valueForKey:@"toolbarSettings"];
}
else
{
[self setValue:properties forKey:@"toolbarSettings"];
}
NSArray * oldarray = [self valueForUndefinedKey:@"toolbar"];
if((id)oldarray == [NSNull null])
{
oldarray = nil;
}
for(TiViewProxy * oldProxy in oldarray)
{
if(![items containsObject:oldProxy])
{
[self forgetProxy:oldProxy];
}
}
for (TiViewProxy *proxy in items)
{
[self rememberProxy:proxy];
}
[self replaceValue:items forKey:@"toolbar" notification:NO];
TiThreadPerformOnMainThread( ^{
if (shouldUpdateNavBar && controller!=nil && [controller navigationController] != nil)
{
NSArray *existing = [controller toolbarItems];
UINavigationController * ourNC = [controller navigationController];
if (existing!=nil)
{
for (id current in existing)
{
if ([current respondsToSelector:@selector(proxy)])
{
TiViewProxy* p = (TiViewProxy*)[current performSelector:@selector(proxy)];
[p removeBarButtonView];
}
}
}
NSMutableArray * array = [[NSMutableArray alloc] initWithObjects:nil];
for (TiViewProxy *proxy in items)
{
if([proxy supportsNavBarPositioning])
{
UIBarButtonItem *item = [proxy barButtonItem];
[array addObject:item];
}
}
hasToolbar = (array != nil && [array count] > 0) ? YES : NO ;
BOOL translucent = [TiUtils boolValue:@"translucent" properties:properties def:YES];
BOOL animated = [TiUtils boolValue:@"animated" properties:properties def:hasToolbar];
TiColor* toolbarColor = [TiUtils colorValue:@"barColor" properties:properties];
UIColor* barColor = [TiUtils barColorForColor:toolbarColor];
[controller setToolbarItems:array animated:animated];
[ourNC setToolbarHidden:(hasToolbar == NO ? YES : NO) animated:animated];
[ourNC.toolbar setTranslucent:translucent];
UIColor* tintColor = [[TiUtils colorValue:@"tintColor" properties:properties] color];
[ourNC.toolbar setBarTintColor:barColor];
[ourNC.toolbar setTintColor:tintColor];
[array release];
}
},YES);
}
-(void)setHidesBarsOnSwipe:(id)value
{
[self replaceValue:value forKey:@"hidesBarsOnSwipe" notification:NO];
[self updateHidesBarsOnSwipe];
}
-(void)updateHidesBarsOnSwipe
{
if ([TiUtils isIOS8OrGreater]) {
TiThreadPerformOnMainThread(^{
if ((controller != nil) && ([controller navigationController] != nil)) {
UINavigationController * ourNC = [controller navigationController];
ourNC.hidesBarsOnSwipe = [TiUtils boolValue:[self valueForUndefinedKey:@"hidesBarsOnSwipe"] def:NO];
}
}, NO);
}
}
#define SETPROP(m,x) \
{\
id value = [self valueForKey:m]; \
if (value!=nil)\
{\
[self x:(value==[NSNull null]) ? nil : value];\
}\
else{\
[self replaceValue:nil forKey:m notification:NO];\
}\
}\
#define SETPROPOBJ(m,x) \
{\
id value = [self valueForKey:m]; \
if (value!=nil)\
{\
if ([value isKindOfClass:[TiComplexValue class]])\
{\
TiComplexValue *cv = (TiComplexValue*)value;\
[self x:(cv.value==[NSNull null]) ? nil : cv.value withObject:cv.properties];\
}\
else\
{\
[self x:(value==[NSNull null]) ? nil : value withObject:nil];\
}\
}\
else{\
[self replaceValue:nil forKey:m notification:NO];\
}\
}\
-(void)setupWindowDecorations
{
if ((controller == nil) || ([controller navigationController] == nil)) {
return;
}
[[controller navigationController] setToolbarHidden:!hasToolbar animated:YES];
//Need to clear title for titleAttributes to apply correctly on iOS6.
[[controller navigationItem] setTitle:nil];
SETPROP(@"titleAttributes",setTitleAttributes);
SETPROP(@"title",setTitle);
SETPROP(@"titlePrompt",setTitlePrompt);
[self updateTitleView];
SETPROP(@"barColor",setBarColor);
SETPROP(@"navTintColor",setNavTintColor);
SETPROP(@"translucent",setTranslucent);
SETPROP(@"tabBarHidden",setTabBarHidden);
SETPROP(@"hidesBarsOnSwipe",setTabBarHidden);
SETPROPOBJ(@"toolbar",setToolbar);
[self updateBarImage];
[self updateNavButtons];
[self refreshBackButton];
}
-(void)cleanupWindowDecorations
{
if ((controller == nil) || ([controller navigationController] == nil)) {
return;
}
NSArray* curValues = [self valueForUndefinedKey:@"leftNavButtons"];
ENSURE_TYPE_OR_NIL(curValues, NSArray);
for (TiViewProxy* curProxy in curValues) {
[curProxy removeBarButtonView];
}
NSArray* curValues2 = [self valueForUndefinedKey:@"rightNavButtons"];
ENSURE_TYPE_OR_NIL(curValues2, NSArray);
for (TiViewProxy* curProxy in curValues2) {
[curProxy removeBarButtonView];
}
if (barImageView != nil) {
[barImageView removeFromSuperview];
}
}
@end
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment