UIScrollView + UIWebView = NO scrollsToTop - iphone

It looks like a problem which could have simple solution, but I haven't found anything what could lead the way to it. I'm using UIWebView inside of UIScrollView and tapping on statusBar (to scroll content to top) is not working.
I've made simple test application to see if it's really UIWebViews fault. And it really is.
// scrolls to top on status bar tap
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
[self.view addSubview:sv];
// doesn't scroll
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
UIWebView *wv = [[UIWebView alloc] init];
wv.frame = CGRectMake(0, 0, 320, 100);
[sv addSubview:wv];
[self.view addSubview:sv];
So, I think maybe there's something I could disable to make UIWebView not to mess with scrollToTop? Or some kind of workaround also would be nice.
Any ideas?

I ran into this last night until I finally found the answer buried in a comment to a comment. The idea of that original post is that when you add the UIWebView to your UIScrollingView, you use the following:
- (void) ensureScrollsToTop: (UIView*) ensureView {
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
}
This seemed fishy to me since the first sub-view of a UIWebView claims to be a UIScroller which is not a subclass of UIScrollView. However, since UIScroller supports the scrollsToTop property, the cast just gives us a way past the compiler warning:
Class List:
Class = UIScroller
Class = UIView
Class = UIResponder
Class = NSObject
Supported Methods:
...
Method _scrollToTop
Method setScrollsToTop:
Method scrollsToTop
...
Supported Properties:
Property scrollsToTop
EDIT:
Just another quick note about where this actually needs to occur: in the webViewDidFinishLoad callback. Calling it on UIWebView construction isn't good enough because at that time the UIWebView hasn't created it's child views yet, which are the ones causing the problem:
- (void)webViewDidFinishLoad:(UIWebView *) wv {
[self ensureScrollsToTop: wv];
}
EDIT #2:
now, in iOS 5, as noted in iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back use UIWebView's new #property scrollView, making ensureScrollsToTop implementation unnecessary for projects that aren't using deployment targets lower than iOS 5.0 .

In iPhone OS, if there is more than one UIScrollView (or its subclass, for example UITableView, UIWebView) in the current viewController, the system doesn't know which UIScrollView should be scrolled to the top.
Quick fix: for all the UIScrollViews that you don't want to support scrollsToTop, just set the scrollsToTop as NO, then every thing works perfect.
self.scrollView1.scrollsToTop = NO;
self.scrollView2.scrollsToTop = NO;
self.scrollView1.scrollsToTop = YES; // by default scrollsToTop is set as YES, this line is not necessary

Webviews by default will have YES for scrollsToTop-value. I've written a simple class for this specific issue. In my app we're having multiple webviews and scrollviews. This makes it all much easier.
https://gist.github.com/hfossli/6776203
It basically sets scrollsToTop to NO on all other scrollViews than the one you are specifying.

I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr said:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];

Related

Strange three20's TTTableViewController frame properties

