i am working on splitviewcontroller in window based application
im writing code as follows but didselect not working
in LeftViewController.h:
#import <UIKit/UIKit.h>
#class RightViewController;
#interface LeftViewController : UITableViewController
{
RightViewController *details;
}
#property (retain, nonatomic) NSNumber *detailItem;
#end
InLeftviewController.m: didselectmethod:
- (void)tableView:(UITableView *)tableView didDeSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
RightViewController *rightViewController = [[RightViewController alloc] initWithNibName:#"RightViewController" bundle:nil];
[self.navigationController pushViewController:rightViewController animated:YES];
NSUInteger item = [indexPath row];
rightViewController.detailItem = [NSNumber numberWithInteger:item];
rightViewController.detailItem = detailItem;
NSLog(#"detailItem= %# , %#", detailItem,rightViewController.detailItem );
int i = [detailItem intValue];
if(detailItem == [NSNumber numberWithInt:0])
{
//Adding label to the details view
UILabel *infoLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 5, 450, 150)];
infoLabel.text = #"Customer:Barrick Gold\r\nMine:Turquiose Ridge Mine \r\nLocation:Mesa, AZ";
[rightViewController.view addSubview:infoLabel];
//Adding table view to the details view
UITableView *mapTable = [[UITableView alloc]initWithFrame:CGRectMake(165, 5, 450,150) style:UITableViewStyleGrouped];
[rightViewController.view addSubview:mapTable];
}
if(item == 1)
{
UILabel *infoLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 5, 450, 150)];
infoLabel.text = #"Eqipement";
[rightViewController.view addSubview:infoLabel];
}
if(i == 2)
{
}
}
in RightViewController.h:
#interface RightViewController : UIViewController
{
}
#property (retain, nonatomic) NSNumber *detailItem;
in RightViewController.m :
#import "RightViewController.h"
#import "LeftViewController.h"
#implementation RightViewController
#synthesize detailItem;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)configureView
{
if (self.detailItem)
{
[self viewDidLoad];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//set a background color Just to recognize the layout of the View
self.view.backgroundColor = [UIColor redColor];
// To display Tiltle & EditButton on the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.title= #"Customer Name";
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)setDetailItem:(NSNumber *)newDetailItem
{
//LeftViewController *left = [[LeftViewController alloc]initWithNibName:#"LeftViewController" bundle:nil];
int i = [detailItem intValue];
NSLog(#"Config item %d",i);
if( detailItem == [NSNumber numberWithInt:0])
{
NSLog(#"Configure item at row 1 %#",detailItem);
//Adding label to the view
UILabel *infoLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 5, 450, 150)];
infoLabel.text = #"Customer:Barrick Gold\r\nMine:Turquiose Ridge Mine \r\nLocation:Mesa, AZ";
[self.view addSubview:infoLabel];
//Adding table view to the view.
UITableView *mapTable = [[UITableView alloc]initWithFrame:CGRectMake(165, 5, 450,150) style:UITableViewStyleGrouped];
[self.view addSubview:mapTable];
}
if( detailItem == [NSNumber numberWithInt:1])
{
NSLog(#"Config item at row 2 %#",detailItem);
}
if( self.detailItem == [NSNumber numberWithInt:2])
{
NSLog(#"Config item at row 3 %#",detailItem);
}
if (detailItem != newDetailItem)
{
[detailItem release];
detailItem = [newDetailItem retain];
[self configureView];
}
else
{
[self configureView];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
I am not sure what you are trying here. If the LeftViewController and RightViewController are the master and detail views of the split view then why are you trying to push the detail view from the master view. The function of the split view is to show the details of the selected item in the master view(left view) on the detail view on the right side(detail view). So why would you bother pushing that view in the master view. All you have to do is to set the detail item for the DetailViewController.
Try to add the line at the end of didSelect method of tableview in leftView controller[self.navigationController pushViewController:rightViewController animated:YES];
Related
Sounds like a question that has been answered... maybe but i have checked all of the possible solutions i believe and nothing will work for me.
My .h file looks like this
#import <UIKit/UIKit.h>
#interface epsMenuPage : UIViewController<UITableViewDelegate,UITableViewDataSource>{
NSArray *listData;
...
UITableView *menuList;
...
}
#property (nonatomic,retain) NSArray *listData;
...
#property (nonatomic, retain) IBOutlet UITableView *menuList;
...
#end
My .m file looks like this
#implementation epsMenuPage
#synthesize listData;
...
#synthesize menuList;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
//Arrays credit,debit and both
creditListData = [[NSArray alloc]initWithObjects:#"Return",#"Force Sale",#"Authorize Only",#"Total Sales",#"Items Sold",#"Reciept's", nil];
debitListData = [[NSArray alloc]initWithObjects:#"Return",#"Force Sale",#"Authorize Only",#"Total Sales",#"Items Sold",#"Reciept's", nil];
bothListData = [[NSArray alloc]initWithObjects:#"Batch History",#"Settle Batch", nil];
self.listData = creditListData;
[menuList reloadData];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.view.backgroundColor =[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0];
[colorChange setBackgroundColor:[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0]];
[self.view addSubview:creditTabButton];
[self.view addSubview:debitTabButton];
[self.view addSubview:bothTabButton];
[self.view addSubview:creditButtonText];
[self.view addSubview:debitButtonText];
[self.view addSubview:bothBottonText];
[self.view addSubview:colorChange];
}
- (void)viewDidUnload
{
[self setTitleBAckButton:nil];
[self setTitleSettingsButton:nil];
[self setCreditTabButton:nil];
[self setDebitTabButton:nil];
[self setBothTabButton:nil];
[self setMenuList:nil];
[self setColorChange:nil];
[self setCreditButtonText:nil];
[self setDebitButtonText:nil];
[self setBothBottonText:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"tableID";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [self.listData objectAtIndex:row];
return cell;
}
- (void)dealloc {
[titleBAckButton release];
[titleSettingsButton release];
[creditTabButton release];
[debitTabButton release];
[bothTabButton release];
[menuList release];
[colorChange release];
[creditButtonText release];
[debitButtonText release];
[bothBottonText release];
[listData release];
[super dealloc];
}
- (IBAction)titleBackClick:(id)sender {
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
- (IBAction)titleSettingsClick:(id)sender {
}
- (IBAction)creditTabClick:(id)sender {
self.listData = creditListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0]];
[self.view addSubview:creditTabButton];
[self.view addSubview:creditButtonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:255/255.0 green:95/255.0 blue:95/255.0 alpha:1.0];
}
- (IBAction)debitTabClick:(id)sender {
self.listData = debitListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:244/255.0 green:133/255.0 blue:33/255.0 alpha:1.0]];
[self.view addSubview:debitTabButton];
[self.view addSubview:debitButtonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:244/255.0 green:133/255.0 blue:33/255.0 alpha:1.0];
}
- (IBAction)bothTabClick:(id)sender {
self.listData = bothListData;
[menuList reloadData];
[colorChange setBackgroundColor:[UIColor colorWithRed:72/255.0 green:72/255.0 blue:255/255.0 alpha:1.0]];
[self.view addSubview:bothTabButton];
[self.view addSubview:bothBottonText];
[self.view addSubview:colorChange];
self.view.backgroundColor = [UIColor colorWithRed:72/255.0 green:72/255.0 blue:255/255.0 alpha:1.0];
}
#end
I really for the life of me can not figure out why it wont display to my TableView, i have tried so many different tutorials.
any help is greatly appreciated.
You're never adding the menuList table view to your view. Add it and see if that does the trick:
// In -viewDidLoad
[self.view addSubview:menuList];
EDIT 1: Did you declare properties in your .h? These aren't visible, so it appears as if you're not creating or adding your table view to the view controller's view. However, if you are using IBOutlets, then this probably isn't the issue.
EDIT 2: From the comments below, your dataSource is nil, which is exactly why nothing is being displayed. Make sure your table view in Interface Builder has its dataSource outlet pointing to your view controller. To be double sure, delete the table view from Interface Builder and add it back again. Make sure your connections are exactly right. Also try cleaning the project and rebuilding, as well as restarting Xcode.
It looks like you are missing the required datasource method:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; {
return 1;
}
Also, it looks like you are not actually initializing your UIButton's, or anything you are adding as a subview. Are you using a nib?
Is there something that I need to remember when using the windows-based template? Because I'm unclear as to why the tabs are showing up but nothing in the views are showing up.
Could you help? Because I've been searching through previous questions for a few hours now and I still haven't found anything to clear this up.
AnotherMadeUpAppDelegate.h
#import <UIKit/UIKit.h>
#import "AnotherMadeUpViewController.h"
#interface AnotherMadeUpAppDelegate : NSObject <UIApplicationDelegate> {
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
AnotherMadeUpAppDelegate.m
#import "AnotherMadeUpAppDelegate.h"
#implementation AnotherMadeUpAppDelegate
#synthesize window=_window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UIViewController *vc1 = [[UIViewController alloc] init];
UIViewController *vc2 = [[UIViewController alloc] init];
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] init];
UITabBarController *tbc = [[UITabBarController alloc] init];
tbc.viewControllers = [NSArray arrayWithObjects:vc1, vc2, vc3, nil];
[vc1 release];
[vc2 release];
[vc3 release];
[self.window addSubview:tbc.view];
[self.window makeKeyAndVisible];
return YES;
}
...
#end
AnotherMadeUpViewController.h
#import <UIKit/UIKit.h>
#interface AnotherMadeUpViewController : UIViewController<UIScrollViewDelegate>
{
IBOutlet UIPageControl *pageControl;
IBOutlet UIScrollView *scroller;
IBOutlet UILabel *label;
}
#property (nonatomic,retain)IBOutlet UIPageControl *pageControl;
#property (nonatomic,retain)IBOutlet UIScrollView *scroller;
#property (nonatomic,retain)IBOutlet UILabel *label;
-(IBAction)clickPageControl:(id)sender;
#end
AnotherMadeUpViewController.m
#import "AnotherMadeUpViewController.h"
#implementation AnotherMadeUpViewController
#synthesize pageControl,scroller,label;
-(IBAction)clickPageControl:(id)sender
{
int page=pageControl.currentPage;
CGRect frame=scroller.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scroller scrollRectToVisible:frame animated:YES];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int page = scrollView.contentOffset.x/scrollView.frame.size.width;
pageControl.currentPage=page;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
[label release];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
scroller.pagingEnabled=YES;
CGFloat labelOriginX = label.frame.origin.x;
CGFloat labelOriginY = label.frame.origin.y;
CGFloat scrollWidth = 0;
int pageNumber = 0;
for (int i=0; i<9; i++)
{
CGRect rect = label.frame;
rect.size.height = label.frame.size.height;
rect.size.width = label.frame.size.width;
rect.origin.x = labelOriginX + scrollWidth;
rect.origin.y = labelOriginY;
label.frame = rect;
label.text = [NSString stringWithFormat:#"%d", pageNumber];
label.textColor = [UIColor redColor];
[scroller addSubview:label];
pageNumber++;
scrollWidth += scroller.frame.size.width;
}
scroller.delegate=self;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
pageControl.numberOfPages=9;
pageControl.currentPage=0;
scroller.contentSize=CGSizeMake(pageControl.numberOfPages*self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:scroller];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[label release];
self.label = nil;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Dissecting your viewDidLoad –
scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height)];
You seem to be creating a new scroll view instance here but you have declared it as an outlet. If you don't have an outlet then remove the IBOutlet tag for scroller. If you do have one and want to use it then remove the above line. A shorter way of doing it would be,
scroller = [[UIScrollView alloc] initWithFrame:self.view.bounds];
Another thing is that you are creating 10 labels but assigning no frame. To show one of them each in different page,
int pageNumber = 0;
for (int i = 0; i < 10; i++)
{
UILabel *label = [[UILabel alloc] init];
[label sizeToFit];
label.center = CGPointMake (((2 * i + 1) * self.view.frame.size.width) / 2, self.view.frame.size.height / 2);
label.text = [NSString stringWithFormat:#"%d", pageNumber];
[scroller addSubview:label];
[label release];
pageNumber++;
}
and later set the contentSize to show 10 pages,
scroller.contentSize = CGSizeMake(10 * self.view.frame.size.width, self.view.frame.size.height);
The problem is with this line
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] init];
You need to change it to
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] initWithNibName:#"AnotherMadeUpViewController" bundle:nil];
Then your .xib will get loaded and your outlets will be connected.
And don't forget to connect your outlets to File's owner in IB.
The iOS app I'm currently working on is tabbar-based, and one of the tab is a UITableViewController.
The thing is, when I open this tab with an empty datasource (for whatever reason), I'd like to bring another view, with some kind of message/image, instead of the blank view I get with the tableviewcontroller.
I tried something like that :
- (void)viewWillAppear:(BOOL)animated {
if ([myData count] == 0) {
if (!emptyView) {
emptyView = [[UIView alloc] initWithFrame:self.view.frame];
UILabel *emptyMsg = [[UILabel alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height / 2, self.view.frame.size.width, 20)];
emptyMsg.text = #"This is Empty !";
emptyMsg.textAlignment = UITextAlignmentCenter;
[emptyView addSubview:emptyMsg];
}
[self.view insertSubview:emptyView atIndex:0];
}
else {
if (emptyView != nil) { [emptyView removeFromSuperview]; emptyView = nil; }
[self.tableView reloadData];
[super viewWillAppear:animated];
}
}
With emptyView defined as an iVar in the view controller.
But It doesn't work as expected, and I can't find the reason :/
Could any of you give it a look and give me the proper way to do this kind of behavior ?
Thanks,
I solved this problem by adding a UIView in the tableview header with a frame size equal to tableview size and disallowing user interaction on the tableview:
UIView *emptyView = [[UIView alloc] initWithFrame:self.tableView.frame];
/* Customize your view here or load it from a NIB */
self.tableView.tableHeaderView = emptyView;
self.tableView.userInteractionEnabled = NO;
When you have data you just remove the header and reenable user interaction:
self.tableView.tableHeaderView = nil;
self.tableView.userInteractionEnabled = YES;
UITableViewController doesn't allow you to add subviews to it's view (the tableView).
You should make a UIViewController and add the UITableView yourself with your optional emptyView.
Don't forget to set the dataSource and the delegate!
Update : I've made a subclass of UIViewController to avoid mimics UITableViewController every time.
.h
//
// GCTableViewController.h
// GCLibrary
//
// Created by Guillaume Campagna on 10-06-17.
// Copyright 2010 LittleKiwi. All rights reserved.
//
#import <UIKit/UIKit.h>
//Subclass of UIViewController that mimicks the UITableViewController except that the tableView is a subview of self.view and allow change of the frame of the tableView
#interface GCTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, readonly) UITableView *tableView;
- (id) initWithStyle:(UITableViewStyle)style;
//Subclass if you want to change the type of tableView. The tableView will be automatically placed later
- (UITableView*) tableViewWithStyle:(UITableViewStyle) style;
#end
.m
//
// GCTableViewController.m
// GCLibrary
//
// Created by Guillaume Campagna on 10-06-17.
// Copyright 2010 LittleKiwi. All rights reserved.
//
#import "GCTableViewController.h"
#implementation GCTableViewController
#synthesize tableView;
- (id) initWithStyle:(UITableViewStyle) style {
if (self = [super initWithNibName:nil bundle:nil]) {
tableView = [[self tableViewWithStyle:style] retain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
self.tableView.frame = self.view.bounds;
self.tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
#pragma mark TableView methods
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return 0;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
#pragma mark Getter
- (UITableView *) tableViewWithStyle:(UITableViewStyle)style {
return [[[UITableView alloc] initWithFrame:CGRectZero style:style] autorelease];
}
- (void)dealloc {
[tableView release];
tableView = nil;
[super dealloc];
}
#end
You could perhaps try setting the number of rows to zero. Then inserting the no results view as the header view.
I have an TabBar app that I would like to be in landscape and portrait. The issue is when I go to tab 2 make a selection from my table then select tab 1 and rotate the device, then select tab 2 again the content does not know that the device rotated and will not display my custom orientated content correctly. I am trying to write a priovate method that tells the view what orientation it is currently in. IN viewDidLoad I am assuming it is in portrait but in shouldAutoRotate I have it looking in the private method for the correct alignment of the content. Please Help!! Here is my code:
#import "DetailViewController.h"
#import "ScheduleTableViewController.h"
#import "BrightcoveDemoAppDelegate.h"
#import "Constants.h"
#implementation DetailViewController
#synthesize CurrentLevel, CurrentTitle, tableDataSource,logoName,showDescription,showDescriptionInfo,showTime, showTimeInfo, tableBG;
- (void)layoutSubviews {
showLogo.frame = CGRectMake(40, 20, 187, 101);
showDescription.frame = CGRectMake(85, 140, 330, 65);
showTime.frame = CGRectMake(130, 10, 149, 119);
tableBG.frame = CGRectMake(0, 0, 480, 320);
}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = CurrentTitle;
[showDescription setEditable:NO];
//show the description
showDescription.text = showDescriptionInfo;
showTime.text = showTimeInfo;
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *ImagePath = [Path stringByAppendingPathComponent:logoName];
UIImage *tempImg = [[UIImage alloc] initWithContentsOfFile:ImagePath];
[showLogo setImage:tempImg];
[tempImg release];
[self masterView];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
isLandscape = UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
if(isLandscape = YES){
[self layoutSubviews];
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[logoName release];
[showLogo release];
[showDescription release];
[showDescriptionInfo release];
[super dealloc];
}
#end
I believe that you need to pass the -shouldAutorotateToInterfaceOrientation: method to each view controller. You could do something like this in your UITabBarController:
- ( BOOL )shouldAutorotateToInterfaceOrientation:( UIInterfaceOrientation )
interfaceOrientation
{
for ( UIViewController *viewController in [ self viewControllers ])
[ viewController
shouldAutorotateToInterfaceOrientation:interfaceOrientation ];
return YES;
}
I use a UISearchBar for entering an address to establish a network connection. While the connection is made I want to show the activity indicator instead of the tiny BookmarkButton on the right side of the searchbar. As far as I can see there is no public declared property that would give me access to the correct subview of the searchbar. I have seen this been done, any thoughts?
How about replacing the search icon on the left side with an activity indicator while searches or connections are in progress?
SearchBarWithActivity.h:
#import <UIKit/UIKit.h>
#interface SearchBarWithActivity : UISearchBar
- (void)startActivity; // increments startCount and shows activity indicator
- (void)finishActivity; // decrements startCount and hides activity indicator if 0
#end
SearchBarWithActivity.m:
#import "SearchBarWithActivity.h"
#interface SearchBarWithActivity()
#property(nonatomic) UIActivityIndicatorView *activityIndicatorView;
#property(nonatomic) int startCount;
#end
#implementation SearchBarWithActivity
- (void)layoutSubviews {
UITextField *searchField = nil;
for(UIView* view in self.subviews){
if([view isKindOfClass:[UITextField class]]){
searchField= (UITextField *)view;
break;
}
}
if(searchField) {
if (!self.activityIndicatorView) {
UIActivityIndicatorView *taiv = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
taiv.center = CGPointMake(searchField.leftView.bounds.origin.x + searchField.leftView.bounds.size.width/2,
searchField.leftView.bounds.origin.y + searchField.leftView.bounds.size.height/2);
taiv.hidesWhenStopped = YES;
taiv.backgroundColor = [UIColor whiteColor];
self.activityIndicatorView = taiv;
[taiv release];
_startCount = 0;
[searchField.leftView addSubview:self.activityIndicatorView];
}
}
[super layoutSubviews];
}
- (void)startActivity {
self.startCount = self.startCount + 1;
}
- (void)finishActivity {
self.startCount = self.startCount - 1;
}
- (void)setStartCount:(int)startCount {
_startCount = startCount;
if (_startCount > 0)
[self.activityIndicatorView startAnimating];
else {
[self.activityIndicatorView stopAnimating];
}
}
#end
I updated the answer from #JohnLemberger to work with iOS 7 (note: I've only tested this on iOS 7), as well as a summary of my changes:
NOTE: this is not very robust code to begin with, since Apple can change the view hierarchy of UISearchBar in any release (as they did between iOS 6 and 7).
SearchBarWithActivity.h (nothing changed):
#interface SearchBarWithActivity : UISearchBar
- (void)startActivity; // increments startCount and shows activity indicator
- (void)finishActivity; // decrements startCount and hides activity indicator if 0
#end
#interface XXTreatmentHeaderViewController : XXViewController
#property (nonatomic, strong, readonly) SearchBarWithActivity *searchBar;
#end
SearchBarWithActivity.m:
1) Show/hide the "magnifying glass" icon when the activity indicator appears
2) Add depth in the view hierarchy search for the UITextField
#interface SearchBarWithActivity()
#property(nonatomic) UIActivityIndicatorView *activityIndicatorView;
#property(nonatomic) int startCount;
#end
#implementation SearchBarWithActivity
- (void)layoutSubviews {
UITextField *searchField = nil;
for(UIView* view in self.subviews){
// on iOS 6, the UITextField is one-level deep
if ([view isKindOfClass:[UITextField class]]){
searchField= (UITextField *)view;
break;
}
// on iOS 7, the UITextField is two-levels deep
for (UIView *secondLevelSubview in view.subviews) {
if([secondLevelSubview isKindOfClass:[UITextField class]]){
searchField= (UITextField *)secondLevelSubview;
break;
}
}
}
if(searchField) {
if (!self.activityIndicatorView) {
UIActivityIndicatorView *taiv = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
taiv.center = CGPointMake(searchField.leftView.bounds.origin.x + searchField.leftView.bounds.size.width/2,
searchField.leftView.bounds.origin.y + searchField.leftView.bounds.size.height/2);
taiv.hidesWhenStopped = YES;
self.activityIndicatorView = taiv;
_startCount = 0;
[searchField.leftView addSubview:self.activityIndicatorView];
}
}
[super layoutSubviews];
}
- (void)startActivity {
self.startCount = self.startCount + 1;
}
- (void)finishActivity {
self.startCount = self.startCount - 1;
}
- (void)setStartCount:(int)startCount {
_startCount = startCount;
if (_startCount > 0) {
[self.activityIndicatorView startAnimating];
// Remove the "magnifying glass icon"
[self setImage:[UIImage new] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
} else {
[self.activityIndicatorView stopAnimating];
// Restore the "magnifying glass icon"
[self setImage:nil forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
}
}
#end
I have implemented a category for UISearchBar that shows a UIActivityIndicatorView, depending on state of a AFNetworking's request operation or session task https://gist.github.com/nguyenhuy/a11d15c11200477b05a6.
Just for the record:
for(UIView* view in self.subviews){
if([view isKindOfClass:[UITextField class]]){
searchField=view;
break;
}
}
if(searchField !=)) {
searchField.leftView = myCustomView;
}
You can subclass UISearchBar and call this code in the layoutSubview method. calling this code in layoutSubview makes sure that resize animations work properly.
I update jonsibley's answer by adding support for the cases where a UISearchBar is embedded in a UINavigationBar using the displaysSearchBarInNavigationBar flag.
SearchBarWithActivity.h (added a new property):
#interface SearchBarWithActivity : UISearchBar
- (void)startActivity; // increments startCount and shows activity indicator
- (void)finishActivity; // decrements startCount and hides activity indicator if 0
#property (nonatomic,assign) UINavigationItem *navigationItem;
#end
SearchBarWithActivity.m (get the searchField from the navigationItem if not nil):
#import "SearchBarWithActivity.h"
#interface SearchBarWithActivity()
#property(nonatomic) UIActivityIndicatorView *activityIndicatorView;
#property(nonatomic) int startCount;
#end
#implementation SearchBarWithActivity
#synthesize navigationItem;
- (void)layoutSubviews {
UITextField *searchField = nil;
if(self.navigationItem) {
searchField = (UITextField *)[self.navigationItem titleView];
} else {
for(UIView* view in self.subviews){
// on iOS 6, the UITextField is one-level deep
if ([view isKindOfClass:[UITextField class]]){
searchField= (UITextField *)view;
break;
}
// on iOS 7, the UITextField is two-levels deep
for (UIView *secondLevelSubview in view.subviews) {
if([secondLevelSubview isKindOfClass:[UITextField class]]){
searchField= (UITextField *)secondLevelSubview;
break;
}
}
}
}
if(searchField) {
if (!self.activityIndicatorView) {
UIActivityIndicatorView *taiv = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
taiv.center = CGPointMake(searchField.leftView.bounds.origin.x + searchField.leftView.bounds.size.width/2,
searchField.leftView.bounds.origin.y + searchField.leftView.bounds.size.height/2);
taiv.hidesWhenStopped = YES;
self.activityIndicatorView = taiv;
_startCount = 0;
[searchField.leftView addSubview:self.activityIndicatorView];
}
}
[super layoutSubviews];
}
- (void)startActivity {
self.startCount = self.startCount + 1;
}
- (void)finishActivity {
self.startCount = self.startCount - 1;
}
- (void)setStartCount:(int)startCount {
_startCount = startCount;
if (_startCount > 0) {
[self.activityIndicatorView startAnimating];
// Remove the "magnifying glass icon"
[self setImage:[UIImage new] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
} else {
[self.activityIndicatorView stopAnimating];
// Restore the "magnifying glass icon"
[self setImage:nil forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
}
}
#end
In your ViewController:
#import "SearchBarWithActivity.h"
- (void)viewDidLoad
{
[super viewDidLoad];
// Embed the search bar into NavigationBar and setup the navigation item in order to show the spinner
[self.searchDisplayController setDisplaysSearchBarInNavigationBar:YES];
[(SearchBarWithActivity *)self.searchDisplayController.searchBar setNavigationItem:self.navigationItem];
}
I hope this saves somebody's time.
Since it seems like the depth of the UITextField keeps changing I figured I would add a recursive solution.
-(NSArray * ) findAllSubviewsForView:(UIView * ) view{
NSMutableArray * views = [[NSMutableArray alloc] init];
for(UIView * subview in view.subviews){
[views addObjectsFromArray:[self findAllSubviewsForView:subview]];
}
[views addObject:view];
return views;
}
You can use this array to find the UITextField,
UITextField * searchField = nil;
for(UIView * view in [self findAllSubviewsForView:self]){
if([view isKindOfClass:[UITextField class]]){
searchField = (UITextField *) view;
}
}