Xcode 5 - Swipe switch view with constant background - ios

I understand how to implement UISwipeGestureRecognizer, but I do not understand how to use multiple views properly in collaboration with it.
My ultimate goal is to provide a sleek interface where buttons or swiping may be used to change views. I am hoping for a constant background rather than a background image show it is transferring to the exact same image again. I am using storyboarding currently where each view has its own controller, and I would like (if possible) to keep it as close to this format for visual clarity of what is going on.
I have read that subviews may be my best hope for this sort of scenario (keeping them to the right until a swipe is called), but that would break up the current storyboarding structure I am using, and most certainly ruin any visual clarity.
Does anyone have any suggestions?

I did same programmatically, but you can achieve same using storyboard
1. You need base view which will keep same background
2. Add 3 Views (or 2 depending on ur requirement) Left, Middle, Right with transparent backgrounds as follows in viewDidLoad of base view controller
[self addChildViewController:myChildViewController];
[myChildViewController view].frame = CGMakeRect(x,y,width,height);//Left one will have x = -320, y=0 ,Middle x= 0, y= 0, Right x = 32O etc.
/* Add new view to source view */
[self.view addSubview:[myChildViewController view]];
/* Inform 'didMoveToParentViewController' to newly added view controller */
[myChildViewController didMoveToParentViewController:self];
3. In handle Swipe method change frames of view with animation which will make it look like swiping page
e.g
//swipe left, get right view in middle
[UIView animateWithDuration:0.2 animations:^{
CGRect frame = rightViewController.view.frame;
frame.origin.x = 0;
frame.origin.y = 0;
rightViewController.view.frame = frame;
CGRect middleViewFrame = middleViewController.view.frame;
middleViewFrame.origin.x = -320;
middleViewController.view.frame = middleViewFrame;
}];

You could use a navigation to do this. If you don't want the navigation bar, you can hide it. You can connect the left swipe gesture recognizer to a segue to the next controller, and connect the right swipe gesture recognizer to an unwind segue (or call popViewControllerAnimated: from its action method). If you want a constant background, then you need to add that to the navigation controller's view (as a background color), and have the child view controller's views be transparent (or partially so). This code in the navigation controller's root view controller will add the background:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"img.tiff"]];
}

I know exactly what you're talking about and I'm actually doing the same with my current project.
I accomplished this by using Interface Builder and a single view controller. Basically I placed a UIImageView in the view and set it to the background you wish, then I put a transparent UIScrollView on top of it. Inside that scroll view I put the two views I want to scroll horizontally through.
Don't forget to enable UIScrollView paging. In my case, I had two table views. Starting from the first one, if you swiped from right to left it would scroll to the next table view, and if you swiped left to right it would scroll back to the first.

Related

Animate a view on key window while dragging another view with UILongPressGestureRecognizer

I have added UILongPressGestureRecognizer to a view, and after long press event, the user can drag the view.
I have added a view on the key window (need the custom view over the navigation and tab bar controllers, that is why need to add it on key window) using below code:
// add the custom view on the key window.
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:customView];
Now, when I am dragging the first view beyond the (screenSize/2) point, I want the customView to animate from the right side of the view. I tried the following code to present the view:
// animate the customView view.
[UIView animateWithDuration:0.50f animations:^{
customView.frame = CGRectMake(SCREEN_WIDTH - customViewWidth, 0, customViewWidth, SCREEN_HEIGHT);
} completion:nil];
But the view does not appear neither it animates. I even tried to use the dispatch_async(dispatch_get_main_queue(),{}); but still no success.
Any help will be appreciated.
You should use UIAttachmentBehavior.
It specifies a dynamic connection between two dynamic items, or between a dynamic item and an anchor point. When a dynamic item moves, either by tracking a gesture or via other input, any attached dynamic item also moves—if possible given its other dynamic parameters and boundaries. You can configure an attachment behavior using its length, damping, and frequency properties.

UIButton created outside view not working