I am adding a TTTableViewController into an existing UIViewController, one strange thing I found is that the frame properties of the initialized TTTableViewController are wired, e.g. in a iOS layout.
I have:
UIStatusBar
UINavigationController
UIViewController
UITabBar
In order to set the TTTableViewController fill in all the remaining space I need to set the height to 460 instead of 367. (367 = 480-20-44-49)
e.g.
self.tableViewController.view.frame = CGRectMake(0, 0, 320, 460.0f);
instead of
self.tableViewController.view.frame = CGRectMake(0, 0, 320, 367.0f);
Why is it so?
*Edit for clarification: I mean TTTableViewController on the top of TTViewController (using [self.view addSubview:self.tableViewController.view];), and I need to set the self.tableViewController.view.frame = CGRectMake(0, 0, 320, 460.0f); instead of 367
It depends on when you are setting the frame, I think. I'm pretty sure when you set the frame in viewDidLoad, for example, you'll be setting it before the status bar and other things are taken into account. There might be other cases like this. If you set it to 320:460, it'll be resized to take into account the status bar and other stuff afterwards, making it fill in the rest of the screen. If you set it to 320:367 because you've already taken into account that stuff, it'll get resized again and squished (basically scaled down twice), making it only fill part of the screen. If you're using viewDidLoad you could try sticking it in another method (maybe viewWillAppear?) or just keep using 320:460.
It'd be nice to know when you set the frame, exactly. Also keep in mind that I could be way off. My mind's feeling a little fuzzy right now.
As per my understanding, only the size of your status bar is deducted i.e. 480-20 = 460. actually status bar is 22 pts but its approx.
Its just like when you add a viewcontroller to your navigation controller or your tab bar controller the size is auto rendered. So same is the case here, the three20 automatically adjusts the size of the view and if you try to set it to something smaller then that it behaves differently.
Its a nice question though. Happy Coding. Cheers!!
I wouldn't add a view of a different view controller into the main view of your current view.
You should present the TTTableViewController using the controller's present / dismiss functions. if you don't want to include the slide up effect, so the users won't see that it's a "different screen", use the boolean flag when you present the controller.
[self presentModalViewController:vc animated:NO];
Alternatively, use a TTTableView without the controller:
tableView = [[TTTableView alloc] initWithFrame:CGRectMake(0, kScrollViewHeight + kSignupLabelHeight, 320, kTableViewHeight) style:UITableViewStyleGrouped];
[tableView setBackgroundColor:[UIColor clearColor]];
tableView.delegate = self;
tableView.dataSource = [TTSectionedDataSource dataSourceWithObjects:
#"",
[TTTableTextItem itemWithText:#"Sign Up" URL:#"tt://signupController"],
nil];
[self.view addSubview:tableView];
Like a this code .
if use iOS6 , get current device.
if();
-(void)viewdidLoad{
TTTableViewController *tt = [TTTableViewController new];
CGRect frame = [UIScreen mainScreen].bounds;
tt.frame = frame;
tt.delegate = self;
[self.view addsubview:tt];
}

Convert UIViewController to UIScrollViewController

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;
}

UITextView text not displayed when parent view is UIScrollView UNTIL I scoll

I have a UITextView inside of a UIScrollView that is configured offscreen when the code below runs in my ViewController's viewDidLoad. Unfortunately, if the "eventDetails" text is particularly long nothing is displayed inside the UITextView until I interact with it (e.g click inside and drag for example).
My question: How to have it so the text is displayed in the UITextView WITHOUT forcing the user to interact with the UITextView first?
Here is the code:
UITextView *txtDetails = [[UITextView alloc] initWithFrame:CGRectMake(-4, yOffset, page3ScrollView.frame.size.width, 0)];
[txtDetails setEditable:NO];
[txtDetails setScrollEnabled:NO];
[txtDetails setFont:[UIFont systemFontOfSize:12]];
[txtDetails resizeAndSetTextWithMaxSize:CGSizeMake(txtDetails.frame.size.width, 999999999) forText:eventDetails withAdditionalHeightOf:16.f];
[page3ScrollView addSubview:txtDetails];
CGRect frame = txtDetails.frame;
frame.size.height = [txtDetails contentSize].height;
txtDetails.frame = frame;
[page3ScrollView setContentSize:CGSizeMake(page3ScrollView.frame.size.width, txtDetails.frame.origin.y + txtDetails.frame.size.height)];
Thanks
I was able to get this working by setting the UITextView's text ONLY when needed (e.g. is about to come on screen). Below is the relevant code:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sv
{
if (sv == scrollView) [self updatePagedView];
}
- (void)updatePagedView
{
int currentPage = pageControl.currentPage;
// *** loadDetailsPage3 is where I set the text ***
if (currentPage == 2) {
[self loadDetailsPage3];
}
}
If anyone has a better solution or needs more explanation just hit me up in the comments.
I've had the same issue and it's taken me several hours to find a suitable fix for it... Here's what I came up with...
-(void)DidBecomeActive {
if (!DidUpdateBounds) {
DidUpdateBounds = true; // instance variable set to false on load
NSString *oldtext = uiTextView.text;
//The trick is (1) removing it from it's superview
// (2) resetting it's 'text' property
// (3) re-adding it to the view WHILE it's on-screen.
[uiTextView removeFromSuperview];
uiTextView.text = oldtext;
[self.view addSubview:uiTextView];
[self.view setNeedsDisplay];
}
}
I'm using CoreAnimation to switch to this view. So right before I execute that code, I call this
//The 0,-300,480,300 is bounds of the UIView my offscreen UITextview is on
[self.view.layer setBounds:CGRectMake(0, -300, 480, 300)];
// SetNeedsDisplay, then call my method above to
//FORCIBILY redrew the UITextView while it's effectively on-screen
[self.view setNeedsDisplay];
[TextLogVC DidBecomeActive];
//CoreAnimation then goes here
This solves the issue. After setting the layer.bounds it redraws the control(UITextView) and it thinks it's onscreen. Then CoreAnimation takes care of animating from my current UIView to the new UIView and all of the text in the uiTextView is displayed throughout the animation.
Looks like the views that you are setting up are not refreshed.
And when you interact with the views then they are refreshed and your changes are rendered to the display...
Try adding [txtDetails setNeedsDisplay]; [page3ScrollView setNeedsDisplay]; after your code in viewDidLoad.
If it will help then maybe we'll find some more elegant solution...

