addSubview outside resized frame - iphone

I've coded a "generic" ads management class for all my applications and i have an issue. This class can add an ads view to any view of my application, randomly; in order to do so, my idea is to resize the frame of my current view to reduce its height (let's say 50 pixels less) and add my ads view in the free space i created. This way, i don't have to bother modifying my views for ads integrations, everything is done automatically. It's working well but my ads aren't responding to touch events. I guess it's because this ads view is "outside" the frame of my controller.
It is possible to reduce the height of my view frame and raise its bounds so my ads subview is really part of my view?
Thanks a lot :)
UIView *adView = [[UIView alloc] init];
adView.frame = CGRectMake(0,267,320,100);
adView.backgroundColor = [UIColor grayColor];
adView.tag = 123456;
adView.userInteractionEnabled = YES;
CGRect myFrame = [self.view frame];
myFrame.size.height = myFrame.size.height - 100;
[self.view setFrame:myFrame];
[self.view addSubview:adView];
Here's a picture representing what i would like to do :
http://i49.tinypic.com/2iw7lz4.jpg

This is not an answer but I do not have option to post a comment to your question.
Can you please post the code you have in your touchesBegan method?
I think there can be the problem
Regards
Alejandra

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

Adding something programmatically to an iOS view

I am trying to get some AdWhirl ads to work with my app, but I am having a bit of trouble positioning them. The ads work just fine with the following code in my viewDidLoad method:
AdWhirlView *adWhirlView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
[self.view addSubview:adWhirlView];
The problem is that it displays the add across the top of the view. I am assuming this is because the default drawing area is from 0,0. I don't know how to change the self.view line to draw it towards the bottom of the screen.
Try it like this....
AdWhirlView *adWhirlView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
adWhirlView.frame = CGRectMake(0.0f, 100.0f, adWhirlView.frame.size.width, adWhirlView.frame.size.height);
[self.view addSubview:adWhirlView];
It should show the new view further below (100 points) - adapt that 100.0f according to your needs.
view.frame = CGMakeRect(x,y,w,h);

UIScrollView + UIWebView = NO scrollsToTop

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

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

Photos app-like gap between pages in UIScrollView with pagingEnabled

