Here is an interesting problem. On the iPhone, I have a view set up that has a toolbar on the bottom of the screen. I am currently trying to make this a universal app so that it runs on iPad as well. I would like the toolbar to be at the top of the iPad screen, so in the viewDidLoad method of the specific viewController I have the following code.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//move the toolbar to the top of the page and move the webview down by the height of the toolbar
CGRect toolBarFrame = self.aToolBar.frame;
CGRect webFrame = self.aWebView.frame;
webFrame.origin.y = toolBarFrame.size.height;
[self.aWebView setFrame:webFrame];
toolBarFrame.origin.y = 0;
[self.aToolBar setFrame:toolBarFrame];
[Utils errorString:[NSString stringWithFormat:#"origen: x=%f y=%f", self.aToolBar.frame.origin.x, self.aToolBar.frame.origin.y]];
[Utils errorString:[NSString stringWithFormat:#"origen: x=%f y=%f", self.aWebView.frame.origin.x, self.aWebView.frame.origin.y]];
}
The problem I am having is that the webView moves down fine, but the toolbar only moves up to about what seems to be the height of a iPhone screen. The call to errorString tells me that the webView's origin is at 0,44 (where it should be) and that the toolbar's origin is at 0,0, but it is actually somewhere in the middle of the screen!
Anybody have a clue what is going on here?
I'd say this is because the frame is being set to the top of an iPhone frame (so 320px from the bottom), and then afterwards the view is being resized to fit the iPad screen. However UIToolbar by default is set to stick to the bottom of the window (fixed bottom margin, and flexible top margin) so it's staying 320px from the bottom.
To fix this try:
[self.aToolbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
before setting the toolbar's frame (if it doesn't work before setting the frame, try putting it after)
Related
I have a UIScrollView that is 320 by 100 (width and height) and UIPageControl with 4 pages. My App has 4 icons at the top in the scroll view but only displays one of the icons with portions of the other icons on the edges (so the user can know that they can scroll). The user can either tap on the pagecontrol to have it change left or right and it correspondingly changes the icons in the scroll view. On the same point, the user can scroll the scroll view and I want it to center on the icon they are scrolling towards and the page control to change. My issue is that whenever I scroll in the IOS simulator, the icons are offset weirdly and display as such regardless of how much I change the parameters I am moving to. It always skips the second icon.
Here is the code for the ScrollViewDidScroll
`- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
float roundedValue = floor(_ScrollView.contentOffset.x / 160);//320
NSLog(#"%f",roundedValue);
self.pageControl.currentPage = roundedValue;
[_dataTable reloadData];
}`
And here is the code for my pageAction
UIPageControl *pageCon = (UIPageControl *)sender;
int pageMoved = pageCon.currentPage;
CGRect movedTo = CGRectMake((pageMoved*190), 0, 320, 100);//160
[_ScrollView scrollRectToVisible:movedTo animated:YES];
All the math works out, im just not sure why its offsetting the images and skipping the second icon.
Currently I've got a UIView of size 100px wide by 40px high. If I add it using
[self.view addSubView:buttonsView];
it adds this small UIVIew to the top left of my iPhone's screen.
Is there any way to make it add to the bottom right instead?
Before adding the buttonView, set its "frame" property:
One way:
buttonsView.frame = CGRectMake(
self.view.frame.size.width - buttonsView.frame.size.width,
self.view.frame.size.height - buttonsView.frame.size.height,
buttonsView.frame.size.width,
buttonsView.frame.size.height );
This should be a pretty common thing to do, but I haven't been able to get it to work exactly right.
I have rectangular content. It normally fits in 320x361: portrait mode minus status bar minus ad minus tab bar.
I have put that content in a UIScrollView and enabled zooming. I also want interface rotation to work. The content will always be a tall rectangle, but when zoomed users might want to see more width at a time and less height.
What do I need to do in Interface Builder and code to get this done? How should I set my autoresizing on the different views? How do I set my contentSize and contentInsets?
I have tried a ton of different ways and nothing works exactly right. In various of my solutions, I've had problems with after some combination of zooming, interface rotation, and maybe scrolling, it's no longer possible to scroll to the entire content on the screen. Before you can see the edge of the content, the scroll view springs you back.
The way I'm doing it now is about 80% right. That is, out of 10 things it should do, it does 8 of them. The two things it does wrong are:
When zoomed in portrait mode, you can scroll past the edge of the content, and see a black background. That's not too much to complain about. At least you can see all the content. In landscape mode, zoomed or not, seeing the black background past the edge is normal, since the content doesn't have enough width to fill the screen at 1:1 zoom level (the minimum).
I am still getting content stuck off the edge when it runs on a test device running iOS 3.0, but it works on mine running 4.x. -- Actually that was with the previous solution. My tester hasn't tried the latest solution.
Here is the solution I'm currently using. To summarize, I have made the scroll view as wide and tall as it needs to be for either orientation, since I've found resizing it either manually or automatically adds complexity and is fragile.
View hierarchy:
view
scrollView
scrollableArea
content
ad
view is 320x411 and has all the autoresizing options on, so conforms to screen shape
scrollView is 480 x 361, starts at origin -80,0, and locks to top only and disables stretching
scrollableArea is 480 x 361 and locks to left and top. Since scrollView disables stretching, the autoresizing masks for its subviews don't matter, but I tell you anyway.
content is 320x361, starts at origin 80,0, and locks to top
I am setting scrollView.contentSize to 480x361.
shouldAutorotateToInterfaceOrientation supports all orientations except portrait upside down.
In didRotateFromInterfaceOrientation, I am setting a bottom content inset of 160 if the orientation is landscape, resetting to 0 if not. I am setting left and right indicator insets of 80 each if the orientation is portrait, resetting if not.
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 2.0
viewForZoomingInScrollView returns scrollableArea
// in IB it would be all options activated
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
scrollView.contentSize = content.frame.size; // or bounds, try both
what do you mean with scrollableArea?
your minZoomScale is set to 1.0 thats fine for portrait mode but not for landscape. Because in landscape your height is smaller than in portrait you need to have a value smaller than 1.0. For me I use this implementation and call it every time, the frame of the scrollView did change:
- (void)setMaxMinZoomScalesForCurrentBounds {
CGSize boundsSize = self.bounds.size; // self is a UIScrollView here
CGSize contentSize = content.bounds.size;
CGFloat xScale = boundsSize.width / contentSize.width;
CGFloat yScale = boundsSize.height / contentSize.height;
CGFloat minScale = MIN(xScale, yScale);
if (self.zoomScale < minScale) {
[self setZoomScale:minScale animated:NO];
}
if (minScale<self.maximumZoomScale) self.minimumZoomScale = minScale;
//[self setZoomScale:minScale animated:YES];
}
- (void)setFrame:(CGRect)rect { // again, this class is a UIScrollView
[super setFrame:rect];
[self setMaxMinZoomScalesForCurrentBounds];
}
I don't think I understood the entire problem from your post, but here's an answer for what I did understand.
As far as I know (and worked with UIScrollView), the content inside a UIScrollView is not automatically autoresized along with the UIScrollView.
Consider the UIScrollView as a window/portal to another universe where your content is. When autoresizing the UIScrollView, you are only changing the shape/size of the viewing window... not the size of the content in the other universe.
However, if needed you can intercept the rotation event and manually change your content too (with animation so that it looks good).
For a correct autoresize, you should change the contentSize for the scrollView (so that it knows the size of your universe) but also change the size of UIView. I think this is why you were able to scroll and get that black content. Maybe you just updated the contentSize, but now the actuall content views.
Personally, I haven't encountered any case that required to resize the content along with the UIScrollView, but I hope this will get you started in the right direction.
If I understand correctly is that you want a scrollview with an image on it. It needs to be fullscreen to start with and you need to be able to zoom in. On top of that you want it to be able to rotate according to orientation.
Well I've been prototyping with this in the past and if all of the above is correct the following code should work for you.
I left a bit of a white area for the bars/custombars.
- (void)viewDidLoad
{
[super viewDidLoad];
//first inits and allocs
scrollView2 = [[UIScrollView alloc] initWithFrame:self.view.frame];
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"someImageName"]];
[scrollView2 addSubview:imageView];
[self drawContent]; //refreshing the content
[self.view addSubview:scrollView2];
}
-(void)drawContent
{
//this refreshes the screen to the right sizes and zoomscales.
[scrollView2 setBackgroundColor:[UIColor blackColor]];
[scrollView2 setCanCancelContentTouches:NO];
scrollView2.clipsToBounds = YES;
[scrollView2 setDelegate:self];
scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;
[scrollView2 setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
[scrollView2 setScrollEnabled:YES];
float minZoomScale;
float zoomHeight = imageView.frame.size.height / scrollView2.frame.size.height;
float zoomWidth = imageView.frame.size.width / scrollView2.frame.size.width;
if(zoomWidth > zoomHeight)
{
minZoomScale = 1.0 / zoomWidth;
}
else
{
minZoomScale = 1.0 / zoomHeight;
}
[scrollView2 setMinimumZoomScale:minZoomScale];
[scrollView2 setMaximumZoomScale:7.5];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
// Portrait
//the 88pxls is the white area that is left for the navbar etc.
self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.width, self.view.frame.size.height - 88);
[self drawContent];
}
else {
// Landscape
//the 88pxls is the white area that is left for the navbar etc.
self.scrollView2.frame = CGRectMake(0, 88, [UIScreen mainScreen].bounds.size.height, self.view.frame.size.width);
[self drawContent];
}
return YES;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
I hope this will fix your troubles. If not leave a comment.
When you want to put a content (a UIView instance, let's call it theViewInstance ) in a UIScrollView and then scroll / zoom on theViewInstance , the way to do it is :
theViewInstance should be added as the subview of the UIScrollView
set a delegate to the UIScrollView instance and implement the selector to return the view that should be used for zooming / scrolling:
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return theViewInstance;
}
Set the contentSize of the UIScrollView to the frame of the theViewInstance by default:
scrollView.contentSize=theViewInstance.frame.size;
(Additionally, the accepted zoom levels can be set in the UIScrollView :)
scrollView.minimumZoomScale=1.0;
scrollView.maximumZoomScale=3.0;
This is the way a pinch to zoom is achieved on a UIImage : a UIImageView is added to a UIScrollView and in the UIScrollViewDelegate implementation, the UIImageView is returned (as described here for instance).
For the rotation support, this is done in the UIViewController whose UIView contains the UIScrollView we just talked about.
UIView *stateView = [getSomeUIView thisOne];
CGRect currentFrame = stateView.frame;
if(currentFrame.size.height == 0.0) {
currentFrame.size = CGSizeMake(260, 60);
}
else {
currentFrame.size = CGSizeMake(260, 0);
}
stateView.frame = currentFrame;
I would expect all the subviews would be hidden when the height of the frame is set to zero however this does not happen (in the iPhone 4.0.1 Simulator).
Any suggestions why or alternatives?
I was planing to later animate the frame so it's a sliding effect. I can not use the y position and move it off screen nor can I create a element to hide it behind since I'm working with a background image and everything on top is transparent/alpha layer.
I've got the same problem. Solved it with clipsToBounds property:
stateView.clipsToBounds = YES
Subviews will only change size if you set their springs and struts to do so.
By default, they are set to "stay the SAME width and height, and stay the same distance from top left corner of the parent view".
You can set the springs/struts in Interface Builder, or in code. e.g.:
aSubView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Use UIScrollView instead of UIView. UIScrollView is made to hide "overflow" and works perfectly.
I have a UIWebView which I want to put under my translucent UINavigationBar. Normally when I put a UIScrollView under a translucent UINavigationBar, I set its contentOffset such that all content will be initially pushed after the bar so that it can be seen; thereafter, the user can scroll text and it will underlap the bar.
The problem is that UIWebView appears not to be a proper subclass of UIScrollView; thus, I can't use setContentOffset. Does anyone have any tips or tricks on getting a UIWebView to look good with a translucent navigation bar? Thanks.
As of iOS 5 you can use the scrollView property of UIWebView, and set a contentInset to adjust the positon.
CGFloat top = 0.0;
if( self.navigationController != nil && self.navigationController.navigationBar.translucent ) {
top = self.navigationController.navigationBar.bounds.size.height;
}
UIWebView* wv = ...
wv.scrollView.contentInset = UIEdgeInsetsMake(top, 0.0, 0.0, 0.0);
The easiest way is to set:
webView.clipsToBounds = NO;
webView.scrollView.clipsToBounds = NO;
It work on bouth iOS 7 & 6, and I didn't try, but on iOS 5 probably too
I achieved this by setting the UIWebView subviews to not clip to bounds, then I could put a toolbar on top of it and get the desired effect:
for (UIView *subview in theWebView.subviews) {
subview.clipsToBounds = NO;
}
I am not sure if there is a clean method to doing this. I have not tried it, but here is an idea:
draw the uiwebview at origin 0,0
intercept all screen touches
if you detect the user dragging up (scrolling up the webview), dont pass the touch on
Instead, move the webview up x pixels so its origin is (0,-x). Then change the height to add x pixels
Youy will need to keep some sort of state so that you know when to stop resizing the webview and start passing on the touches so the webview will scroll.
Getting it back is the same only you do it on a drag down (scrolling down the webview).
Another way to possibly do this is to insert a div in the html code you are rendering so that it is spaced out up on the top of the page. make sure you set your zoom correctly and set the uiwebviews origin to (0, -x) to begin with.
With the advent of iOS 7, the offset height would now need to include the height of the top status area. Otherwise, iOS7 devices will have 20 pixels of webview still hidden under the navigation bar.
In a project that needs to support iOS 7 and older devices, a macro like the one found
here:
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
Can be very useful.
A modified version of zerotool's helpful code listed above could now look something like this:
if (self.navigationController != nil && self.navigationController.navigationBar.translucent) {
top = self.navigationController.navigationBar.bounds.size.height;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
top += [[UIScreen mainScreen] applicationFrame].origin.y;
}
}
// (etc.)