Transparent NavgationBar on iPhone

I'm trying to display transparent UINavigationBar on top of Scrollview.
This is actual result of code that I have written...
where as I'm expecting view to be displayed like below image, which happens after I slightly scroll the image.
Code :
- (void) loadView {
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [self imageCount],
pagingScrollViewFrame.size.height);
pagingScrollView.delegate = self;
self.wantsFullScreenLayout = YES;
pagingScrollView.scrollsToTop = YES;
self.view = pagingScrollView;
}
question is how do I make view to load as I expected without user interacting to it?
any suggestion or help is appreciated..
EDIT: I'm creating view totally from CODE
It seems like you're trying to do this in code not in the IB. If so, you have to put your code in the viewDidLoad of the Application Delegate (e.g. MyProgramAppDeligate class or whatever). If you want it in some certain views, put it in the viewDidLoad of the UINavigationController class/subclass.
Does this satisfy your requirement?
self.navigationController.navigationBar.translucent = YES;
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
And to make your statusbar translucent.
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
[self setWantsFullScreenLayout:YES];
I have this inside my willWillAppear and I reset it in my viewWillDisappear.
You have to set
self.navigationController.navigationBar.translucent = YES;
As soon as you do this, the 0,0 coordinate is behind your navigation bar not below it and your view shifts behind the bar.
It may be a conflict between IB and your code. I would add the line of code suggested by Ortwin in the viewDidLoad method and then double check you've set the navBar to translucent in IB.
The code you have posted has nothing to do with the opacity of the navigation bar. Show where you are setting the configuration of the components of the view. There you could just set the alpha of the navigation bar. Alternatively if you are using nibs, just set the alpha in IB.
Since you say that it works fine after the user (you) slightly scrolls the image, the problem might be that the UINavigationBar's drawRect: method does not get called after the UIScrollView is loaded.
Suggestion: Can you explicitly call setNeedsDisplay on the navigation bar after the view is loaded?
Have you tried setting the frame of the scroll view with an Y origin of 0 after setting the nav bar to transparent?
EDIT: I mean, you don't say what's the frame used in your code.
In viewDidLoad, try moving the origin up 32 pixels and grow the height by 32 pixels as well:
pagingScrollView.frame = CGRectMake(pagingScrollView.frame.origin.x, pagingScrollView.frame.origin.y-32, pagingScrollView.frame.size.width, pagingScrollView.frame.size.height+32);
In viewWillAppear scroll the content to the correct location.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView setContentSize:CGSizeMake(320,568)];
[scrollView scrollRectToVisible:CGRectMake(0, 548, 320, 20) animated:NO];
}

Learning the basics of UIScrollView

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