I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.
My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.
The DetailViewController is made in IB and has the following hierarchy:
top view => UIScrollView => UIView => UIImage and a UITextField.
My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.
After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.
In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):
- (void)viewDidLoad {
[scrollView setContentSize:CGSizeMake(320, 1500)];
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
NSLog(#"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}
Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.
My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.
A ugly workaround I have found is by using this delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
NSLog(#"Prog. scrolling ended");
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
This brings my scrollview to top, but makes it bounce down and up like a yo-yo
Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!detailViewController) {
detailViewController = [[DayDetailViewController alloc] init];
}
// Pass dictionary for the selected event to next controller
NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
// This method sets values for the image and textfield outlets
[detailViewController setEventDictionary:dict];
// Push it onto the top of the navigation controller´s stack.
[[self navigationController] pushViewController:detailViewController animated:NO];
}
If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?
Any help with these matters are highly appreciated, as this is really driving me nuts!
Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.
However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting
[textView setScrollEnabled:YES];
This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)
With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).
I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?
OK! i have a question before i can give a correct answer.
Why are you using a UIView inside the Scrollview?
You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView
and set the contentSize dynamically depending on the size of the text.
to give you an example how i do it:
int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:#"yourimage"];
contSize = 190 //or add extra space if you dont want your image and your text to be so close
[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = #"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);
[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];
In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.
That way the size of your scrollview will always match your view, and the scrollView will always be at top.
But if you don't want to do all this, you can allways just:
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
at the end of the code where you set your image and your text, and the NOto avoid the bouncing.
Hope this helps.
Related
My UIScrollView is a ~4500px horizontal view that the user needs to scroll horizontally through to view the content.
I have set it up as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
Yet the scroll view does nothing. Is there something obvious I missed? i've tried literally every tutorial on the web.
I got similar issue. I did following modifications and the scrollView started scrolling for me:
Select to check the 'Bounce Horizontally' property for UIScrollView
in xib.
Move the code following code to viewDidAppear instead of
viewDidLoad:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
I think this should help you.
I've explained it here, but there are so many answers to this problem that suggests turning off Auto Layout. That fixes the problem but that's not really the correct solution. Here's my answer:
Turning Auto Layout works, but that's not the solution. If you really need Auto Layout, then use it, if you don't need it, turn it off. But that is not the correct fix for this solution.
UIScrollView works differently with other views in Auto Layout. Here is Apple's release note on Auto Layout, I've copied the interesting bit:
Here are some notes regarding Auto Layout support for UIScrollView:
In general, Auto Layout considers the top, left, bottom, and right edges of a view to be the visible edges. That is, if you pin a view to
the left edge of its superview, you’re really pinning it to the
minimum x-value of the superview’s bounds. Changing the bounds origin
of the superview does not change the position of the view.
The UIScrollView class scrolls its content by changing the origin of its bounds. To make this work with Auto Layout, the top, left, bottom,
and right edges within a scroll view now mean the edges of its content
view.
The constraints on the subviews of the scroll view must result in a size to fill, which is then interpreted as the content size of the
scroll view. (This should not be confused with the
intrinsicContentSize method used for Auto Layout.) To size the scroll
view’s frame with Auto Layout, constraints must either be explicit
regarding the width and height of the scroll view, or the edges of the
scroll view must be tied to views outside of its subtree.
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints
between the view and a view outside the scroll view’s subtree, such as
the scroll view’s superview.
Apple then goes on to show example of how to correctly use UIScrollView with Auto Layout.
As a general rule, one of the easiest fix is to create a constraint between the element to the bottom of the UIScrollView. So in the element that you want to be at the bottom of the UIScrollView, create this bottom space constraint:
Once again, if you do not want to use Auto Layout, then turn it off. You can then set the contentSize the usual way. But what you should understand is that this is an intended behaviour of Auto Layout.
First of all you have to add some content to UIScrollSiew as subview for scrolling,without content on UIScrollView how can you scroll?. Here is what i did,just add UIImageView to UIScrollView as subview of size same as size of UIScrollView...
In viewDidLoad method try the following code..
-(void)viewDidLoad
{
UIScrollView *scroll=[[UIScrollView alloc] init];
scroll.frame=CGRectMake(0, 0, 320, 460);
UIImageView *imageView=[[UIImageView alloc] init];
imageView.frame=CGRectMake(0, 0, 320,460);
imageView.image=[UIImage imageNamed:#"chiranjeevi.jpeg"];
scroll.contentSize = CGSizeMake(4500, 460);
[scroll setScrollEnabled:YES];
[scroll addSubview:imageView];
[self.view addSubview:scroll];
}
I tested this code it works well.I hope this code will be helpful to you..
I assume you are adding UISrollingView in your Xib file. This will work for you.
sview.delegate = self;
sview.backgroundColor=[UIColor clearColor];
[sview setCanCancelContentTouches:NO];
sview.indicatorStyle = UIScrollViewIndicatorStyleWhite;
sview.clipsToBounds = YES;
sview.scrollEnabled = YES;
sview.contentSize = CGSizeMake(320,570);
CGPoint topOffset = CGPointMake(0,0);
[sview setContentOffset:topOffset animated:YES];
Also, make sure to give IBOutlet connection in your Xib file.
I also faced the same issue.I added the scroll view in xib.I also added some subviews to this scroll view. The scroll view would stop scrolling after I added the subviews. The solution for this problem was in the xib for the view in file inspector Use Autolayout was checked. I unchecked it and the scroll view scrolled after adding the subviews.
The solution was uncheking the Use Autolayout in file inspector in xib.
I am new to iPad developer,
I made one Registration form in my application, when i see my application in Portrait mode,
i am able to see whole form with no scrolling, but when i see same form in Landscape mode, i am not able to see part which is at bottom of page, for that a scrolling should be there to see bottom part.
:
In my .h file when i replace
#interface ReminderPage : UIViewController{
...
...
}
:UIViewController with :UIScrollView
and then when i add label in my .m file like this,
UILabel *Lastpaidlbl = [[[UILabel alloc] initWithFrame:CGRectMake(70 ,400, 130, 50)]autorelease];
Lastpaidlbl.backgroundColor = [UIColor greenColor];
Lastpaidlbl.font=[UIFont systemFontOfSize:20];
Lastpaidlbl.text = #"Lastpaid on :";
[self.view addSubview:Lastpaidlbl];
I am getting error on last line Property view not found on object of type classname.
i am unable to add label in my view.
Any help will be appreciated.
The question appears to be really asking how can all the components on the screen be placed inside a UIScrollView, rather than a UIView. Using Xcode 4.6.3, I found I could achieve this by simply:
In Interface Builder, select all the sub-views inside the main UIView.
Choose Xcode menu item "Editor | Embed In | Scroll View".
The end result was a new scroll view embedded in the existing main UIView, will all the former sub-views of the UIView now as sub-views of the UIScrollView, with the same positioning.
If you want to replace your UIViewController with a UIScrollView, you will have to go a bit of refactoring to your code. The error you get is just an example of that:
the syntax:
[self.view addSubview:Lastpaidlbl];
is correct if self is a UIViewController; since you changed it to be UIScrollView, you should now do:
[self addSubview:Lastpaidlbl];
You will have quite a few changes like this one to make to your code and will face some issues.
Another approach would be this:
instantiate a UIScrollView (not derive from it);
add your UIView (such as you have defined it) to the scroll view;
define the contentSize of the scroll view so to include the whole UIView you have.
The scroll view acts as a container for your existing view (you add your controls to the scroll view, then add the scroll view to self.view); this way, you could integrate it within your existing controller:
1. UIScrollView* scrollView = <alloc/init>
2. [self.view addSubview:scrollView]; (in your controller)
3. [scrollView addSubview:<label>]; (for all of your labels and fields).
4. scrollView.contentSize = xxx;
I think the latter approach will be much easier.
Please put all of your UIComponents to the UIScrollview and then it will start scrolling.
please look in to content size. please change it according to the orientation of device.
You're subclassing UIScrollView, so there is no self.view because already self is the view (of the scrollview). You dont need to subclass the scrollview, you can just embed your components in a ivar scrollview and set its contentSize (in your case, you have to enable the scrolling just when the device is in landscape mode). In interface builder you can embed the selected elements in one click, Editor-> Embed in-> scrollview.
First create scrollview
UIScrollView * scr=[[UIScrollView alloc] initWithFrame:CGRectMake(10, 70, 756, 1000)];
scr.backgroundColor=[UIColor clearColor];
[ self.view addSubview:scr];
second
change [self.view addSubview:Lastpaidlbl];
to
[scr addSubview:Lastpaidlbl];
third
set height depends on content
UIView *view = nil;
NSArray *subviews = [scr subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
CGRect frame = view.frame;
curXLoc += (frame.size.height);
}
// set the content size so it can be scrollable
[scr setContentSize:CGSizeMake(756, curXLoc)];
Finally
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
if (interfaceOrientation==UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.scr.frame = CGRectMake(0, 0, 703,768);
} else {
self.scr.frame = CGRectMake(0, 0, 768, 1024);
}
return YES;
}
I'm working on a browser app, and I have an address bar on top the UIWebView. On MobileSafari if you scroll down, the address bar starts to move to the top, out of the screen, and the UIWebView doesn't scroll. Only when the address bar disappears completely, it starts to scroll. I would like to have this effect in my app as well.
What's the best way to implement this?
Thanks
The only way to implement this requires iOS 5.
In iOS 5, UIWebView has an UIScrollView subview.
And use the following code:
Set a area for the address bar:
[[myWebView scrollView] setContentInset:UIEdgeInsetsMake(64, 0, 0, 0)];
Move the address bar using the scrollview delegate:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if(scrollView.contentOffset.y>=-64&&scrollView.contentOffset.y<30)
{
topBar.frame=CGRectMake(0,-44-scrollView.contentOffset.y, 320, 44);
}
else if(scrollView.contentOffset.y<-64)
topBar.frame=CGRectMake(0,20, 320, 44);//Lock the position
}
There is a way, but I am not sure if it is a bit too hacky. First search for the scrollview within the webview, then alter the contentInset and finally add the searchbar(for example) to the scrollview. The following code is just an example, I did not set any frames correctly and 40 is just a made up height for the searchbar. I am not sure if this will work in every iOS Version.
UIWebView * myWebView = [[UIWebView alloc] init]
UISearchBar * mySearchBar = [[UISearchBar alloc] init];
for (NSObject * aSubView in [myWebView subviews]) {
if ([aSubView isKindOfClass:[UIScrollView class]]) {
UIScrollView * theScrollView = (UIScrollView *)aSubView;
theScrollView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
[theScrollView addSubview:mySearchBar];
}
}
PeakJi's solution works but is a bit laggy. A better solution would be adding an observer to the UIScrollView's content offset, something like
[scrollview addObserver:self forKeyPath:#"contentOffset"
options:NSKeyValueObservingOptionNew context:nil];
You can find more document on NSKeyValueObserving protocol at
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html
Come to think of it, it is simply a scrolling view with an address bar stuck on the top, and both the web view and the bar always move together. Now, lets say you create a scroll view and add two subviews, the address bar and the web view (one below the other). It is to be noted that the height of the web view is determined and fixed after the page has been loaded (in webViewDidFinishLoad:).
Hence, it is simply a scrolling view whose contentSize is equal to the height of the bar + the height of the web view. Now, by default the web view allows scrolling, as it has a scroll view as a subview. As only the outer scroll view should be scrolling, it is required that the web view's scrolling be turned off. For that, fetch the first subview (that's the scroll view) and disable its scrolling using:
(UIScrollView*)[myWebView.subviews objectAtIndex:0].scrollEnabled = NO;
I've been having a very hard time finding good examples of UIScrollView. Even Apple's UIScrollView Suite I find a bit lacking.
I'm looking for a tutorial or example set that shows me how to create something similar to the iPhone Safari tab scrolling, when you zoom out from one browser window and can flick to others.
But I'm having a hard time just getting any old view showing within a scroll view. I have a view set up with an image in it, but when I add it to the scroll view, I only get a black rectangle, no matter what I put in the view I add.
Any links or code snippets would be great!
Here is a scroll view guide from Apple
The basic steps are:
Create a UIScrollView and a content view you want to put inside (in your case a UIImageView).
Make the content view a subview of the scroll view.
Set the content size of the scrollview to the frame size of the content view. This is a very important step that people often omit.
Put the scroll view in a window somewhere.
As for the paging behavior, check out UIScrollView’s pagingEnabled property. If you need to scroll by less than a whole page you’ll need to play tricks with clipsToBounds, sort of the reverse of what is happening in this StackOverflow question.
UIScrollView *scrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSInteger viewcount= 4;
for (int i = 0; i <viewcount; i++)
{
CGFloat y = i * self.view.frame.size.height;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, y,self.view.frame.size.width, self .view.frame.size.height)];
view.backgroundColor = [UIColor greenColor];
[scrollview addSubview:view];
[view release];
}
scrollview.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height *viewcount);
For more information Create UIScrollView programmatically
New 3/26/2013
I stumbled on an easier way to do this without code (contentSize)
https://stackoverflow.com/a/15649607/1705353
I have a UITableView with an Index on the side; I want to add a UISearchBar to it, but the index overlaps with the "x" to clear the search. I've noticed in the Contacts application, the textfield within the UISearchBar is resized to accommodate this, but I can't work out how to do this in my own app.
I have tried the following in my viewDidLoad, but it does not seem to work.
UITextField * textField = (UITextField *)[[self.search subviews] objectAtIndex:0];
CGRect r = textField.frame;
[textField setFrame:CGRectMake(r.origin.x, r.origin.y, r.size.height, r.size.width-30)];
Any ideas?
it's much easier than all these suggestions. In interface builder, instead of putting the Search Bar as the header of your Table View, you can put a View instead. Then, put a Navigation Bar inside this View. Grab the left resizing handle of the Navigation Bar and pull it to the right until the N B is only 25 pixels wide. Clear out the Title in the N B (double click to select it, then delete). Then, add a Search Bar into the same View. Move its right resizing handle to the left, adjust so that it abuts the N B. That's it.
You can enable a cancel button if you want too and it also won't overlap the index (remains within the search bar).
Apparently a Table View can only have 1 subview in its header, that's why you need to put the View first, then the N B and Search Bar inside it.
UPDATE: see Beginning iPhone Development from Apress, p. 241 of SDK 3 edition. You just disable the index while searching.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (isSearching) {
return nil;
}
return keys;
}
Also they talk about adding a magnifying glass to the top of the index.
Great book all around.
Why not just make the actual UISearchBar smaller horizontally, and place an (empty) UINavigationBar to the right of it? They will render the exact same background.
Better than hacking the internals of Apple's objects that could change.
Also, when animating the UISearchBar's width, you'll notice that the inner text field is not animated along with it. You can fix this by calling UISearchBar's "layoutSubviews" within your animation block after changing its frame. (that's where it determines the size of the inner text field)
Ok, I've come up with a solution.
Create a subclass of UISearchBar
Include this code in the drawRect: method.
UITextView * textField = [self.subviews objectAtIndex:0];
textField.frame = CGRectMake(5, 6, (310 - kRightSideMargin), 31);
[super drawRect:rect];
Note: kRightSideMargin is a constant I set in my header file; I have it set to 25.
Thanks for the suggestions from everyone else.
As Padraig pointed out all you have to do is subclass out the searchBar. Create your UISearchBar subclass, and add the following code into the layoutSubviews method:
- (void)layoutSubviews
{
UITextField *searchField;
for(int i = 0; i < [self.subviews count]; i++)
{
if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]])
{
searchField = [self.subviews objectAtIndex:i];
}
}
if(!(searchField == nil))
{
searchField.frame = CGRectMake(4, 5, 285, 30);
}
}
This loops through all the subviews and checks them against type UITextField. That way if it ever moves in its line up of subviews this will still grab it. I found 285 to just wide enough not to overlap with the index of my tableView.
As of iOS 6, the navigation bar solution didn't work well for me because of slightly different looks now between the UISearchBar and UINavigationBar. So, I switched to something similar to Padraig's approach by subclassing the UISearchBar.
#interface SearchBarWithPad : UISearchBar
#end
#implementation SearchBarWithPad
- (void) layoutSubviews {
[super layoutSubviews];
NSInteger pad = 50;
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]])
view.frame = CGRectMake (view.frame.origin.x, view.frame.origin.y, view.frame.size.width - pad, view.frame.size.height);
}
}
#end
Edit: Ah, I haven't tried it, but I think you might be able to set a navigation bar's clipToBounds = YES to turn off it's new shadow, thereby creating a consistent look again between the two controls.
I am using ViewDeck and want to show a UISearchbar inside the leftController.
Now the problem is if I open the left side which contains the navigation, the right bit overlaps my search field.
I got rid of this by over writing UISearchBar, the textfield will always have the same width, but in one case there is the ViewDeck overlapping and in the other case I hide the ViewDeck-bit and then the cancel button will take up the space:
Subclassing UISearchBar
#import "ViewDeckSearchBar.h"
#define kViewDeckPadding 55
#interface ViewDeckSearchBar()
#property (readonly) UITextField *textField;
#end
#implementation ViewDeckSearchBar
static CGRect initialTextFieldFrame;
- (void) layoutSubviews {
[super layoutSubviews];
// Store the initial frame for the the text field
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initialTextFieldFrame = self.textField.frame;
});
[self updateTextFieldFrame];
}
-(void)updateTextFieldFrame{
int width = initialTextFieldFrame.size.width - (kViewDeckPadding + 6);
CGRect newFrame = CGRectMake (self.textField.frame.origin.x,
self.textField.frame.origin.y,
width,
self.textField.frame.size.height);
self.textField.frame = newFrame;
}
-(UITextField *)textField{
for (UIView *view in self.subviews) {
if ([view isKindOfClass: [UITextField class]]){
return (UITextField *)view;
}
}
return nil;
}
#end
ViewController class
In my Navigation class I need to overwrite these two UISearchbarDelegate methods in order to go to fullscreen with the search results:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
[self.viewDeckController setLeftSize:0];
// I am also using scopes, which works fine (they fade out when not searching)
self.searchBar.scopeButtonTitles = #[#"Food",
#"Beverages",
#"Misc"];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
self.viewDeckController.leftSize = 55;
}
Result
ViewDeck showing to the right:
(source: minus.com)
Search in Fullscreen (The button and the scope buttons are animated in).
(source: minus.com)
searchBar.layoutMargins = UIEdgeInsetsMake(0, 0, 0, rightPad);
My old solution of changing the UITextField frame stopped working in iOS 13. Putting a UINavigationBar to the right of the UISearchBar never worked well for me as they had different looks at top and bottom.
Sorry to drag this all up again.
I wanted the UISearchBar to be shorter, and I'm using a UISearchBarController, but without actually wanting the index. This is because I have an overlay to the right:
To do this, I fake a sectionIndex with one blank item, then hide it. Here's how I do that:
- (void)hideTableIndex {
for (UIView *view in [tableView subviews]) {
if ([view isKindOfClass:NSClassFromString(#"UITableViewIndex")]) {
view.hidden = YES;
}
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)aTableView {
if (aTableView == self.searchDisplayController.searchResultsTableView) {
return nil;
} else {
[self performSelector:#selector(hideTableIndex) withObject:nil afterDelay:0];
return [NSArray arrayWithObjects:#"", nil];
}
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return 0;
}
This shortens the the UISearchBar and hides the index so it can't be tapped (a small section would otherwise hand to the left of the overlay that when tapped would scroll the UITableView to the top). Like this:
Best of all, when you use the search, you still get the full width bar:
Just put a UIView and put the search bar inside that UIView. UIView must be of same size as UISearchBar.
this worked for me.
The text field used in UISearchBar is a subclass of UITextField called UISearchBarTextField.
AFAIK, there's no way to resize a UISearchBarTextField using the public API, and the private API doesn't reveal much either.
Maybe you can take a look at UISearchBarTextField's subviews, if it has any.
UPDATE: It doesn't.
UPDATE 2: I think you should take a look at UITextField's rightView property. The below code, although it doesn't work, seems like a good starting point:
UIView *emptyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[textField setRightView:emptyView];
[textField setRightViewMode:UITextFieldViewModeAlways];
[emptyView release];
Sorry for Necroposting, but I found another way to make a little space on the right of the textfield.
I was having the problem, that I had an indexed tableview with a searchbar as the first row. Now the index and the searchbar (made in IB, btw.) were overlapping. It tried almost everything with no success. It seems that the width and height properties of the textifield don't respond... So I came up with this:
searchBar.showsCancelButton = YES;
UIView *cButton = [searchBar.subviews objectAtIndex:2];
cButton.hidden = YES;
I still can't adjust the size of the space, but this does it for now... although... pretty weird solution...
Everyone has provided ways to modify the UI. I have discovered how to obtain identical results. You must provide the following two implementations:
Use UISearchDisplayController
More importantly, make sure you initialize it with:
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController
Failure to set a valid UISearchBar (or passing nil) will prevent the adjustment of the UITextField for the index.
You must return a valid array of titles by implementing:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
If you return nil, the index will not be displayed, and the UITextField will not be properly adjusted.
I've submitted a bug report to Apple, suggesting that it seems logical that only #2 should be required, not #1. I have found nothing in the Human Interface Guideline (iPhone HIG) requiring use of the UISearchDisplayController.
The key is to use the "Search Bar and Search Display Controller" and not the "Search Bar" when using Interface Builder.
It kind of looks as though Apple resize the view (note that the index is animated to the right, off screen), making it bigger than the screen.
I would imagine that you'd need to implement the searchBarTextDidBeginEditing: method of the UISearchBarDelegate to trigger this at the appropriate point. This does, however, feel a bit hacky do maybe there's a better way of doing it.
Another appraoch (though tedious) would be to resize the search bar and fill the 'gap' with a navigation bar. Works for me.
What I've come up with isn't too much better. Basically, I make an empty view with the frame that I want to use for the search bar. Then I create a UIToolbar to go behind the search bar. Be sure to set its frame to the same frame as the UIView, except that the Y value has to be -1; otherwise, you'll get two borders drawn at the top. Next create your UISearchBar, but set the frame's width to 30 (or whatever makes sense for your app) less than the UIView. Add them as subviews and set your UIView as the tableHeaderView.
I followed Mike's advice by making a UIView, then putting a Navigation Bar and UISearch Bar inside it. Only problem is first time the search bar is shown its background is the same as a Navigation Bar normally?
Interestingly, if I activate the search, then click cancel the background of this 'fixed'!?
I'm using SDK 3.0, so I removed the UISearchBar item made when I dragged a UISearchDisplayController in to my NIB, then made the view as described above and wired it up to the file owner and the searchBar outlet in the search display controller.
It work fine!!!
[searchBar setContentInset:UIEdgeInsetsMake(5, 0, 5, 35)];