how to get the absolute position of a section header in tableview?
I have already used the tableView:viewForHeaderInSection: to get the header's view.But now i need to get the absolute position of this view in the screen.
the return value's frame is not the absolute position in the screen.I also tried to call superview,but it seems not work.
tableView:viewForHeaderInSection: is a UITableViewDelegate method for creating a header view for display. This means, however, that the view has not been added to the view hierarchy, rendering it's frame meaningless for your purposes.
Try
UIView *headerView = [tableView headerViewForSection:sectionIndex];
instead. From there you can try the following methods on the returned view to get the rect of the view in any other view's coordinate system:
[headerView convertRect:[headerView bounds] toView:[headerView window]];
Assuming that your top-level view directly contains table view which in turn contains header:
- (CGRect) getHeaderAbsoluteFrame : (UIView *)headerview :(UIView *)tableview
{
CGRect frame = headerview.frame;
CGRect tableFrame = tableview.frame;
float x = tableview. origin.x + headerview.frame.origin.x;
float y = tableview.frame.origin.y + headerview.frame.origin.y;
CGRect rect = CGRectMake (x,y,headerview.frame.size.width, headerview.frame.size.height);
return rect;
}
Related
I have following hierarchy: Controller.view [tableView, overlayView]. Table view has top inset of 16 points from parent view via constraint, overlay view - not.
Inside table cell content view I have another view responder and I want to show it's image on view overlayView.
If I use this code (inside overlay view):
CGRect frame;
CGPoint origin = [responder convertPoint:responder.frame.origin toView:self];
// FIXME origin.y -= 16;
frame.origin = origin;
frame.size = responder.frame.size;
_imageView.frame = frame;
UIGraphicsBeginImageContextWithOptions(responder.bounds.size, NO, 0);
[responder drawViewHierarchyInRect:responder.bounds afterScreenUpdates:YES];
_imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I get imageView with 16 points offset from responder origin and image not fit into original view. So I have to use line with FIXME mark to have origin points equal. Why converting don't work?
You should be converting the point from the responder's superview, not the responder itself. Change your second line to this:
CGPoint origin = [responder.superview convertPoint:responder.frame.origin toView:self];
I have a detail view where I want to show a title, subtitle and content for articles. I want to be able to use HTML to format the text, so I've used a UIWebView for showing the article body. This works perfectly.
How ever, all of this, is inside a UIScrollView, so my issue is that I have to calculate the height of the UIScrollView?
This is how it works today:
And this is how it looks like in Storyboard:
So what I need to find out, is what is the correct code and syntax to calculate the correct height of the UIScrollView? Amongst several things, I tried [self.scrollView sizeToFit] without luck.
EDIT: Apparently it sets the correct heights with the code below, but seems like the view never updates.
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
// get height of content in webview
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"] floatValue];
// set new frame height
CGRect frame = webView.frame;
frame.size.height = height;
webView.frame = frame; // webview is now correct height
// set new frame height for scrollview (parent of webview)
CGRect scrollFrame = self.scrollView.frame;
scrollFrame.size.height = webView.frame.origin.y + height;
self.scrollView.frame = scrollFrame;
// log to console for cross checking
NSLog(#"new frame: %f, scrollview frame: %f", scrollFrame.size.height, self.scrollView.frame.size.height);
}
The console reports the apparently correct height:
new frame: 582.000000, scrollview frame: 582.000000
And a quick check in Photoshop as well, this seems to be correct:
The summed value of green and blue area is 582 pixels, but the scrollview still just scrolls the 504 pixel area from below the navigation bar to the bottom of the screen (to the bottom of the tab bar).
The webview has internally a scrollview. You can query its size by webview.scrollView.contentSize. You have to wait with this until the webview has finished rendering.
So, in the -webViewDidFinishLoad: delegate method you can get the optimal height of the webView through webView.scrollView.contentSize.height. You can then resize the webView to this height and layout the other views appropriately. If all of this is done in a custom view, the proper way of doing this would probably be to just call [theView setNeedsLayout] and override -layoutSubviews in theView.
You also should set webView.scrollView.alwaysBounceVertically to NO.
I solved the problem.
First of all, just expand the UIWebView to a height higher than the content ever will be (e.g. 2000 pixels).
The delegate method code that makes the magic happen
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
// set height for webiew
webView.autoresizesSubviews = NO;
webView.translatesAutoresizingMaskIntoConstraints = YES;
webView.scrollView.autoresizesSubviews = NO;
webView.scrollView.translatesAutoresizingMaskIntoConstraints = YES;
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('content').clientHeight;"] floatValue] + 80; // +80 for tabbar and spacing
CGRect frame = webView.frame;
frame.size.height = height;
webView.frame = frame;
// fix height of scroll view as well
self.scrollView.translatesAutoresizingMaskIntoConstraints = YES;
self.scrollView.contentSize = CGSizeMake(320, (self.webView.frame.origin.y + self.webView.frame.size.height));
}
I have a view containing a UITableView. On view did load, I set the table's tableFooterView to be a view I create by hand (a UIView containing a button). When the view appears, I adjust the frame of the tableFooterView:
CGRect tableFrame = self.myTableView.frame;
CGRect originalFrame = self.tableFooter.frame;
CGSize imageSize = CGSizeMake(40.0f, 40.0f);
CGRect footerFrame = CGRectMake(originalFrame.origin.x, originalFrame.origin.y, tableFrame.size.width, imageSize.height);
self.tableFooter.frame = footerFrame;
CGRect nextFrame = CGRectMake((footerFrame.size.width - imageSize.width) / 2.0f, 0.0f, imageSize.width, imageSize.height);
self.tableFooterButton.frame = nextFrame;
On iOS7, this works the way I want -- when I scroll to the bottom of the table, I see my footer view. On iOS6, when I scroll to the bottom of the table, the footer view is still offscreen (I can pull the scroll view and see it, but it resets offscreen when I release).
What should I do differently?
After change the frame of table footer, try this:
self.myTableView.tableFooterView = nil ;
self.myTableView.tableFooterView = self.tableFooter ;
I design the scrollview in interface builder like this
It looks good here. But unfortunately when I run it on emulator or device
it becomes
The content in scrollview is expand outside scrollview itself and even though outside UIView that contains this scrollView.
In my viewDidLoad (panel is the container of scrollView )
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
CGFloat adjustPanelHeight = [PTTScreenScaleUtil getAdjustHeight:self.panel.frame.size.height];
CGRect panelRect = self.panel.frame;
panelRect.size.height = adjustPanelHeight;
self.panel.frame = panelRect;
UIImage *image = [UIImage imageNamed:#"panel-background"];
UIGraphicsBeginImageContext(self.panel.frame.size);
[image drawInRect:CGRectMake(0, 0, self.panel.frame.size.width, adjustPanelHeight)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.panel setBackgroundColor:[UIColor colorWithPatternImage:newImage]];
NSLog(#"scrollView Height : %f", self.scrollView.frame.size.height);
NSLog(#"scrollView contentSize Height : %f", self.scrollView.contentSize.height);
// CGRect scrollViewRect = self.scrollView.frame;
// CGRect scrollViewContentRect = self.scrollView.frame;
// NSLog(#"ScrollView Height Before : %f , After : %f", self.scrollView.frame.size.height, [PTTScreenScaleUtil getAdjustHeight:self.scrollView.frame.size.height]);
// scrollViewRect.size.width = 280;
// scrollViewRect.size.height = [PTTScreenScaleUtil getAdjustHeight:270];
// self.scrollView.frame = scrollViewRect;
// [self.detailsLabel sizeToFit];
UIView *view = [[self.scrollView subviews] objectAtIndex:0];
// [view sizeToFit];
// [self.scrollView setContentMode:UIViewContentModeScaleAspectFit];
// NSLog(#"ContentSize Height : %f", view.frame.size.height);
// scrollViewContentRect.size.height = view.frame.size.height;
NSLog(#"Bounds : %f", view.bounds.size.height);
self.scrollView.frame = CGRectMake(10, 10, 280, 270);
self.scrollView.contentSize = CGSizeMake(280, 500);
NSLog(#"Frame Height %f", self.scrollView.frame.size.height);
//[self.scrollView setContentSize: CGSizeMake(280, 1000)];
CGRect termBtnRect = self.termBtn.frame;
CGRect mailBtnRect = self.mailBtn.frame;
CGRect twitterBtnRect = self.twitterBtn.frame;
CGRect fbBtnRect = self.fbBtn.frame;
termBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
mailBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
twitterBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
fbBtnRect.origin.y = adjustPanelHeight - 10 - termBtnRect.size.height;
self.termBtn.frame = termBtnRect;
self.mailBtn.frame = mailBtnRect;
self.twitterBtn.frame = twitterBtnRect;
self.fbBtn.frame = fbBtnRect;
}
All the log return 270.0
PS. the scroll bar is correct even though the content goes outside but the scroll bar is working correctly (stay in the scrollview's frame as arrange in interface builder)
I have no idea how can I solve this.
Anyone help me please.
Thanks you.
Solve it by creating new view controller in interface builder and redo the same process with careful and bingo. It works.
When I compare both two view controller I realise that the wrong one UIScrollView Clip Subviews is unchecked. When check it the problem solve.
I just struggled with this for an hour and had a head smack moment.
In my case, I had a UIView on the scene in the Storyboard. At some point I decided I needed it to be a UIScrollView instead (as opposed to the original plan which was to embed the UIScrollView in a UIView)
I went ahead and changed the class on the UIView to UIScrollView. IB changed it to Scroll View in the Document Outline, I figure I'm good, right?
And then I see the behavior you describe.
At some point it hits me that this isn't sufficient. Apparently adding a UIScrollView via IB does some things differently than adding a UIView and just changing class isn't enough. And this is probably the reason re-doing it from scratch fixed it for you.
So for anyone who runs into this in the future, make sure you added the UIScrollView via IB instead of a UIView
I was having the same problem as described in this post. I tried multiple combinations of solutions that did not work, including:
putting the scroll view inside a view with Clip To Bounds = YES
putting a view inside the scroll view with Clip To Bounds = YES, that then contained my child view
putting a Container View inside the scroll view, and then embedding my subview
rebuilding the Interface Builder files completely
every combination of autosizing mask options systematcially for both the scroll view and container view
clip to bounds enabled or disabled for every single element systematically
The child view in question had previously worked inside a scroll view, but wouldn't in this one case where the content blew outside the bounds of the scroll view.
In the end, I implemented the solution in code as I could find no way to get Interface Builder to co-operate:
// There are two scroll areas on the screen, the left view and the right view.
// We want the right view to contain a scrollable area with another child view controller
// we designed in Interface Builder.
// create a scroll view to fill the right view with a scrollable area
CGSize rightFrameSize = self.rightView.bounds.size;
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake (0, 0, rightFrameSize.width, rightFrameSize.height)];
scrollView.contentSize = CGSizeMake(640, 1352);
[self.rightView addSubview:scrollView];
// now create our child view controller from Interface Builder and add it to the scroll view
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"CustomerAddress" bundle:[NSBundle mainBundle]];
detailsView = [sb instantiateViewControllerWithIdentifier:#"CustomerDetailsView"];
detailsView.delegate = self;
detailsView.customer = _customer;
[scrollView addSubview:detailsView.view];
You could of course get the scrollView.contentSize from the child view controller you constructed in Interface Builder using scrollView.contentSize = detailsView.view.frame.size.
I have a love/hate relationship with Interface Builder... most days I love it, but some days we argue and I wish we'd never met... :)
only make cliptobound=YES in storyboard if you changed UIView to UIScrollView
I have a UITableView with a custom header (i.e. I create the UIView myself). I need to tweak the accessibilityFrame of one of the subviews of the view, but I can’t figure out how to set the coordinates of the frame appropriately—they need to be relative to the window, but I’m not sure how to accomplish that.
My code looks like
- (UIView *)tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger) section
{
CGRect bounds = CGRectMake(0, 0, [tableView frame].size.width, 48);
UIView *header = [[UIView alloc] initWithFrame:bounds];
UILabel *labelOne = [[UILabel alloc] initWithFrame:
CGRectMake(0, 0, bounds.size.width - 80, 18)];
UILabel *labelTwo = [[UILabel alloc] initWithFrame:
CGRectMake(0, 20, bounds.size.width - 80, 18)];
CGRect frameOne = [labelOne frame];
CGRect frameTwo = [labelTwo frame];
[labelTwo setIsAccessibilityElement:NO];
[labelOne setAccessibilityFrame:CGRectUnion(frameOne, frameTwo)];
// ...
return header;
}
I’ve got two UILabels, which I want to combine into one for the purposes of VoiceOver. I accomplish this by ignoring the second label and extending the frame of the first label to cover the area of the second label. (The second label is immediately below the first.) The problem is getting the frames. If I use the code as shown above, the accessibility frame is the correct size, but is positioned as if the UITableView’s header were in the top left corner of the screen. I tried to modify the code to say
CGRect frameOne = [header convertRect:[labelOne frame] toView:nil];
CGRect frameTwo = [header convertRect:[labelTwo frame] toView:nil];
but the same thing happened. Shouldn’t this latter piece of code convert the UILabels’ frames into window-relative coordinates?
I thought maybe the issue is that when the UIView is created, it doesn’t know where on screen it’s going to be positioned (and as part of a UITableView it may be scrolled all over the place). Is it necessary to implement accessibilityFrame as a message which checks the UIView’s position each time it is called?
There's a helper function that will assist you with doing exactly that: UIAccessibilityConvertFrameToScreenCoordinates. This function takes a CGRect and converts it from a view's coordinate system into screen coordinates.
I don't think it's the timing of when the UIView is created, as I believe the window should be not-nil by the time tableView:viewForHeaderInSection: is called. I think the problem is the receiver of the convertRect:toView: message. Rather than passing this message to header, you should be passing it to [self view].
You're converting from the receivers coordinate system to that of another view, in this case nil or the UIWindow in your app. When header receives this message, you're converting from header's coordinate system to window's coordinate system, but header itself is a subview of [self view]. Instead, you want to ask [self view] to do the conversion, which should take into account any UINavigationBar's, etc.
CGRect frameOne = [[self view] convertRect:[labelOne frame] toView:nil];
CGRect frameTwo = [[self view] convertRect:[labelTwo frame] toView:nil];