Following this tutorial, i ended up with a nice arrow for my UITabBar in iPhone.
Now i wanted to do the same for iPad, but it seems to not work.
I tried
- (CGFloat) horizontalLocationFor:(NSUInteger)tabIndex
{
CGFloat tabItemWidth;
CGFloat halfTabItemWidth;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
tabItemWidth = 320 / tabBarController.tabBar.items.count;
halfTabItemWidth = (tabItemWidth / 2.0) - (tabBarArrow.frame.size.width / 2.0);
}
else
{
tabItemWidth = 768 / tabBarController.tabBar.items.count;
halfTabItemWidth = (tabItemWidth / 2) - (tabBarArrow.frame.size.width / 2);
}
return (tabIndex * tabItemWidth) + halfTabItemWidth;
}
following the example, taking the tabBar dimensions for iPad, but the arrow is still so far from being in the middle of each tab.
Any help?
Try this in place of the current "horizontalLocationFor" method you have:
- (CGFloat) horizontalLocationFor:(NSUInteger)tabIndex
{
// Get the frame of the selected tab item's view.
// Add one becuase the first subview is the not a button.
CGRect tabFrame = [[[[[self tabBarController] tabBar] subviews] objectAtIndex:tabIndex+1] frame];
// Add tab x to half tab width and substract hald arrow image width to center it.
return tabFrame.origin.x + (tabFrame.size.width * .5) - (tabBarArrow.frame.size.width * .5);
}
The original solution assumed that the tab bar width was the entire screen, but on ipad 4 items only fills a portion of the tab bar width, hence dividing the width by the number of items doesn't get you the correct positions.
Related
I've created a RootViewController / RootView that:
Handles the content layout for the app
Exposes and interface for performing application level behaviors, like presenting the "hamburger" menu or overlay views with CAKeyframe animations.
This is in accordance with good practice.
The Problem:
When the main content view presents a form, there's a utility to animate the frame of that view, when a field is selected that would otherwise be obscured by the keyboard. This has been working fine all the way up until iOS 8.0.2
On iOS 8.0.2 the frame for the form will no longer animate if you set a negative value for origin.y. Instead of going from the current origin.y to the required origin.y it jerks down by the amount it was supposed to move, then animates back to 0.
If I present the form outside of the RootVC it works correctly.
What I've tried:
Checked that RootView is not doing anything in layout subviews to prevent the animation. (In iOS8.0 it was. I removed this and problem was solved. Only to return in iOS8.0.2)
Checked the BeginFromCurrentState flags.
Instead of animating the form view, animate [UIScreen mainScreen].keyWindow. Works but causes some other side effects that I don't want.
Question:
What has changed with animation of UIViewControllers that are contained in another view in iOS8.0.2. It seems to be something very fundamental.
The code that animates frame to move input fields out the keyboard's way:
Looks something like this:
- (void)scrollToAccommodateField:(UIView *)view
{
UIView *rootView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
CGPoint position = [view convertPoint:view.bounds.origin toView:rootView];
CGFloat y = position.y;
CGFloat scrollAmount = 0;
CGFloat margin = 25;
CGSize screenSize = [self screenSizeWithOrientation:[UIApplication sharedApplication].statusBarOrientation];
CGSize accessorySize = CGSizeMake(_view.width, 44);
CGFloat maxVisibleY = screenSize.height - [self keyboardSize].height - accessorySize.height - margin;
if (y > maxVisibleY)
{
scrollAmount = maxVisibleY - y;
CGFloat scrollDelta = scrollAmount - _currentScrollAmount;
_currentScrollAmount = scrollAmount;
[self scrollByAmount:scrollDelta];
}
else
{
if (_currentScrollAmount != 0)
{
_currentScrollAmount = 0;
[UIView transitionWithView:_view duration:0.30
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut animations:^
{
_view.frame = [_view bounds];
} completion:nil];
}
}
}
Update:
I've since installed TPKeyboardAvoiding pod and its working very well. . leaving this open, in case its of interest to others.
I have a MKMapView having many MKAnnotations on it.
On a button click, another set of annotations are to be added.
Now on the button click, I have an array of annotations.I add the array of annotations to Mkmapview.
I want the mapview to move to that region where new annotations are added without zoom out or zoom in.
Please help me out with a solution.
I think setting the center to one of the co-ordinates in the array of annotations will serve your purpose
[_mapView setCenterCoordinate:annotationCoOrd zoomLevel:_zoomLvl animated:YES];
where ,annotationCoOrd is one of the co-ordinates in your array and
_zoomLvl is your current zoom-level.
Would be more helpful if you post your code here.
for zoom-level
- (double)getZoomLevel{
MKCoordinateRegion reg=self.region; // the current visible region
MKCoordinateSpan span=reg.span; // the deltas
CLLocationCoordinate2D centerCoordinate=reg.center; // the center in degrees
// Get the left and right most lonitudes
CLLocationDegrees leftLongitude=(centerCoordinate.longitude-(span.longitudeDelta/2));
CLLocationDegrees rightLongitude=(centerCoordinate.longitude+(span.longitudeDelta/2));
CGSize mapSizeInPixels = self.bounds.size; // the size of the display window
// Get the left and right side of the screen in fully zoomed-in pixels
double leftPixel=[self longitudeToPixelSpaceX:leftLongitude];
double rightPixel=[self longitudeToPixelSpaceX:rightLongitude];
// The span of the screen width in fully zoomed-in pixels
double pixelDelta=abs(rightPixel-leftPixel);
// The ratio of the pixels to what we're actually showing
double zoomScale= mapSizeInPixels.width /pixelDelta;
// Inverse exponent
double zoomExponent=log2(zoomScale);
// Adjust our scale
double zoomLevel=zoomExponent+20;
return zoomLevel;
}
- (double)longitudeToPixelSpaceX:(double)longitude
{
return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
}
- (double)latitudeToPixelSpaceY:(double)latitude
{
return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
}
to get the zoom level of the map add the above code in your MKMapView implementation(overriding MKMapview implementation) .
use belo method for move with out zoom
[mapview setCenterCoordinate:cordinate animated:YES];
I've been trying to get the converted CGRect of a UIView within a UIScrollView. It works fine if I'm not zoomed, but once I zoom, the new CGRect shifts. Here is the code that's gotten me close:
CGFloat zoomScale = (scrollView.zoomScale);
CGRect newRect = [self.view convertRect:widgetView.frame fromView:scrollView];
CGPoint newPoint = [self.view convertPoint:widgetView.center fromView:scrollView];
// Increase the size of the CGRect by multiplying by the zoomScale
CGSize newSize = CGSizeMake(newRect.size.width * zoomScale, newRect.size.height * zoomScale);
// Subtract the offset of the UIScrollView for proper positioning
CGPoint newCenter = CGPointMake(newPoint.x - scrollView.contentOffset.x, newPoint.y - scrollView.contentOffset.y);
// Create rect with the proper width/height (x and y set by center)
newRect = CGRectMake(0, 0, newSize.width, newSize.height);
[self.view addSubview:widgetView];
widgetView.frame = newRect;
widgetView.center = newCenter;
I'm fairly certain that my issue lies in the zoomScale - I should probably be modifying the x and y coordinates based on the zoomScale value. Everything I have tried thus far has been unsuccessful, though.
I received the following answer from user Brian2012 on the iOS dev forums:
What I did:
Created a UIScrollView that covers the view controller's main view.
Put a desktop view (a standard UIView) in the scroll view. The origin of the desktop is at 0,0 and the size is bigger than the scroll view so I could scroll around without having to zoom first.
Put some widget views (UIImageView) into the desktop view at various locations.
Set the contentSize of the scroll view to the size of the desktop view.
Implemented viewForZoomingInScrollView to return the desktop view as the view to scroll.
Put NSLogs in scrollViewDidZoom to print out the frame of the desktop view and one of the widget views.
What I found out:
The widget frame never changes from the initial value that I set. So for example, if a widget started at position 108, 108 with a size of 64x64, then the frame is always reported as 108,108,64,64 regardless of zooming or scrolling.
The desktop frame origin never changes. I put the origin of the desktop at 0,0 in the scroll view, and the origin is always reported as 0,0 regardless of zooming or scrolling.
The only thing that changes is the desktop view's frame size, and the size is just the original size multiplied by the scroll view's zoomScale.
Conclusion:
To figure out the location of a widget relative to the coordinate system of the view controller's main view, you need to do the math yourself. The convertRect method doesn't do anything useful in this case. Here's some code to try
- (CGRect)computePositionForWidget:(UIView *)widgetView fromView:(UIScrollView *)scrollView
{
CGRect frame;
float scale;
scale = scrollView.zoomScale;
// compute the widget size based on the zoom scale
frame.size.width = widgetView.frame.size.width * scale;
frame.size.height = widgetView.frame.size.height * scale;
// compute the widget position based on the zoom scale and contentOffset
frame.origin.x = widgetView.frame.origin.x * scale - scrollView.contentOffset.x + scrollView.frame.origin.x;
frame.origin.y = widgetView.frame.origin.y * scale - scrollView.contentOffset.y + scrollView.frame.origin.y;
// return the widget coordinates in the coordinate system of the view that contains the scroll view
return( frame );
}
I have also similar kind of issue, i fixed it by a different trick. i catch the zoom scale in a temporary variable, and set scrollView's zoom scale to minimum(1.0) and then calculate my frame using convertRect() and set the original zoom scale again
CGFloat actualZoomScal = self.baseVideoView.zoomScale;
CGPoint actualOffset = self.baseVideoView.contentOffset;
self.baseVideoView.zoomScale = 1.0;
CGRect iFrame = [[RGLayout layout] rectToPixels:[self recordingIndicatorFrame]];
self.recordIndicator = [[RiscoRecordingIndicatorView alloc] initWithFrame:[self convertRect:iFrame fromView:self.previewView]];
[self addSubview:self.recordIndicator] ;
[self bringSubviewToFront:self.recordIndicator] ;
self.baseVideoView.zoomScale = actualZoomScal;
self.baseVideoView.contentOffset = actualOffset;
Looking at this question: Prevent UIScrollView from moving contents to top-left, i'm having the exact issue.
I'm using this tutorial: http://cocoadevblog.heroku.com/iphone-tutorial-uiimage-with-zooming-tapping-rotation
Back to the similar question, if i disable the UIScrollViewPanGestureRecognizer, i'm not able to pan the zoomed image anymore.
I have a UIImageView within a UIScrollView, and i want to be able to zoom and pan the image as well.
How can i do tho disable the contents moving to the top left corner when zooming in?
Seems i solved tweaking my UiScrollView Autosizing and Origin in the Size inspector \ Attributes inspector. I unchecked Paging Enabled and the magic happened.
Just in case anyone else comes here and none of the other answers seem to work ( which was my case ), what did the trick for me was setting the contentSize of the scrollView. Just set it to the size whatever subview you are zooming in on and it should work.
Make a subclass of UIScrollView, and add this method to it:
- (void)layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
//get the subView that is being zoomed
UIView *subView = [self.delegate viewForZoomingInScrollView:self];
if(subView)
{
CGRect frameToCenter = subView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
subView.frame = frameToCenter;
}
else
NSLog(#"No subView set for zooming in delegate");
}
If I understand you right, you want to allowing scrolling only when theImageView is zoomed in, then a scrollView.zoomScale > 1. For my app requirement I am using this.
Add UIScrollView's delegate method as follows and check.
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
CGFloat offsetY = 0;
if (aScrollView.zoomScale > 1)
offsetY = aScrollView.contentOffset.y;
[aScrollView setContentOffset: CGPointMake(aScrollView.contentOffset.x, offsetY)];
}
I'm new to iPhone development, coming from a web application development background and I'm working on my first project. I chose to create a Navigation based project, since after reading it seemed to be the easiest way to get what I'm after. How do you change the width of the UITableView? Eventually, I'd like to have a top bar, UITableView, and bottom bar be 304px wide. I've tried the following in my RootViewController's viewDidLoad method, but I'm doing it wrong:
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.width = 200;
self.tableView.frame = tableViewFrame;
Thanks for any help in advance.
If you want to change the width of the tableViewCell.. go to cellForRowAtIndexPath, and assign it there.
You could also do -
CGFloat tableBorderLeft = 1;
CGFloat tableBorderRight = 1;
CGRect tableRect = self.view.frame;
tableRect.origin.x += tableBorderLeft; // make the table begin a few pixels right from its origin
tableRect.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
tableView.frame = tableRect;
For changing the size of header
-(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section
{
return 150.0; //Give a value
}
For changing size of footer
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 150.0;//Give a value
}