【问题标题】:Update UIview with new objects使用新对象更新 UIview
【发布时间】:2012-05-14 18:04:50
【问题描述】:

我有一个方法 makeButtons(在此处发布),它删除屏幕中的所有按钮并再次添加它们。这在 viewDidLoad 和 viewDidAppear 中运行良好。我正在从一个告诉我我需要一个新按钮的网络服务访问信息。当我从该方法调用 [self makebuttons] 时,什么都没有发生,直到我使用 NavigationController 来回移动,迫使 viewDidAppear 再次完成工作。我的问题是为什么?我做的完全一样,除非它不是从 viewDidAppear 调用的,而是从 doneGettingInformation 调用的。

- (void) viewDidAppear:(bool) animated {
    [self makebuttons]; // Works great!
}

- (void) doneGettingInformation : (ASIFormDataRequest *) request {
    NSString *response = [request responseString];
    [[self.temp.userInfo objectForKey:@"spillider"] addObject:response];
    [self makebuttons]; // This gets called, but nothing changes in the view itself.
}

- (void) makeButtons {
    NSLog(@"kjort");
    int newAntall = [[self.temp.userInfo objectForKey:@"spillider"] count];
    for (UIButton * button in gameButtons) {
        NSString *tag = [NSString stringWithFormat:@"%i",button.tag];
        [button removeFromSuperview];
        if ([webviews objectForKey:tag]) {
            [[webviews objectForKey:tag] removeFromSuperview];
            [webviews removeObjectForKey:tag];
        }
    }
    [gameButtons removeAllObjects];
    scroller.contentSize = CGSizeMake(320, 480);
    if (newAntall > 3) {
        CGSize scrollContent = self.scroller.contentSize;
        scrollContent.height = scrollContent.height+((newAntall-3)*BUTTON_HEIGTH);
        self.scroller.contentSize = scrollContent;
    }
    int y = 163;
    self.nyttSpillKnapp.frame = CGRectMake(BUTTON_X, y, BUTTON_WIDTH, 65);
    for (int i=0; i<newAntall; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setBackgroundImage:[UIImage imageNamed:@"knapp_midt"] forState:UIControlStateNormal];
        [button setBackgroundImage:[UIImage imageNamed:@"knapp_midt"] forState:UIControlStateHighlighted];
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [button.titleLabel setFont:[UIFont systemFontOfSize:15]];
        button.frame = CGRectMake(BUTTON_X, y, BUTTON_WIDTH, BUTTON_HEIGTH);
        button.enabled = YES;
        UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(deleteButton:)];
        swipe.direction = UISwipeGestureRecognizerDirectionRight;
        [button addGestureRecognizer:swipe];
        button.tag = [[[self.temp.userInfo objectForKey:@"spillider"] objectAtIndex:i] intValue];
        NSString * tittel = [NSString stringWithFormat:@"spill %@",[[self.temp.userInfo objectForKey:@"spillider"] objectAtIndex:i]];
        [button setTitle:tittel forState:UIControlStateNormal];
        UIButton *subButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        subButton.transform = CGAffineTransformMakeRotation(M_PI_2);
        subButton.tag = i;
        CGRect subframe = CGRectMake(230, 5, subButton.frame.size.width, subButton.frame.size.height);
        subButton.frame = subframe;
        CGRect myframe = self.nyttSpillKnapp.frame;
        myframe.origin.y = myframe.origin.y+BUTTON_HEIGTH;
        self.nyttSpillKnapp.frame = myframe;
        [subButton addTarget:self action:@selector(clickGameButton:) forControlEvents:UIControlEventTouchUpInside];
        [button addSubview:subButton];
        [gameButtons addObject:button];
        [self.scroller addSubview:button];
        y += BUTTON_HEIGTH;
    }
}

总而言之,它仅在我来回更改视图控制器导致 viewWillAppear 被调用时才有效。这是为什么呢?

我很抱歉我的混乱方法。

谢谢

【问题讨论】:

  • 你试试这个[view setneeddisplay];
  • 放在哪里?我几乎在所有地方都试过了..
  • 考虑到我正在调用 [self makeButtons] 从它应该加载到的同一视图中,我看不出这有什么帮助......对于 viewWillAppear 被调用,我必须切换到那个观点,不是吗?
  • 我不明白你在说什么?

标签: ios xcode view refresh reload


【解决方案1】:

如果您在初始视图出现过程或布局更改之外更改了视图的内容,则您有责任调用 setNeedsDisplay 并通知运行循环它需要重新绘制。

系统会要求视图在最初或在布局更改期间绘制其内容,这就是为什么它作为首先显示视图的过程的一部分。在初始过程中,将调用 viewWill/DidAppear 委托。

来自UIView class reference

视图绘制周期

视图绘图根据需要进行。首次显示视图时, 或者当它的全部或部分由于布局更改而变得可见时, 系统要求视图绘制其内容。对于包含 使用 UIKit 或 Core Graphics 自定义内容,系统调用 视图的 drawRect: 方法。您对此方法的实现是 负责将视图的内容绘制到当前图形中 上下文,由系统在调用之前自动设置 这种方法。这会创建您的静态视觉表示 视图的内容,然后可以显示在屏幕上。

当您的视图的实际内容发生变化时,它是您的 有责任通知系统您的视图需要 重绘。您可以通过调用视图的 setNeedsDisplay 或 setNeedsDisplayInRect:视图的方法。这些方法让 系统知道它应该在下一次绘图期间更新视图 循环。因为它要等到下一个绘图周期才更新 视图,您可以在多个视图上调用这些方法来更新它们 同一时间。

编辑:

另外,请确保后台线程不会调用完成获取图像。您不能在后台线程上编辑视图。如果是,您可以在 bg 线程上准备所有数据,然后在主线程上调用 makeButtons(performSelectorOnMainThread 或使用块。

GCD, Threads, Program Flow and UI Updating

【讨论】:

  • 我尝试在 void makeButtons 末尾调用 [self setNeedsDisplay]。这是正确的协议吗?如果不是,那是什么?
  • 在 makebuttons 结束时不需要它(因为它被称为加载的一部分)。你可以在 doneGettingInformation 中调用 makeButtons 后调用它。
  • 我在调用 [self makeButtons] 后添加了 [self.view setNeedsDisplay]。正在调用 makeButtons 方法(NSLoged),但视图仍然没有改变......我的一个朋友说了一些关于 [self performSelector] 的事情,这需要应用吗?我必须等到 makebuttons 完成才能告诉视图重绘?非常感谢。
  • performSelector 只是一种动态调用方法(选择器)的方式。您确实需要 setNeedsDisplay 但如果它正在添加按钮,听起来至少还有第二个问题。尝试使用调试器逐步完成它,以确保按预期添加按钮。我必须用完,但我稍后会回来查看代码。
  • 这肯定是问题所在。那么我该怎么办呢..我必须从那个方法运行它。我没有让它与 doneGettingInformation 的 performSelectorOnMainThread 一起工作。你会建议我怎么做?我很确定它是一个后台进程,因为它的 ASIFormDataRequest 的 startAsynchronously(在后台运行)。
猜你喜欢
  • 2020-12-10
  • 2020-08-18
  • 2016-09-13
  • 2019-06-28
  • 2019-12-15
  • 2021-07-08
  • 1970-01-01
  • 2012-01-31
  • 2023-03-22
相关资源
最近更新 更多