I have an application I'm making in storyboards. I want to have a tutorial-type of view. I decided to go with a freeform view controller and am filling it with 600x600 views that count as the pages. The problem I'm having is that when I have a UI button animate to the next page, the buttons that were created outside of the visible view don't seem to work. I even moved a view over so the button was half-visible and only half the button works when I move the view over.
Here's my next page code:
- (void)nextPage {
if (scrolling) return;
scrolling = YES;
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = self.tutorialView.frame;
frame.origin.x -= 50; //frame.size.width;
[self.tutorialView setFrame:frame];
}];
scrolling = NO;
}
I currently have it moving only 50px instead of the whole page for testing purposes.
For testing purposes, I've started it half-way through and only half the button works. I've started it with the second view on top of the other one halfway visible and the same thing happens (only half the button works). Otherwise, when I tap the next button on the first view the buttons on the second view don't work (buttons created outside the initial view).
Views don't receive touch events where they're outside the bounds of their superview. You'll need to increase the button's superview's size.
You can visualize this behavior by setting clipsToBounds = YES - then you'll only see the touchable area of your button.
(You can override this behavior, but you probably shouldn't.)

How to animate transition between two views without using two view controllers?

I am trying to simulate a deck of cards, where a swipe over the screen makes the next card enter the display from the right, covering the card that is currently visible. I know how to program this using two view controllers and custom segues, but I want to keep it simple. I therefore want to stay within one and the same view controller, copy the current view into a temporary view, draw the new view, and then animate the new view to drift in from the right and cover the old one. Here's my attempt:
- (IBAction)SwipeLeft:(id)sender
{ UIView *sv = self.view;
[self Layout]; // this is where the next card is drawn
UIView *dv = self.view;
dv.center = CGPointMake(sv.center.x + sv.frame.size.width, sv.center.y);
sv.center = CGPointMake(sv.center.x, sv.center.y);
[UIView animateWithDuration:0.3
animations:^
{ dv.center = CGPointMake(sv.center.x, sv.center.y);
sv.center = CGPointMake(sv.center.x - sv.frame.size.width, sv.center.y);
}];
NSLog(#"Swipe left");
}
When I run this code, I do see the new card enter the screen appropriately, however, the 'old' view dissappears immediately and turns into a black screen before the animation starts.
How can I correct this?
Clearly this code does not work, as both pointers point at the same memory location. I decided to solve my problem in a different way. Rather than trying to copy a View object, I create a screen shot, copy the UIImage into a View object, cover the screen under the copy of the old screen when I draw the new screen and than animate that View object. Probably a smarter solution. It works great.

how to show an overlapping view iOS

I have a view with some UI components and a button on it, upon touch of a button I want to show a half view with some textfields on it overlapping the initial view, the initial view should be visible partly , the overlapping view will cover only half screen from bottom. Is this possible ?
I don't have any code as I am unable to figure out what it needs to be done, as we show any view it covers the entire screen.
Thanks
there are several ways you can do this, here are two:
1) add a popover controller that gets displayed on your button press:
here's some apple documentation on popovers: https://developer.apple.com/Library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/Popovers.html
2) add the new view as a subview to your UIViewController
PROGRAMICALLY:
in the viewDidLoad function you can do the following to initialize the halfScreenView
GLfloat topOffset = self.view.frame.size.height/2;
UIView halfScreenView = [[UIView alloc] initWithFrame: CGRectMake(0, topOffset , [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - topOffset)
[self.view addSubview:halfScreenView];
-more logic might be needed if you support Landscape orientation, you can always re-assign the location of the view with halfScreenView.frame.origin and halfScreenView.frame.size
-initially you can have this view be hidden
halfScreenView.hidden = YES;
-when you click the button it will show the overlaying view:
halfScreenView.hidden = NO;
USING STORYBOARD:
you can also set up your overlaying view in the storyboard if you have one
-drag a UIView into your UIViewController and set it up where you want it to be located
-initialize the view to be hidden by checking the hidden box in the attribute inspector
-add the view as a property to your view
-manage when to show this view with self.halfScreenView.hidden
-this technique allows you to customize what is inside the new view within the storyboard which is nice
FOR BOTH:
-be careful with layers, you don't want your view to show up behind the one you already present. In the storyboard the last thing inserted goes on top. With in the code you can always access/change the views z position with halfScreenView.layer.zPosition (higher z values are on top)
First create a new class subclassing UIViewController called SecondView (or whatever you want), then design the UI the way you want (in its .xib file)
Then go to your main view controller's file and make an IBAction for that button.
In that method, write:
SecondView* second = [[SecondView alloc] initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height/2, height, width);
[self.view addSubview:second.view];
This will add it to the bottom half of the screen. Put your own parameters for its height and width. When you want to dismiss the view, you can do this inside your SecondView class
[self.view removeFromSuperview];
You can deal with the textFields from within the SecondView class and have them communicate with your other view by doing the following in SecondView.h
#property IBOutlet UITextField* textField;
Hope this helps!
Yes, assuming you are using Interface Builder, go ahead and build the overlapping view and hook up all of the IBOutlets and IBActions. Say this view is called myView. Set myView.hidden = YES and myView.enabled = NO. This hides and disables myView so that it isn't even there from the user's perspective. In the appropriate button's IBAction, change the hidden and enabled properties to YES. That will make the view visible and active again.

uitableview with header like instagram user profile

I've been struggling with this for quite a while now.
I have to implement an user profile similar to what Instagram has in their ios app.
When clicking on the first to buttons on that tab bar like thing all the contents downwards from it changes. The tableview that is displayed on the bottom part has dynamic size so they keep account of that also.
I have something implemented where the top part is a UIView with 5 buttons and based on them the bottom part (witch is like a container view) changes content. And these two (top uiview and bottom container view) are part of UIScrollView. But this way I can't get information back in time on the size about the tableview's size that I want to display in the bottom part in order to modify the UIScrollView's size. And I have a feeling this is a flawed way to do it.
I would really appreciate any ideas oh how to implement this king of interaction. Thank you.
I believe it's a headerView on a UITableView or a UICollectionView, depending on which view mode you have selected. When you tap one of the buttons it changes out the UITableView to a UICollectionView or vice versa.
You want to keep track of the current contentOffset for whichever is being displayed (UICollectionView and UITableView are both subclasses of UIScrollView so you will be able to get this from both) and then set the contentOffset on the view you're switching to.
Setup an ivar for the UIView header subclass so you can easily re-use it.
This is what I have. My problem is that I'm mot getting back in useful time the tableview's frame height from the tableview controller to the UserProfileViewController in order to change the latter's scrollview size. I also feel that I'm somehow doing this backwards so any suggestions are more than welcome.
This view has two parts: an upper part and a lower part. The parent view is a scroll view. What I wanted to achieve with this is having a sort of tab bar in the upper part that will controll waht will appear in the lower part.
The upper part has a flip animation when the upper left button is pressed to reveal another view.
The way this is achieved is by having 2 views: a dummy view and the back view. The dummy view has the front view as a child. The front view is the one that containes all the buttons.
The code for this animation is achieved in this way:
- (IBAction)infoButtonPressed:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.hoverView cache:YES];
if ([self.headerView superview]) {
[self.headerView removeFromSuperview];
[self.hoverView addSubview:self.backOfHeaderView];
[self.infoButton removeFromSuperview];
[self.backOfHeaderView addSubview:self.infoButton];
} else {
[self.backOfHeaderView removeFromSuperview];
[self.hoverView addSubview:self.headerView];
[self.infoButton removeFromSuperview];
[self.headerView addSubview:self.infoButton];
}
[UIView commitAnimations];
}
The lower part is made out of a container view that acts as a place holder.
When a button is pressed a different view controller is displayed in the container view.
Each view controller has a container view of it's own. The specific view of that view controller (tableview) is added to it's container view when the controller is loaded. It also makes sure that if the tableview is already added to the container view it will be removed. All this is done in each specific view controller.
In the view controller of the User Profile view there is an instance of the container view and one of a UIViewController that also acts as a placeholder(named currentViewController from now on). When a specific button is pressed it checks if the an instance of the view controller that we want to display already exists. If not it will make one and will set it's tableview's frame to the bounds of the container view. After that it will remove the currentViewController's view from the superview and the currentViewController itself from the parent viewcontroller to make sure that if there is something assigned to these they will not be there. Then it goes and assigns the desired viewcontroller to the currentViewController. It also assigns the desired viewcontroller's containerView instance to the containerview in the parent viewcontroller (the User Profile viewcontroller). At the end it will add the desired viewcontroller as a child to the main viewcontroller (the User Profile viewcontroller) and desired viewcontroller's view to the containerView of the main viewcontroller.
This is the code for one of the buttons:
//Check if there is an instance of the viewcontroller we want to display. If not make one and set it's tableview frame to the container's view bounds
if(!_userWallViewController) {
self.userWallViewController = [[WallViewController alloc] init];
// self.userWallViewController.activityFeedTableView.frame = self.containerView.bounds;
}
[self.userWallViewController.containerView addSubview:self.userWallViewController.activityFeedTableView];
//If the currentviewcontroller adn it's view are already added to the hierarchy remove them
[self.currentViewController.view removeFromSuperview];
[self.currentViewController removeFromParentViewController];
//Add the desired viewcontroller to the currentviewcontroller
self.currentViewController = self.userWallViewController;
//Pass the data needed for the desired viewcontroller to it's instances
self.userWallViewController.searchURLString = [NSString stringWithFormat:#"event/user/%#/", self.userID];
self.userWallViewController.sendCommentURLString = [NSString stringWithFormat:#"event/message/%#", self.userID];
self.userWallViewController.totalCellHeight = ^(float totalCellHeight){
self.userWallViewController.numberOfCells = ^(float numberOfCells){
NSLog(#"The total number of cells: %f", numberOfCells);
NSLog(#"The total cell height: %f", totalCellHeight);
self.scrollView.contentSize = CGSizeMake(320.0, totalCellHeight + 172.0 + 33.0);
CGRect newFrame = self.userWallViewController.containerView.frame;
newFrame.size.height = totalCellHeight + 33.0;
self.userWallViewController.containerView.frame = newFrame;
NSLog(#"Container view: %f", self.containerView.frame.size.height);
NSLog(#"Scroll view: %f",self.scrollView.contentSize.height );
};
};
//Add this containerview to the desired viewcontroller's containerView
self.userWallViewController.containerView = self.containerView;
//Add the needed viewcontroller and view to the parent viewcontroller and the containerview
[self addChildViewController:self.userWallViewController];
[self.containerView addSubview:self.userWallViewController.view];
[self performSelector:#selector(changeScrollView) withObject:self afterDelay:0.5];
//CLEAN UP THE CONTAINER VIEW BY REMOVING THE PREVIOUS ADDED TABLE VIEWS
[self.userFansViewController.userSimpleTableView removeFromSuperview];
[self.fanOfViewController.userSimpleTableView removeFromSuperview];
[self.userPublishedMovellaListViewController.gridView removeFromSuperview];
[self.userPublishedMovellaListViewController removeFromParentViewController];
self.userPublishedMovellaListViewController = nil;
}
I know this answer is over a year late, but I wanted to state my hypothesis on it...just incase it might help someone else later. Im implementing a similar view and came to this conclusion. Anyone is welcomed to correct me if I'm wrong.
I think that perhaps the top view is a header view and the two options that seem like a collection view and a table view are both collection views.
Because the layout of collection views can be fine tuned to the most minute details, I think the view that looks like a table view is just a really specifically designed collection view. And when switching between the views, the collection view's data and properties are being swapped and reloaded.

Resources