【问题标题】:Programatically changing multiple UIViews in masterDetail App以编程方式更改主详细信息应用程序中的多个视图
【发布时间】:2013-07-07 19:56:26
【问题描述】:

为了正确传达作者的意图,已重新编写此问题

我有一个 MasterDetail 应用程序,它最终将成为一种通过固定数量的“挑战”(准确地说是 60 个)跟踪“玩家”数量的方法。每个玩家的挑战都是相同的,而每个玩家在个人挑战中的状态可能会有所不同。所有关于玩家的数据都存储在 Postgres 数据库中,然后使用 LeftViewController 中的 JSONModel 获取。我从数据库中正确获取了所有数据,并且已成功将其放入 NSMutableDictionary。 Dictionary 中的数据如下所示(这是一位玩家):

    player =     (
            {
        id = 9;
        name = "Arthur Dent";
        currentChallenge = "Cooking";
        timeStarted = "04 Jul 2013 1:08 PM";
        challengesDone = (
                            {
                challengeName = "Flying";
                timeCompleted = "04 Jul 2013 12:08 PM";
            }
        );
        nextChallenge = "Swimming";
        freePass =             (
            Running,
            "Climbing"
        );
    },

正如你所看到的,玩家有一些挑战“完成”(“done”),一些他不需要做(“pass”),一个他正在做(“currentChallenge”)和一个他接下来要做的挑战(“nextChallenge”)。对于玩家可能处于的这些状态中的每一个,我希望 RightViewController 中的“挑战”进行颜色编码,以便您一眼就能了解正在发生的事情。我需要“挑战”来根据玩家的状态点亮不同的颜色,这取决于我的 NSMutableDictionary 中的数据。

通过从 NSDictionary 中的数据创建数组,我可以通过这样做来改变颜色:

if ([freePassArray containsObject:@"challenge three name"])
{
    UIImage *image = [UIImage imageNamed:@"status_pass.png"]; //status_pass.png is my color
    [challengeThreeImageView setImage:image];
}

但如果我这样做,我将不得不编写 240 个 if 和 else if 语句来涵盖所有 60 个挑战的所有可能状态。

我的数组只包含所选玩家的数据,因为我像这样传递数据:

*LeftViewController.m * didSelectRowAtIndexPath

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

    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    //Re-fetch the feed from the Postgres Database when a user selects an entry

    [JSONHTTPClient getJSONFromURLWithString:@"http://myurl" completion:^(NSDictionary *json, JSONModelError *err) {
    NSError* error = nil;
    _feed = [[PostgresFeed alloc] initWithDictionary:json error:&error];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"myNotification" object:nil userInfo:[[json objectForKey:@"preclear"] objectAtIndex:indexPath.row]];

}];

Player *selectedPlayer = [_players objectAtIndex:indexPath.row];

if (_delegate) 
    {
    [_delegate selectedPlayer:selectedPlayer];
    }
}

因此图像不会同时为所有玩家设置,但在选择另一个玩家后它们也不会清除。

如何在不编写 240 if 和 else if 语句的情况下改变颜色?当我选择另一个播放器时如何清除颜色?

【问题讨论】:

  • 澄清一下,您有一个玩家列表,在详细视图中您有所有 50 个挑战。对于每个用户选择,您想查看 50 个挑战中的哪些已完成,免费、当前和通过。对吗?
  • @Vame 是的,我想我可以这样说。你是对的。
  • 我很困惑——这与 JSON 有什么关系?您有想要用来控制某些视图组件状态的值。值的来源无关紧要。
  • @HotLicks 你是对的,JSON 标签已被删除。对此感到抱歉。
  • 通常大约 80% 的解决问题是知道问题是什么。

标签: ios objective-c ipad uiimageview


【解决方案1】:

假设您拥有所有 50 张图片,并且您知道哪个挑战对应于哪个图像,我会将 status 图像放在实际挑战图像之上:

