【问题标题】:Xcode make a view appear with a transition on clickXcode 使视图在单击时出现过渡
【发布时间】:2012-08-22 08:13:07
【问题描述】:

很抱歉,这似乎是一个基本问题,但我的谷歌搜索技能似乎无法找到我的答案,希望您能提供帮助!

基本上,我希望我的应用程序有一个按钮或一个标签,点击它会在其下方显示一些文本(以常见问题解答的形式,如这里的链接:http://aptow.com/faq)并用它来推送所有内容.我知道如何单击并显示以前隐藏的元素,但我不确定如何实现向下滑动的效果,同时在单击时将其他所有内容推到屏幕下方,然后重新一旦用户再次单击以重新隐藏以前隐藏的内容,将其安排在屏幕顶部附近。我提供的链接正是我想要做的。

有什么想法吗?提前致谢。

【问题讨论】:

  • 这可以通过 UIView 方法 beginAnimations 和 commitAnimations 轻松实现,您在相应地更改帧等之前和之后调用它们。 Holwever 自 iOS4 以来,该框架提供了基于块的动画。不幸的是,我还没有使用基于块的动画的经验。这就是为什么我不将此作为答案发布,而是作为评论发布的原因。但是你当然可以用谷歌搜索动画块或 uianimation 块并找到一些教程和其他资源。
  • 如果您使用 UITableView 对象来显示您的文本项,那么您可以分别使用insertRowsAtIndexPaths:withRowAnimation:beginUpdatesendUpdates and ``deleteRowsAtIndexPaths:withRowAnimation: 方法免费获得动画。 (只是为了提供一个替代解决方案)
  • 你想要一个向下滚动的菜单吗?

标签: objective-c ios xcode cocoa-touch


【解决方案1】:

如果你想做一些类似于你发布链接的常见问题页面,你可以使用 UITableView 使用动态单元格高度。

一个简单的 UITableViewController 可能如下所示:

#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

您肯定需要根据内容计算所选行的实际行高(例如,此处解释为:Iphone - when to calculate heightForRowAtIndexPath for a tableview when each cell height is dynamic?)。

您可以使用 scrollToRowAtIndexPath:atScrollPosition:animated 来确保所选单元格位于屏幕顶部。

【讨论】:

    【解决方案2】:

    正如@hermannKlecker 所说,您可以使用 animateWithDuration:animations 方法对块进行此操作:

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

    这段代码应该可以做到。

    【讨论】:

    • 因此,我必须在代码中声明我的块才能知道它们在屏幕上的位置?或者是否有相当于“moveDownTheScreen”的东西,然后你说明有多少像素?
    • 好吧,你不要移动积木。您移动视图 :) 是的,您将不得不重新定位受他的动画影响的每个视图。但是,智能视图层次结构可能会减少要移动的视图数量。只有当它包含以下所有视图作为子视图时,您才能归结为移动一个视图(...的子视图的子视图)
    • 好的,那么在这种情况下,我需要知道视图在屏幕上的位置吗,或者您能否指出一个类似于“moveDownScreen”的方法,以便我可以说明像素数和那我就完了?
    【解决方案3】:

    您可以通过为视图的 frame 属性设置动画来做到这一点。

    使用UIView(或UITextView等子类)初始化,并使用适合其初始内容(即标签,或者如果您使用单独的按钮或标签来切换可见性,则不使用任何内容)的框架高度进行初始化。

    然后确定显示所需的扩展内容所需的帧高度,并将动画设置到这个新高度。下面的其他视图(如果有的话)的位置也必须改变相同的量。

    举个例子:

    [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];
    

    还有各种其他方法可以为 UIView 及其子类的框架设置动画,请查看 Apples UIView Reference

    【讨论】:

    • 在性能方面,最好创建一个视图层次结构并处理一个视图,而不是拥有一组视图。
    • 您将如何使用单个视图来实现这一点?数组myViews 可以通过[mySuperview subviews] 之类的方式获得。
    • 您不需要访问您的子视图:这就是重点。如果您移动“主”视图,所有子视图都将跟随,而无需为每个子视图指定新框架。
    • 您是否将此“主”视图定义为包含所有可扩展视图的超级视图?如果是这样,移动此视图会导致其所有子视图跟随(如您所说),但并非所有这些视图都应该移动 - 仅扩展子视图下方的那些。
    • 我的意思是说,他想在按钮或标签下方显示的所有视图都应该放在一个您将制作动画的视图下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 2014-03-22
    • 2023-03-19
    相关资源
    最近更新 更多