UIScrollView in paging mode assumes the pages are located right next to each other, with no gap. However if you open a photo in the Photos app and swipe through photos, you can see that it has some gap between pages. I want these gaps too.
I'm looking for existing solutions if any, or for some more bizarre ideas about implementing the page gaps besides the one I have explained below. Or maybe there's some obvious easy way I am missing?
To be clear: I want the gap to only be visible while scrolling, so I cannot simply inset the page content.
My plan is to try moving the page content from inside scrollViewDidScroll callback, so that (assuming you're scrolling to the right) initially the target page is slightly offset to the right of its page boundaries, and by the time you arrive at the target page it's back at its proper location, and the source page is slightly offset to the left of its boundaries. (Or maybe instead of moving things continuously, I'll be better off shifting the offsets, say, exactly halfway between pages.)
I'm the author of the ScrollingMadness article+example that I've been referring some people to here. I've implemented progammatic zooming, and got in-photo zooming+scrolling working together with inter-photo paging. So I know how to play with UIScrollView, and am looking for the advanced stuff.
Please don't point me at TTScrollView. I've already pointed many people to it myself, but I consider it's feel too far from the native UIScrollView behaviour, and do not want to use it in my projects.
Note that this answer is quite old. The basic concept still works but
you should not be hard coding view sizes in iOS7 and 8. Even if you ignore
that advice, you should not use 480 or 330.
Have you tried making the frame of the UIScrollView slightly larger than the screen (assuming that you want to display your images fullscreen and then arranging your subviews on the same slightly-larger-than-the-screen boundaries.
#define kViewFrameWidth 330; // i.e. more than 320
CGRect scrollFrame;
scrollFrame.origin.x = 0;
scrollFrame.origin.y = 0;
scrollFrame.size.width = kViewFrameWidth;
scrollFrame.size.height = 480;
UIScrollView* myScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
myScrollView.bounces = YES;
myScrollView.pagingEnabled = YES;
myScrollView.backgroundColor = [UIColor redColor];
UIImage* leftImage = [UIImage imageNamed:#"ScrollTestImageL.png"];
UIImageView* leftView = [[UIImageView alloc] initWithImage:leftImage];
leftView.backgroundColor = [UIColor whiteColor];
leftView.frame = CGRectMake(0,0,320,480);
UIImage* rightImage = [UIImage imageNamed:#"ScrollTestImageR.png"];
UIImageView* rightView = [[UIImageView alloc] initWithImage:rightImage];
rightView.backgroundColor = [UIColor blackColor];
rightView.frame = CGRectMake(kViewFrameWidth * 2,0,320,480);
UIImage* centerImage = [UIImage imageNamed:#"ScrollTestImageC.png"];
UIImageView* centerView = [[UIImageView alloc] initWithImage:centerImage];
centerView.backgroundColor = [UIColor grayColor];
centerView.frame = CGRectMake(kViewFrameWidth,0,320,480);
[myScrollView addSubview:leftView];
[myScrollView addSubview:rightView];
[myScrollView addSubview:centerView];
[myScrollView setContentSize:CGSizeMake(kViewFrameWidth * 3, 480)];
[myScrollView setContentOffset:CGPointMake(kViewFrameWidth, 0)];
[leftView release];
[rightView release];
[centerView release];
Apologies if this doesn't compile, I tested it in a landscape app and hand edited it back to portrait. I'm sure you get the idea though. It relies on the superview clipping which for a full screen view will always be the case.
So I don't have enough "rep" to post a comment on the answer above. That answer is correct, but there is a BIG issue to be aware of:
If you're using a UIScrollView in a viewController that's part of a UINavigationController, the navigation controller WILL resize the frame of your scrollView.
That is, you have an app that uses a UINavigationController to switch between different views. You push a viewController that has a scrollView and you create this scrollView in the viewController's -init method. You assign it a frame of (0, 0, 340, 480).
Now, go to your viewController's -viewDidAppear method, get the frame of the scrollView you created. You'll find that the width has been reduced to 320 pixels. As such, paging won't work correctly. You'll expect the scrollView to move 340 pixels but it will, instead, move 320.
UINavigationController is a bit notorious for messing with subviews. It moves them and resizes them to accommodate the navigation bar. In short, it's not a team player -- especially in this case. Other places on the web suggest that you not use UINavigationController if you need precise control over your views' size and locations. They suggest that, instead, you create your own navigationController class based on UINavigationBar.
Well that's a ton of work. Fortunately, there's an easier solution: set the frame of the scrollView in your viewController's -viewDidAppear method. At this point, UINavigationController is done messing with the frame, so you can reset it to what it should be and the scrollView will behave properly.
This is relevant for OS 3.0. I have not tested 3.1 or 2.2.1. I've also filed a bug report with Apple suggesting that they modify UINavigationController with a BOOL such as "-shouldAutoarrangeSubviews" so that we can make that class keep its grubby hands off subviews.
Until that comes along, the fix above will give you gaps in a paginated UIScrollView within a UINavigationController.
Apple has released the 2010 WWDC session videos to all members of the iphone developer program. One of the topics discussed is how they created the photos app!!! They build a very similar app step by step and have made all the code available for free.
It does not use private api either. Here is a link to the sample code download. You will probably need to login to gain access.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
And, here is a link to the iTunes WWDC page:
http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj
The way to do this is like you said, a combination of a few things.
If you want a gap of 20px between your images, you need to:
First, expand your scroll view's total width by 20px and move it left by 10px.
Second, when you lay out the xLoc of your images, add 20px for each image so they're spaced 20px apart.
Third, set the initial xLoc of your images to 10px instead of 0px.
Fourth, make sure you set the content size of your scroll view to add 20px for each image. So if you have kNumImages images and each is kScrollObjWidth, then you go like this:
[scrollView setContentSize:CGSizeMake((kNumImages * (kScrollObjWidth+20)), kScrollObjHeight)];
It should work after that!
This is just a hunch, so apologies if completely wrong, but is it possible that the contentSize is just set to slightly wider than the screen width.
The correct information is then rendered within the view to the screen width and UIScrollView takes care of the rest ?
Maybe you want to try UIScrollView's contentInset property?
myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);
I just thought I'd add here for posterity the solution I ended up going with. For a long time I've been using Bryan's solution of adjusting the frame in -viewDidAppear, and this has worked brilliantly. However since iOS introduced multitasking I've been running into a problem where the scroll view frame gets changed when the app resumes from the background. In this case, -viewDidAppear was not being called and I couldn't find a delegate method that would be called at the right time to reverse the change. So I decided to make my scroll view a subview of my View Controller's view, and this seemed to fix the problem. This also has the advantage of not needing to use -viewDidAppear to change the frame - you can do it right after you create the scroll view. My question here has the details, but I'll post them here as well:
CGRect frame = CGRectMake(0, 0, 320, 460);
scrollView = [[UIScrollView alloc] initWithFrame:frame];
// I do some things with frame here
CGRect f = scrollView.frame;
f.size.width += PADDING; // PADDING is defined as 20 elsewhere
scrollView.frame = f;
[self.view addSubview:scrollView];
To avoid messing with UIScrollView's frame, you could subclass UIScrollView and override layoutSubviews to apply an offset to each page.
The idea is based on the following observations:
When zoomScale !=1, the offset is zero when it is at the left / right edge
When zoomScale ==1, the offset is zero when it is at the visible rect centre
Then the following code is derived:
- (void) layoutSubviews
{
[super layoutSubviews];
// Find a reference point to calculate the offset:
CGRect bounds = self.bounds;
CGFloat pageGap = 8.f;
CGSize pageSize = bounds.size;
CGFloat pageWidth = pageSize.width;
CGFloat halfPageWidth = pageWidth / 2.f;
CGFloat scale = self.zoomScale;
CGRect visibleRect = CGRectMake(bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale);
CGFloat totalWidth = [self contentSize].width / scale;
CGFloat scrollWidth = totalWidth - visibleRect.size.width;
CGFloat scrollX = CGRectGetMidX(visibleRect) - visibleRect.size.width / 2.f;
CGFloat scrollPercentage = scrollX / scrollWidth;
CGFloat referencePoint = (totalWidth - pageWidth) * scrollPercentage + halfPageWidth;
// (use your own way to get all visible pages, each page is assumed to be inside a common container)
NSArray * visiblePages = [self visiblePages];
// Layout each visible page:
for (UIView * view in visiblePages)
{
NSInteger pageIndex = [self pageIndexForView:view]; // (use your own way to get the page index)
// make a gap between pages
CGFloat actualPageCenter = pageWidth * pageIndex + halfPageWidth;
CGFloat distanceFromRefPoint = actualPageCenter - referencePoint;
CGFloat numOfPageFromRefPoint = distanceFromRefPoint / pageWidth;
CGFloat offset = numOfPageFromRefPoint * pageGap;
CGFloat pageLeft = actualPageCenter - halfPageWidth + offset;
view.frame = CGRectMake(pageLeft, 0.f, pageSize.width, pageSize.height);
}
}