Creights
Creights

Reputation: 917

Xcode make a view appear with a transition on click

I'm sorry if this seems like a basic question but it seems my Googling skills aren't up to the task of finding my answer, and I hope you can help!

Basically, I want my app to have either a button, or a label and onclick it reveals some text underneath itself (in the form of an FAQ, as in this link here: http://aptow.com/faq) and pushes everything down with it. I'm aware of how to click and show an element which was previously hidden, but I'm not sure how to do that slide down effect, at the same time as pushing everything else further down the screen on click, and then re-arranging it near the top of the screen once the user clicks again to re-hide the previously hidden content. The link I've given shows exactly what I'm looking to do.

Any ideas? Thanks in advance.

Upvotes: 3

Views: 2666

Answers (3)

Daniel Vogelnest
Daniel Vogelnest

Reputation: 959

You could do this by animating a view's frame property.

Use a UIView (or a subclass such as UITextView) initialised with a frame height appropriate for its initial content (i.e. the label, or nothing if you use a separate button or label to toggle the visibility).

Then determine the frame height required to display the expanded content you desire, and animate to this new height. The other views below (if any) must also have their position changed by the same amount.

As an example example:

[UIView beginAnimations:@"expand" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[myView setFrame:CGRectMake(myView.frame.origin.x, myView.frame.origin.y, myView.frame.size.width, expandedHeight)]; // set expandedHeight to the height you require
for (UIView *view in myViews) { // myViews is an array containing each view that can be expanded or moved.
    if (view.frame.origin.y > myView.frame.origin.y) // check if view is below the one to be expanded
        [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y + expandedHeight, view.frame.size.width, view.frame.size.height)]; // animate the move
}
[UIView commitAnimations];

There are various other methods for animating the frame of UIView and its subclasses, check Apples UIView Reference.

Upvotes: 1

geminiCoder
geminiCoder

Reputation: 2906

As @hermannKlecker said, you can do this with a block using the method animateWithDuration:animations:

[view animateWithDuration:duration animations:^{ //Block code here
/*set the new positions of the view either move up or down*/
}];

This code should do it.

Upvotes: 1

Steffen Blass
Steffen Blass

Reputation: 276

If you want to do something similar to the FAQ page you posted the link of, you can use a UITableView using dynamic cell heights.

A simple UITableViewController could look like this:

#import "ViewController.h"

@interface ViewController () {
    NSArray *data;
    int selected;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    selected = -1;

    data = [NSArray arrayWithObjects:
                     [NSDictionary dictionaryWithObjectsAndKeys:@"Title 1", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 2", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 3", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 4", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 5", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 6", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],
                      [NSDictionary dictionaryWithObjectsAndKeys:@"Title 7", @"title", @"Lorem ipsum dolor bla blab bla", @"details", nil],nil ];

}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == selected) {
        return 130;
    } else
        return tableView.rowHeight;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [data count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"ci";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    NSDictionary *tmp = [data objectAtIndex:indexPath.row];

    cell.textLabel.text = nil;


    static int TITLE_LABEL_TAG  = 122;
    UILabel *titleLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_LABEL_TAG];
    if (!titleLabel) {
        titleLabel = [[UILabel alloc] initWithFrame:CGRectNull];
        titleLabel.tag = TITLE_LABEL_TAG;
        [cell.contentView addSubview:titleLabel];
        titleLabel.backgroundColor = [UIColor clearColor];
        titleLabel.numberOfLines = 1;
        titleLabel.font = [UIFont boldSystemFontOfSize:16];
        [cell.contentView addSubview:titleLabel];
    }
    titleLabel.frame = (CGRectMake(8, 8, cell.contentView.frame.size.width-16, 20));
    titleLabel.text = [tmp objectForKey:@"title"];

    static int DETAIL_LABEL_TAG  = 123;
    UILabel *detailLabel = (UILabel *)[cell.contentView viewWithTag:DETAIL_LABEL_TAG];
    if (!detailLabel) {
        detailLabel = [[UILabel alloc] initWithFrame:CGRectNull];
        detailLabel.tag = DETAIL_LABEL_TAG;
        [cell.contentView addSubview:detailLabel];
        detailLabel.backgroundColor = [UIColor clearColor];
        detailLabel.numberOfLines = 0;
    }
    if (indexPath.row == selected) {
        detailLabel.frame = (CGRectMake(8, 30, cell.contentView.frame.size.width-16, 100));

        detailLabel.hidden = NO;
        detailLabel.text = [tmp objectForKey:@"details"];
    } else {
        detailLabel.hidden = YES;
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    NSMutableArray *ip2reload = [NSMutableArray array];
    if (selected > -1 && selected != indexPath.row)
        [ip2reload addObject:[NSIndexPath indexPathForRow:selected inSection:0]];
    [ip2reload addObject:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
    selected = indexPath.row;
    [tableView reloadRowsAtIndexPaths:ip2reload withRowAnimation:UITableViewRowAnimationAutomatic];
}


@end

You would surely have to calculate the actual row height of the selected row based on the content (e.g. like explained here: Iphone - when to calculate heightForRowAtIndexPath for a tableview when each cell height is dynamic?).

And you can use scrollToRowAtIndexPath:atScrollPosition:animated to make sure, the selected cell is right on top of your screen.

Upvotes: 1

Related Questions