在iOS中通过编程方式创建视图(它是如何工作的)?

16

背景:我正在通过CS193P的iTune视频学习,最近卡在了第三个作业上。基本上,该作业要求您以编程方式创建自定义视图以在屏幕上显示形状。顺便说一下,我没有使用任何视图控制器。

直到我最终拖动一个View对象到Interface Builder中并将对象名称更改为我的自定义视图类,我才能让我的视图显示出来。所以我的问题是,当人们说要以编程方式创建视图时,他们是否只是手动创建类,但需要在IB中显示它?我不能帮助感觉自己误解了什么吗?

编辑:让我更明确一些。我的自定义视图已经用0、0、200、150的框架初始化,并重写了drawRect以在其中绘制一个正方形。如果我尝试将其添加到我的控制器中的主窗口中,我的视图甚至不会显示出来:

    UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview:polygonView];

然而,如果在IB中拖动一个视图并将其类更改为我的视图类,则可以正常显示。

编辑:添加了一些代码。这是我的控制器的awakeFromNib方法,视图应该在其中绘制。

    - (void)awakeFromNib {
    shape = [[PolygonShape alloc] initWithNumberOfSides:numberOfSidesLable.text.integerValue minimumNumberOfSides:3 maximumNumberOfSides:12];
    polygonView = [[PolygonView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    polygonView.backgroundColor = [UIColor blackColor];
    [window addSubview:polygonView];
    [self updateInterface];  
}

我的控制器的updateInterface方法的一部分:

- (void)updateInterface {
    [polygonView setPolygon:shape];
    [polygonView setNeedsDisplay];
...
}

PolygonView.h

#import <UIKit/UIKit.h>
#import "PolygonShape.h"

@interface PolygonView : UIView {
    IBOutlet PolygonShape *polygon; 
}

@property (readwrite, assign) PolygonShape *polygon;

- (void)drawRect:(CGRect)rect;
@end

PolygonView.m

#import "PolygonView.h"

@implementation PolygonView
@synthesize polygon;

- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        nslog(@"initialized");
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
       CGRect bounds = [self bounds];

    [[UIColor grayColor] set];
    UIRectFill(bounds);

    CGRect square = CGRectMake(10, 10, 10, 100);
    [[UIColor blackColor] set];
    UIRectFill(square);

    [[UIColor redColor] set];
    UIRectFill(square);
    NSLog(@"drawRect called");
}
@end

虽然polygonView正在初始化,但是drawRect方法并没有被调用。


关键窗口(keyWindow)在哪里被创建的?如果您没有加载nib文件(从您的问题中无法确定是否加载了nib文件),那么您必须先创建窗口,然后再添加子视图。 - jlehr
它正在AppDelegate类中创建。这是否意味着我必须在那里导入我的polygonView类并在那里创建它? - subject_x
有趣的是,如果我将初始化和将视图添加到窗口的操作放在updateInterface方法中,它可以工作,但只有在我点击调用该方法的按钮后才能工作。似乎代码没有在awakeFromNib中被处理。你有什么想法吗? - subject_x
有没有完成这门课程的人可以友善地分享他们控制器的代码吗?这个任务不是为了真正的课堂,我只是想自学 Obj-C。到目前为止,我理解了大部分的内容,但显然还有一些我所不知道的东西。 - subject_x
共识认为我的代码是正确的,尽管似乎没有人能告诉我为什么当从控制器的awakeFromNib方法调用视图时,视图没有被绘制。既然我将要学习有关视图控制器的知识,我将考虑此问题已解决。 - subject_x
8个回答

17

为了更加针对您的问题,语法应该是:

UIWindow* window = [UIApplication sharedApplication].keyWindow;

UIView *polygonView = [[UIView alloc] initWithFrame: CGRectMake ( 0, 0, 200, 150)];
//add code to customize, e.g. polygonView.backgroundColor = [UIColor blackColor];

[window addSubview:polygonView];
[polygonView release];

这是一个您不仅用于此处,而且在随后的子视图中也会使用的模式。另外,需要注意的是在许多模板中,viewController已经设置了自己的视图。当您想要创建自定义视图时,像上面那样创建它,但是不使用上面的方法,而是将viewControllers视图设置为新创建的视图,如下所示:

viewController.view = polygonView;

祝你好运!


那我一定做错了什么。我按照你写的方式来做了,但我的视图没有显示出来。 - subject_x
嗯...如果你注释掉drawRect或者在initWithFrame中特别调用[self drawRect];会发生什么? - SushiGrass Jacob
如果我不重写drawRect方法,什么也不会发生。如果我从initWithFrame方法调用drawRect,则会出现异常错误:“reason:'- [PolygonView drawRect]:向实例0x4b58c70发送未识别的选择器'” - subject_x

4
这是一个老问题,但我不确定他得到了他期望的答案 - 听起来他遇到了我遇到的同样的问题,即我创建了一个UIViewController子类,在界面编辑器nib中放置了一个UIViewController,但是无法弄清如何使两者彼此配合。
如果您单独制作了nib(因此它不是与您的类一起制作的),则必须记住单击您放置在界面构建器中的UIViewController,然后从属性面板单击第三个选项卡按钮(“自定义类”)。 Class将是默认基类UIViewController等 - 只需打开此下拉列表,您将看到所有自定义子类的列表,请选择它,volla - 您已将自定义元素链接到接口。
希望这能节省某人花费几天时间才能找出来的时间,我发现了一些愚蠢而奇妙的方法来解决它,直到我意识到简单的解决方案。

2
您需要有一个视图(或窗口)来添加子视图。正常的语法如下:
UIView *newView = [[UIView alloc] initWithFrame:mainView.bounds];
[mainView addSubview:newView];
[newView release];

当然,如果您有一个从UIView继承的自定义对象,您将使用该对象而不是UIView。当您开始一个新项目时,请创建一个“基于视图的应用程序”,这将为您提供一个带有相关视图的视图控制器(可以使用“CustomViewController.view”访问该视图),该视图将替代上面代码段中的“mainView”。

如果您想在应用程序启动时以编程方式创建视图,请将代码放入视图控制器的“- (void)viewDidLoad”方法中。


我知道一个视图控制器是正确的选择,但在这个特定的任务中只有一个模型类、一个控制器类和一个自定义视图类。你是说我需要将我的视图对象添加到主窗口吗?我应该在哪里以及如何做呢? - subject_x

2

你好,只需要添加这段代码:

[window bringSubviewToFront:polygonView];

right after,
 [window addSubview:polygonView];

0

调用

[super drawRect];

在drawRect:方法的自定义代码之前。


0
在您的活动控制器类中的某个位置,您可以将自定义视图添加到当前顶层视图。
[ myCurrentTopView addSubview: myNewCustomView ];

首先,分配和初始化自定义视图是很有帮助的。

然后,您可以通过执行以下操作在此自定义视图的drawRect中触发一些绘图:

[ myNewCustomView setNeedsDisplay ];

我的当前顶层视图是主窗口。主窗口不是我控制器类中的对象,那么我该如何将我的视图设置为子视图([window addSubView:…]不起作用)。 - subject_x

0
你是否设置了视图的背景颜色以便于区分?
你确定你的视图没有显示出来,还是只是你看不见它?如果你使用自定义视图类,请在视图的drawRect:方法中放置一个NSLog。

是的,我尝试将初始背景颜色设置为黑色,只是为了看看是否会出现白色或灰色视图,但没有。我还在drawRect和iniWithFrame中放置了一个NSLog消息,但也没有显示在控制台中。我认为我的视图没有被初始化,即使我在控制器的awakeFromNib方法中使用polygonView = [polygonView initWithFrame:CGRectMake(0, 10, 320, 480)];。 - subject_x
我收回关于视图没有初始化的说法。它已经初始化了,initWithFrame中的NSLog消息也显示出来了。只是drawRect中的NSLog消息没有显示出来。我可以看到我的模型数据已经正确地传递给了我的视图。我只是不知道为什么窗口不会显示我的视图。 - subject_x
也许再多一点代码能帮助我们分析情况。 - fzwo

0
我最近也遇到了非常相似的问题,下面是解决方法: 在 Xcode 4.3.2 中,如果你从一个“空应用程序”开始,你必须使用 setRootViewController 方法将你的视图设置为主窗口的根视图,而不是使用 addSubview。因此:
// Initialize myView and then
[window setRootViewController:myView];
// instead of [window addSubview:myView];
// the rest as normal...
[window makeKeyAndVisible];

之后,您可以使用addSubview方法添加其他视图。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接