How to create a collapsible UIView - iphone

I need to create a expandable and collapsible UIView of some sort and am not able to pay for a third party control.
This is basically how I would like it to behave:
At the top there should be a UIButton (or similar) that allows the user to toggle between expanded and collapsed.
When expanded I want to be able to place other UIView (e.g. calendar)and when collapsed the surrounding controls should move up.
Does anyone have any ideas how to implement this simply - noob here :(

Subclass a ViewController and have two methods that your button can fire like 'collapse' and 'expand', this might get you started: You can assign new selectors to UIButtons dynamically:
[button addTarget:self action:#selector(eventMethod:)
forControlEvents:UIControlEventTouchUpInside];
Code:
#define COLAPSED_HEIGHT 30
-(void)expand
{
CGRect s= [self getScrerenBoundsForCurrentOriantation];
CGRect f = self.view.frame;
f.origin.y =s.size.height-self.view.frame.size.height;
[UIView beginAnimations:#"expand" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
self.view.frame=f;
//CHANGE YOUR EXPAND/COLLAPSE BUTTON HERE
[UIView commitAnimations];
self.thumbScrollerIsExpanded=YES;
}
-(void)collapseView
{
//re-factored so that this method can be called in ViewdidLoad
CGRect s= [self getScrerenBoundsForCurrentOriantation];
CGRect f = self.view.frame;
f.origin.y =(s.size.height-COLAPSED_HEIGHT);
self.view.frame = f;
self.thumbScrollerIsExpanded=NO; //thumbScrollerIsExpanded is a BOOL property
}
- (void)collapse
{
[UIView beginAnimations:#"collapse" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
[self collapseView];
//CHANGE YOUR EXPAND/COLLAPSE BUTTON HERE
[UIView commitAnimations];
}
-(CGRect)getScrerenBoundsForCurrentOriantation
{
return [self getScrerenBoundsForOriantation:[[UIDevice currentDevice] orientation]];
}
-(CGRect)getScrerenBoundsForOriantation:(UIInterfaceOrientation)_orientation
{
UIScreen *screen = [UIScreen mainScreen];
CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation.
if (UIInterfaceOrientationIsLandscape(_orientation))
{
CGRect temp;
temp.size.width = fullScreenRect.size.height;
temp.size.height = fullScreenRect.size.width;
fullScreenRect = temp;
}
return fullScreenRect;
}
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
if ([animationID isEqualToString:#"expand"])
{
//example
}
else if ([animationID isEqualToString:#"collapse"])
{
//example
}
}

You could try adding a UIView (either in xib or programmatically) off screen, then use a UIView animation to slide it into your main viewing area.
The button would have an IBAction which would toggle the animation (slide in/slide out). You can slide it off screen then set UIView's hidden property to true. When you recall the IBAction, have it check if the view's hidden property is true. If it is, you know to play the animation of it sliding in, if not, then you play the animation of sliding out.

Related

Insert a UIView between 2 other UIViews to create a list with 3 UIView's

I have in my application one ViewController that requires a UIScrollView
In this UIScrollView i have many UIButton's. When i press one button bellow the button that i touched i want to show a UIView animating his entrance. Just like a accordion, like this: Jquery demo
Currently i have this method to open the "accordion":
-(void) openView:(UIView *)view inFrame:(CGRect)final {
CGRect frame = view.frame;
frame.size.height = 0;
frame.origin = finalFrame.origin;
view.frame = frame;
[self.buttonsView addSubview:view];
[UIView animateWithDuration:1.0 animations:^{
view.frame = finalFrame;
} completion:^(BOOL finished){
}];
}
the self.buttonsView is the UIView that i use inside my scrollview.
With this method i can insert a view rigth after my button. But the problem is: I can't open the space between the buttons to enlarge my buttonsView
is there a way to do this?
button1
button2
button3
button 2 clicked:
button1
button2
a view
button3
button 2 clicked again:
button1
button2
button3
And i can't use UITableView
Modify your openView:inFrame: method to also animate the frames of all the buttons below the one you tapped.
Please try this
//in .h file declare one variable
IBOutlet UIButton *btnpreviouslySelected;
CGRect customerButtonFrame,inventoryButtonFrame,templatesButtonFrame;
Consider btnCustomer,btnInventroy,btntemplate are your three buttons & assign them tag as 1,2,3 resp.
viewsearch is new view which you want to add in between two buttons
//in .m
//in view did load method set following
btnpreviouslySelected=nil;
customerButtonFrame=btnCustomer.frame;
inventoryButtonFrame=btnInventory.frame;
templatesButtonFrame=btnTemplates.frame;
-(void) RepositioningFrameMneuTree
{
btnCustomer.frame=customerButtonFrame;
btnInventory.frame=inventoryButtonFrame;
btnTemplates.frame=templatesButtonFrame;
}
-(void) RepositioningMenuTree:(int)iCaseValue
{
if (iCaseValue==1)
{
btnInventory.center=CGPointMake(btnInventory.center.x,btnInventory.center.y+300);
}
if (iCaseValue==2 || iCaseValue==1)
{
btnTemplates.center=CGPointMake(btnTemplates.center.x,btnTemplates.center.y+300);
}
}
-(IBAction) buttonClicked:(UIButton*)btn;
{
if(btnpreviouslySelected==btn)
{
//set to default location
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
//here remove search view
[viwSearchView removeFromSuperview];
[self RepositioningFrameMneuTree];
[UIView commitAnimations];
return;
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
//assign previousbutton to new button
btnpreviouslySelected=btn;
[self RepositioningFrameMneuTree];
viwSearchView.frame=CGRectMake(0,btn.frame.origin.y+45,viwSearchView.frame.size.width,viwSearchView.frame.size.height);
//add search view on your view
[self.buttonsview addSubview:viwSearchView];
//-------------------------------------------
//change the location of button below selected button to show the search button
switch (btn.tag) {
case 1:
[self RepositioningMenuTree:1];
break;
case 2:
[self RepositioningMenuTree:2];
break;
case 3:
//dont do any thing
break;
default:
break;
}
//end animation
[UIView commitAnimations];
}

Cannot change UIView frame size

I have a custom uiview that i am trying to update the frame size. I do it like this in a method once it is clicked. The method is called, and the frame value changes, however on the screen nothing happens!
if (!touched) {
GameBox *box = (GameBox *)[self.view viewWithTag:40];
[box setFrame:CGRectMake(20, 20, 100, 73)];
NSLog(#"%f", box.frame.origin.x);
markButton.enabled = NO;
guessButton.enabled = NO;
[self.view reloadInputViews];
NSLog(#"The action bar should now be hidden");
}
else if (touched) {
guessButton.enabled = YES;
markButton.enabled = YES;
[self.view reloadInputViews];
NSLog(#"The action bar should now be visible");
}
I guess you have hooked self.view to UIView in Interface Builder.
In order to change UIView frame, in Interface Builder go to File Inspector, and uncheck Use Autolayout, then in the code change the frame.
Hope this helps.
You need to set adjust the frame in the viewDidAppear (not viewDidLoad).
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
CGRect frame = self.tableView.frame;
frame.origin.y += 100.0;
frame.size.height -= 100.0;
self.tableView.frame = frame;
}
Apparently this has something to do with table views within navigation controllers.
It is because of Auto Layout, however you could do it after Auto Layout done its work or change constraints of it. If you want to do it after auto layout add following.
- (void)viewDidAppear:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
box.frame = CGRectMake(20, 20, 100, 73)];
});
[self.view reloadInputViews] is generally used for FirstResponders. I Don't have much of an idea about your customview, but I think for just settings the frame you can use:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
viewFrame.frame=frame;//Frame Defined by you
[UIView commitAnimations];
can give better solution if i get a look at your custom view.

UIAnimation - Show UIView from button.frame.origin.y

I have a UIButton somewhere on my view. On touch event of button I making a UIView appear. The UIAnimation I have used make the view appear from top of window. But I want it to appear from button.frame.origin.y . Before touching the button the view is not visible. On touching the button view should start appearing from above position.
Here is the code :
-(IBAction) ShowInfowView:(id)sender{
CGRect rect = viewInfo.frame;
rect.origin.y = rect.size.height - rect.size.height+58.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.70];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
viewInfo.frame = rect;
[UIView commitAnimations];
}
This is how I am hiding the view again :
-(IBAction) HideInfoView:(id)sender{
CGRect rect = viewInfo.frame;
rect.origin.y = -rect.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.70];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
viewInfo.frame = rect;
[UIView commitAnimations];
}
In viewDidLoad I am doing the following :
CGRect rect = viewInfo.frame;
rect.origin.y = -rect.size.height;
viewInfo.frame = rect;
UPDATE:
Please see this example. Here view is appearing from top of screen. I want it to appear from button y axis. For that matter please consider button y position a bit upwards.
So you want a slide-in effect, but not from the top of the screen, just some arbitrary value?
One way to do it:
1) You should create a view that has the dimensions and position of your desired view AFTER animation finishes, we'll call it baseview.
2) Set this baseview property clipsToBounds to YES. This will make all subviews that are outside of the baseview's frame invisible.
3) Add your animating view as a subview of the baseview, but set the frame so it is invisible (by plcacing it above the baseview):
frame = CGRectMake(0, -AnimViewHeight, AnimViewWidth, AnimViewHeight);
4) Animate the animview frame:
//put this inside of an animation block
AnimView.frame = CGRectMake(0, 0, AnimViewWidth, AnimViewHeight);
EDIT:
Example:
//define the tags so we can easily access the views later
#define BASEVIEW_TAG 100
#define INFOVIEW_TAG 101
- (void) showInfo
{
//replace the following lines with preparing your real info view
UIView * infoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[infoView setBackgroundColor: [UIColor yellowColor]];
[infoView setTag: INFOVIEW_TAG];
//this is the frame of the info view AFTER the animation finishes (again, replace with real values)
CGRect targetframe = CGRectMake(100, 100, 100, 100);
//create an invisible baseview
UIView * baseview = [[UIView alloc] initWithFrame:targetframe];
[baseview setBackgroundColor: [UIColor clearColor]];
[baseview setClipsToBounds: YES]; //so it cuts everything outside of its bounds
[baseview setTag: BASEVIEW_TAG];
//add the nfoview to the baseview, and set it above the bounds frame
[baseview addSubview: infoView];
[infoView setFrame:CGRectMake(0, -infoView.bounds.size.height,
infoView.bounds.size.width, infoView.bounds.size.height)];
//add the baseview to the main view
[self.view addSubview: baseview];
//slide the view in
[UIView animateWithDuration: 1.0 animations:^{
[infoView setFrame: baseview.bounds];
}];
//if not using ARC, release the views
[infoview release];
[baseview release];
}
- (void) hideinfo
{
//get the views
UIView * baseView = [self.view viewWithTag: BASEVIEW_TAG];
UIView * infoView = [baseView viewWithTag: INFOVIEW_TAG];
//target frame for infoview - slide up
CGRect out_frame = CGRectMake(0, -infoView.bounds.size.height,
infoView.bounds.size.width, infoView.bounds.size.height);
//animate slide out
[UIView animateWithDuration:1.0
animations:^{
[infoView setFrame: out_frame];
} completion:^(BOOL finished) {
[baseView removeFromSuperview];
}];
}
I have done exactly what you're trying in my recent project.
The following steps should make this work:
1. In your viewDidLoad: you init your viewToFadeIn like this:
viewToFadeIn = [[UIView alloc] initWithFrame:CGRectMake(20,self.view.frame.size.height+10, self.view.frame.size.widh-40, 200)];
//its important to initalize it outside your view
//your customization of this view
[self.view addSubview:viewToFadeIn];
2.your ShowInfowView: Method should look like this:
` -(IBAction) ShowInfowView:(id)sender{
[UIView beginAnimations:#"fadeIn" context:NULL];
[UIView setAnimationDuration:0.25];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
viewToFadeIn.transform = CGAffineTransformMakeTranslation(0, -290);
//290 is in my case, try a little for your correct value
[UIView commitAnimations];
}
3.yourHideInfoView:` Method looks like this
-(IBAction) HideInfoView:(id)sender{
[UIView beginAnimations:#"fadeOut" context:NULL];
[UIView setAnimationDuration:0.25];
[UIView setAnimationDelegate:self];
viewToFadeIn.transform = CGAffineTransformMakeTranslation(0, 0);
[UIView commitAnimations];
}
EDIT:
4. animationFinishedMethod:
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context{
if ([animationID isEqual:#"fadeIn"]) {
//Do stuff
}
if ([animationID isEqual:#"fadeOut"]) {
//Do stuff
}
}
SEE THIS
This should do the trick. Good luck
Your problem is not clear (for me).
What is this?
rect.origin.y = rect.size.height - rect.size.height+58.0;
Is 58 origin of your UIButton?
You should use sender.frame etc
Use blocks to animate like this
[UIView animateWithDuration:0.5f animations:^{
// Animation here
} completion:^(BOOL finished) {
// onComplete
}];
- (void) slideIn{
//This assumes the view and the button are in the same superview, if they're not, you'll need to convert the rects
//I'm calling the animated view: view, and the button: button...easy enough
view.clipToBounds = YES;
CGRect buttonRect = button.frame;
CGRect viewRect = CGRectMake(buttonRect.origin.x, buttonRect.origin.y + buttonRect.size.height, view.bounds.size.width, 0);
CGFloat intendedViewHeight = view.height;
view.frame = viewRect;
viewRect.size.height = intendedViewHeight;
[UIView animateWithDuration:.75 delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
view.frame = viewRect;
}completion:nil];
}
This will cause the the view to appear to slide out from under the button. To slide the view back in, you just reverse the animations. If you wish to slide it up from the button, you'll need to make sure your starting 'y' is the 'y' value of the button (rather than the 'y' + 'height') and animate both the height and y values of the view that needs animating.

How can I present a UIView from the bottom of the screen like a UIActionSheet?

I'd like a UIView to slide up from the bottom of the screen (and stay mid-screen) like a UIActionSheet. How can I accomplish this?
UPDATE:
I am using the following code:
TestView* test = [[TestView alloc] initWithNibName:#"TestView" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
test.view.center = CGPointMake(160,100);
//test.view.frame = CGRectMake(0, 0, 160, 210);
[[[UIApplication sharedApplication] keyWindow] addSubview:test.view];
[UIView commitAnimations];
The view seems to be animating from the corner and appearing in the corner. How can I make it slide up from the bottom? Getting close!
Do what Matt did here, but just change the values and direction. I have code at home to do this from the bottom if you need it later (I'll update this post).
Link: http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html
Also, don't forget to take out the bit of code that shifts the main view downward (so instead the UIView just pops over top like an ActionSheet)
Updated with code:
This is what I use in one of my apps to show/hide a little "options" view:
- (void)toggleOptions:(BOOL)ViewHidden
{
// this method opens/closes the player options view (which sets repeat interval, repeat & delay on/off)
if (ViewHidden == NO)
{
// delay and move view out of superview
CGRect optionsFrame = optionsController.view.frame;
[UIView beginAnimations:nil context:nil];
optionsFrame.origin.y += optionsFrame.size.height;
optionsController.view.frame = optionsFrame;
[UIView commitAnimations];
[optionsController.view
performSelector:#selector(removeFromSuperview)
withObject:nil
afterDelay:0.5];
[optionsController
performSelector:#selector(release)
withObject:nil
afterDelay:0.5];
optionsController = nil;
}
else
{
optionsController = [[PlayOptionsViewController alloc] init];
//
// Position the options at bottom of screen
//
CGRect optionsFrame = optionsController.view.frame;
optionsFrame.origin.x = 0;
optionsFrame.size.width = 320;
optionsFrame.origin.y = 423;
//
// For the animation, move the view up by its own height.
//
optionsFrame.origin.y += optionsFrame.size.height;
optionsController.view.frame = optionsFrame;
[window addSubview:optionsController.view];
[UIView beginAnimations:nil context:nil];
optionsFrame.origin.y -= optionsFrame.size.height;
optionsController.view.frame = optionsFrame;
[UIView commitAnimations];
}
}
One way would be to use the present modal view controller on the view controller:
presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
For more info take a look at the UIViewController documentation.
EDIT: If you want a mid-screen view you'll need to animate it into position as #jtbandes has pointed out. I suggest also adding some candy to UIView animation block:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
myView.center = CGPointMake(x,y);
[UIView commitAnimations];
You can then move it again if you need to go full screen or dismiss it.
You'll have to move the view yourself, by setting its center or frame. I'll let you figure out what to set those to. But for the animation:
// set the view to its initial position here...
[UIView beginAnimations:nil context:NULL];
// move the view into place here...
[UIView commitAnimations];
Check out this post: http://blog.yetanotherjosh.com/post/33685102199/3-ways-to-do-a-vertical-transition-with
I'm going with the modal window approach.
Try this solution.... it works
#pragma mark - Date Selector View PresentModelView with Transparent ViewController
- (void) showModal:(UIView*) modalView {
CGRect rect=modalView.frame;
rect.origin=CGPointMake(0, 0);
self.tutorialView.frame=rect;
UIWindow *mainWindow = [(AppDelegate *)[UIApplication sharedApplication].delegate window];
CGPoint middleCenter;
middleCenter = CGPointMake(modalView.center.x, modalView.center.y);
CGSize offSize = [UIScreen mainScreen].bounds.size;
CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, offSize.height * 1.5);
modalView.center = offScreenCenter;
if ([[mainWindow subviews] containsObject:modalView]) {
[modalView removeFromSuperview];
}
[mainWindow addSubview:modalView];
[mainWindow bringSubviewToFront:modalView];
// Show it with a transition effect
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
// animation duration in seconds
modalView.center = middleCenter;
[UIView commitAnimations];
}
// Use this to slide the semi-modal view back down.
- (void) hideModal:(UIView*) modalView {
CGSize offSize = [UIScreen mainScreen].bounds.size;
CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, offSize.height * 1.5);
[UIView beginAnimations:nil context:(__bridge void *)(modalView)];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(hideModalEnded:finished:context:)];
modalView.center = offScreenCenter;
[UIView commitAnimations];
}
- (void) hideModalEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
UIView *modalView = (__bridge UIView *)context;
[modalView removeFromSuperview];
}

Make textfield appear from above in an animated way

Is it possible to make textfield come from above to down in an animated way when a button is pressed?
Yes. You must chnage the frame of the UITextField inside an animation block. Something like this. Assuming, for example, that the Y origin of the text field before pressing the button is 0.0f (top of its container).
- (void) buttonPressed {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: <desired_animation_duration_in_seconds> ];
CGRect aFrame = _myTextField.frame;
aFrame.origin.y = <desired_y_coord>;
_myTextField.frame = aFrame;
[UIView commitAnimations];
}