- (void)setChallengesDone:(NSArray*)doneAr next:(NSArray*)nextAr current:(NSArray*)currentAr andPass:(NSArray*)passAr
{
    // remove additions from the previous selected player
    UIView *prevAdditionsView = [self.view viewWithTag:122333];
    while (prevAdditionsView != nil)
    {
        [prevAdditionsView removeFromSuperview];
        prevAdditionsView = [self.view viewWithTag:122333];
    }

    for (int i=0; i<[doneAr count]; i++)
    {
        [self addChallengeImageAdditionWithImage:@"status_done" forChallenge:[doneAr objectAtIndex:i]];
    }

    for (int i=0; i<[nextAr count]; i++)
    {
        [self addChallengeImageAdditionWithImage:@"status_next" forChallenge:[nextAr objectAtIndex:i]];
    }

    for (int i=0; i<[currentAr count]; i++)
    {
        [self addChallengeImageAdditionWithImage:@"status_current" forChallenge:[currentAr objectAtIndex:i]];
    }

    for (int i=0; i<[passAr count]; i++)
    {
        [self addChallengeImageAdditionWithImage:@"status_free" forChallenge:[passAr objectAtIndex:i]];
    }
}

- (void)addChallengeImageAdditionWithImage:(NSString*)image forChallenge:(NSString*)challengeTitle
{
    UIImageView *challengeImage = [challenges objectForKey:challengeTitle];

    CGRect frame = challengeImage.frame;
    UIImageView *statusImg = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:image]] autorelease];
    [statusImg setFrame:frame];
    [statusImg setAlpha:0.5]; // optionally add some transparency
    [statusImg setTag:122333];
    [self.view addSubview:statusImg];
    [self.view bringSubviewToFront:challengeImage]; // bring challenge image to front
}

将挑战标题与 UIImageViews 映射的最简单方法是维护一个 NSDictionary,其中挑战标题作为键,并将对它们对应的 UIImageViews 的引用作为值。

【讨论】:

  • 正在努力解决这个问题,抱歉。我想我也应该说,目前我的挑战(挑战名称)实际上是 png 图像,上面带有框架的挑战标题,其余部分是透明的,然后“statusImageView”在其后面,这将显示我的颜色.你能安排一下我将如何制作你提到的字典吗?我猜 for 循环看起来像 for ([notification.userinfo objectForKey:@"done"]),因为我所有的数据都在 NSNotificationCenter 中?
  • NSMutableDictionary *挑战;在您的班级中,然后在视图初始化中: [challenge setObject:@"Water Fight" forKey:waterFightImageView];将 statusImageView 放在后面检查我编辑的答案。
  • 好的,我想我明白你的意思了。但是我无论如何都看不到上面的代码对从数据库接收到的数据采取行动。我在问题中包含了我的 DetailVC.m,这样您就可以看到数据是如何进入的。考虑到这一点,我将如何实现上面的代码?我没有针对玩家或挑战的课程,因此创建字典变得很有趣。如果这变得乏味,请原谅我,我仍在掌握这种语言。
  • 我改了问题。希望它现在更有意义。
  • 你点击左边的播放器,你得到上面显示的 JSON,你解析它,你有 4 个字符串数组(挑战名称为 current、next、done 和 free)。你在我写给你的函数中传递这些数组,瞧。这需要您在 detailViewController 的初始创建中创建具有挑战标题/挑战 UIImageView 映射的字典。就是这样
【解决方案2】:

这是模型/视图概念的一个很好的例子。

  • 每个挑战都是一个模型,其中包含所需的所有信息(挑战名称、状态、时间戳等)。
  • 您的 50 个视图中的每一个都是“挑战视图”,它知道如何呈现任何挑战。
  • 状态数据在模型中;状态 图像 在视图中。

例子:

-(void) drawChallenge: (Challenge*) challenge
{
    // Draw challenge name as text
    switch ([challenge status])
    {
        case done: // draw "done" image
        case next: // draw "next" image
    }
}

这个想法是挑战本身不应该知道它是如何呈现的,并且视图不应该知道挑战包含什么。视图负责绘制它。

这可以打包到 UIView 的 ChallengeView 子类中。然后,创建 50 个左右的 ChallengeView,并调用 [currentView drawChallenge: currentChallenge]。

本质上,当添加新挑战时,您会为其创建一个视图,并为该视图提供指向挑战的指针。当 iOS 呈现挑战视图时,它将绘制“它的”挑战,正如您在 drawChallenge 方法中描述的那样。

如果您需要模型-视图-控制器模式的入门知识,Apple 文档的this section 非常好。在这种情况下,您可以忽略 Controller 角色。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-16
    • 2015-01-15
    • 1970-01-01
    • 2010-12-06
    相关资源
    最近更新 更多