how to do animated transition between different UIViewControllers within a UITabBarController? - animation

I have a UITabBarController,displaying 4 tabs.
I want to add an animated UIViewController transition when user swiping screen to switch tab. (- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController method only work for select tab directly). transition will be in easeinout style.
I tried following codes but not work. only coming UIViewController moves, going UIViewController doesn't show at all.(I printed all UIViewControllers' frame data, all these 4 UIViewControllers are {0,0},{320,480} )
// Get views. controllerIndex is passed.
UIViewController *fromVC = [_tabBarController.viewControllers objectAtIndex:startIndex];
UIViewController *toVC = [_tabBarController.viewControllers objectAtIndex:to];
UIView *fromView = fromVC.view;
UIView *toView = toVC.view;
MWLog(#"from view is %#",fromView);
int direct = startIndex - to;
// calculate move direction.
if (direct < 0) {
CGRect outFrame = fromView.frame;
outFrame.origin.x = -320; // expect fromView will move to {-320,0}, out of screen.
MWLog(#"fromView's frame is %#", NSStringFromCGRect(fromView.frame));
CGRect inFrame = toView.frame;
inFrame.origin.x = 0;
MWLog(#"toView's frame is %#", NSStringFromCGRect(toView.frame));
[UIView beginAnimations:#"moveView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.5f];
toView.frame = inFrame;
fromView.frame = outFrame;
[UIView commitAnimations];
}else
{
// reverse moving. ignored....
}
Could you tell me what's wrong and how to do it correctly? thanks in advance!

finally I found the solution.
use CATransition animation, type push, type left or right depending on direction(by calculating tabbarcontroller's selectedIndex property). then, add this animation to tabbarcontroller's container view.
This view's reference can be got by enumerate all UIViews in [tabbarcontroller subviews] array. Actually, if no custom UIView, tabbarcontroller contains 2 subviews, one is UITabBar, the other is the container view, UITransitionView. Add animation on this view, you can enable page transition animation for different content screen.

Related

OSX 10.10 NSSplitViewController content sizes and resizing

The basis of my problem is that when I resize my window, the left pane of my split view resizes and the right side keeps a fixed width, i'd like it to work the other way around.
If I try to move the split divider to make the right side bigger, it snaps back.
I add the SplitView items in my NSSplitViewController subclass like this:
// Add a new SplitViewItem with list view
if (self.tabView == nil)
{
self.tabView = [self.storyboard instantiateControllerWithIdentifier:#"ListTabView"];
}
[self addChildViewController:self.tabView];
NSSplitViewItem *slSplitView = [self splitViewItemForViewController:self.tabView];
[slSplitView setCanCollapse:NO];
[slSplitView setHoldingPriority:260];
if (self.mediaview == nil)
{
self.mediaview = [self.storyboard instantiateControllerWithIdentifier:#"MediaView"];
}
[self insertChildViewController:self.mediaview atIndex:1];
NSSplitViewItem *slSplitViewMedia = [self splitViewItemForViewController:self.mediaview];
[slSplitViewMedia setCanCollapse:NO];
[slSplitViewMedia setHoldingPriority:251];
The subviews in my mediaView have their widths set to >=400 so that's not the issue.

xcode UITapGestureRecognizer on scrollview not calling until second tap

I have the following code to dismiss the keyboard if the user taps the background. It works fine if the scrollview is in the PointZero position, but if the user scrolls the view and then selects the textview, it doesn't call the "dismissKeyboard' method until the 2nd background tap.
On the first tap (for some reason) moves the scrollview offset to align with the scrollview frame to the screen bottom. The second tap will dismiss the keyboard and run the code below. I know it has to do with the scrollview. Any help would be appreciated.
Thanks
- (void)viewDidLoad {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
tapGesture.cancelsTouchesInView = NO;
[_scrollView addGestureRecognizer:tapGesture];
}
-(void)dismissKeyboard {
[self.view endEditing:YES];
}
- (void)keyboardWasShown:(NSNotification *)notification {
scrollViewRect = _scrollView.contentOffset.y;
NSDictionary* info = [notification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
keyboardSize.height += 10;
CGFloat viewBottom = CGRectGetMaxY(self.scrollView.frame);
if ([_itemNotes isFirstResponder]) {
CGFloat notesBottom = CGRectGetMaxY(_itemNotes.frame);
viewBottom -= notesBottom;
if (viewBottom < keyboardSize.height) {
keyboardSize.height -= viewBottom;
CGPoint scrollPoint = CGPointMake(0.0, keyboardSize.height);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
else {
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
}
else {
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification {
CGPoint scrollPoint = CGPointMake(0.0, scrollViewRect);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
EDIT:
So I figured out a solution but it seems like there must be a better way to handle this. The problem was because I was setting the contentOffset of the scrollView so that the contentSize was beyond the screen boundaries. Thus the first tap was moving the scrollView contentOffset back within the screen boundaries and the second was performing the tap gesture. I will post my solution below hoping that someone has a better answer.
I would recommend setting
_scrollView.layer.borderColor = [UIColor redColor].CGColor;
_scrollView.layer.borderWidth = 1;
This will show you exactly where your scrollview boundaries are, which may not be where you think they are, or may be covered by something else. Also, when I open the keyboard, I generally set the scrollview frame bottom to the top of the keyboard. Otherwise, you may have content below the keyboard you can't get to. Not sure if this is exactly related to your issues.
I am assuming there must be a better solution to this but I was able to solve the issue by extending the contentSize when the keyboard is displayed and then shrinking it back down when the keyboard is hidden.
Set a float (scrollViewHeight) to hold the original content size for the reset.
//add this right before setting the content offset
scrollViewHeight = _scrollView.contentSize.height;
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width , scrollViewHeight + keyboardSize.height);
//add this right before reseting the content offset
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width , scrollViewHeight);
It really seems like there must be a better way that I'm not aware of. I will have to go back through the documentation to see if there is another way.

select a view by clicking osx 10.6

i created a image view
for(int i=0; i<pcount; i++)
{
int x = rand() % 350;
int y = rand() % 350;
NSRect rect = NSMakeRect((x+10),(y+10), 200, 200);
//NSImageView *imageView
imageView1 = [[NSImageView alloc]initWithFrame:rect];
[imageView1 setTag:i];
// imageView = [[NSImageView alloc]initWithFrame:rect];
// [imageView1 rotateByAngle:rand() % 150];
[imageView1 setImageScaling:NSScaleToFit];
[imageView1 canBecomeKeyView];
NSImage *theImage = [[NSImage alloc]initWithContentsOfURL:(NSURL*)[patharray objectAtIndex:(i)]];
[imageView1 setImage:theImage];
[[imageView1 cell] setHighlighted:YES];
[[layoutCustom view] addSubview:imageView1 positioned:NSWindowMovedEventType relativeTo:nil];}
now how can select each image view by mouse click ? thanks in advance.
I'm assuming here that you have your reasons for not using existing collection views. So from what I read in your code you have layoutCustom.view, which contains a bunch of NSImageViews. Here are two options:
In your layoutCustom object implement the mouseDown: (or mouseUp: or both). Take the event location convert it view coordinates and look for any subview for which CGRectContainsPoint(subview.frame, mouseDownPoint) return YES. You should select that view.
Subclass NSImageView and implement mouseDown: (or mouseUp: or both). On mouseDown: simply set a "selected" flag. Either the view can draw something itself when selected or the layoutCustom object can observe the property and draw the selection accordingly.
I would prefer option 1 because it simpler, requires fewer classes and fewer interactions between objects.
// Option 1 (in layoutCustom class)
- (void) mouseDown:(NSEvent*)theEvent {
CGPoint mouseDownPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
for (NSView *view in self.subviews) {
if (CGRectContainsPoint(view.frame, mouseDownPoint)) {
// Do something to remember the selection.
// Draw the selection in drawRect:
[self setNeedsDisplay:YES];
}
}
}
// Option 2 (in Custom subclass of NSImage)
- (void) mouseDown:(NSEvent*)theEvent {
self.selected = !self.selected;
}
// Option 2 (in layoutCustom class)
- (void) addSubview:(NSView*)view positioned:(NSWindowOrderingMode)place relativeTo:(NSView*)otherView {
[super addSubview:view positioned:place relativeTo:otherView];
[self startObservingSubview:view];
}
- (void) willRemoveSubview:(NSView*)view {
[self stopObservingSubview:view];
}
- (void) startObservingSubview:(NSView*)view {
// Register your KVO here
// You MUST implement observeValueForKeyPath:ofObject:change:context:
}
- (void) stopObservingSubview:(NSView*)view {
// Remove your KVO here
}
I've got a better idea: Instead of fighting with converting mouse clicks in a view to coordinates and then figuring out how to map it to the right subview or sub-image, why not have one big (or scrolling?) view and then add your images as giant "NSButton" objects (set to custom type), where the button images can be the images you want to add.
As for how to select each image? You can either subclass "NSButton" and keep track of some custom data within it, or you can use a "tag" to figure out which button was pressed in your "IBAction" method and then decide what to do with it.
Another approach might be to embed your images into NSTableView cells...

Custom animation when switching tab/viewcontroller in UITabBarController

I'd like to make a UITabBarController tab switching animation similar to pop and push animation of navigation controller.
That's means if I select a tab at the left of the current tab, the view of new viewcontroller move into the screen from the left, and the view of old/current viewcontroller move out of screen to the right (similar to pop).
I can only achieve this at the moment but I don't know how to implement slide in/out effect.
Thank you!
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController:
UIView *fromView = tabBarController.selectedViewController.view;
NSInteger fromIndex = tabBarController.selectedIndex;
UIView * toView = [viewController view];
NSInteger toIndex = [[tabBarController viewControllers] indexOfObject:viewController];
[UIView transitionFromView:fromView
toView:toView
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {
if (finished) {
tabBarController.selectedIndex = toIndex;
}
}];
}

CGGradient isn't visible (not using interface builder) and UIButtons can't be triggered

I have created a view that contains a CGGradient:
// Bar ContextRef
CGRect bar = CGRectMake(0, screenHeight-staffAlignment, screenWidth, barWidth);
CGContextRef barContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(barContext);
CGContextClipToRect(barContext,bar);
// Bar GradientRef
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components[16] = { 1.0,1.0,1.0,0.0, 0.0,0.0,0.0,1.0, 0.0,0.0,0.0,1.0, 1.0,1.0,1.0,0.0};
CGFloat locations[4] = {0.95,0.85,0.15,0.05};
size_t count = 4;
CGGradientRef gradientRef = CGGradientCreateWithColorComponents(colorSpace, components, locations, count);
// Draw Bar
CGPoint startPoint = {0.0,0.0};
CGPoint endPoint = {screenWidth,0.0};
CGContextDrawLinearGradient(barContext, gradientRef, startPoint, endPoint, 0);
CGContextRestoreGState(barContext);
This code is called in the drawRect method of the UIView. I then use a UIViewController to access the created view.
- (void)loadView {
MainPageView *mpView = [[MainPageView alloc] initWithFrame:[window bounds]];
[self setView:mpView];
[mpView release];
}
and displayed on the screen through the appDelegate:
mpViewController = [[MainPageViewController alloc] init];
[window addSubview:[mpViewController view]];
[window makeKeyAndVisible];
The UIView contains more objects, such as UIButtons, that are visible. I am assuming because they are added as a subview. But I can't work out how to add the CGGradient as a subview? Does it need to be? Is there another reason CGGradient is not visible?
I also don't get the functionality on the UIButtons. I guess that is because of where I have added the UIButtons to the view. Do the buttons need to be added in the UIViewController or the appDelegate to have functionality. Sorry to ask what would seem like simple questions but I am trying to accomplish the programming without the Interface Builder and material on that is scarce. If anyone could point me in the right direction on both these problems I would really appreciate it.
Thanks!
The functionality on the buttons was lost because the frame was too large but the buttons were still visible because the background was clearColor

Resources