原文:http://www.raywenderlich.com/18319/how-to-make-a-simple-mac-app-on-os-x-10-7-tutorial-part-23
原创译文,欢迎转载,分享 .请注明出处:http://blog.youkuaiyun.com/yuan_will/article/details/46912665
本教程由iOS Tutorial Team成员Ernesto García发布,他是一位Mac和iOS开发者,CocoaWithChurros.的创始人。
本教程是"如何创建一个简单的Mac应用程序"系列中的第二部分。
在本系列的第一部分
(http://www.raywenderlich.com/17811/how-to-make-a-simple-mac-app-on-os-x-10-7-tutorial-part-13)
中,您创建了一个Mac的应用程序,它能显示出"可怕的虫子"列表。
在第二篇文章中,您将学习如何添加详细信息部分,显示有关虫子的完整信息:它的名字,恐怖评级,以及较大的虫子(更可怕!)的画面。 (跳转到第三部分(http://www.raywenderlich.com/18413/how-to-make-a-simple-mac-app-on-os-x-10-7-tutorial-part-33))
你还将学会如何改变虫子的信息,包括恐怖的级别,甚至是改变它们的图片!
那我们现在开始吧!
先来下载一些需要的东西:
为了完成本教程,你会需要一些图片和一些代码文件。所以下载这些额外的项目资源并解压。(http://cdn3.raywenderlich.com/downloads/MacApp2ExtraStuff.zip)
//-----------------------------------------------------------------------------------------------------------------------
注:为了完成从"不可怕"到"非常吓人"的评级,你将会使用一个叫做"EDStarRating"的开源代码,它已经包含在刚才下载的包中.
在本教程中,我们不会解释他是如何工作的,但是我们将教会如何在您的项目中使用自定义视图. 在这个包里面还包含了NSImage类目,你可以用它利用大图生成缩略图,用来做评级.
有关EDStarRating的更多信息,你可以检查去这里找(https://github.com/erndev/EDStarRating)。
//-------------------------------------------------------------------------------------------------------------------------
现在,添加这些文件在你的项目中(和之前在第一部分的一样,我们要新建文件夹来装这些文件)
- 在Xcode里面新建"View"文件夹,将 EDStarRating.h/EDStarRating.m 拖到里面,确保“Copy items into destination group’s folder (if needed)”这个选项是选中的,还有“Add to Targets”这里面的“ScaryBugsMac”选项是选中的.这两部非常重要.
- 重复刚才的动作,将NSImage+Extras.h/NSImage+Extras.m 拖拽到新的组名为“Helpers”的文件夹里面,这是一些待会儿可以帮助我们调整图像的代码,再次,确保我们勾选了(Copy Items check,还有 Add To Targets check).这两个选项.
- 还是重复刚才的动作,将那三张图片添加到“Art”文件夹中,这些图片我们将用来评级,~_~ (同样,不要忘了检查那两个选项,重要的事情说三遍...)
This is how your Project should look like after adding those files:
当添加完所有的文件后,你的界面应该是这个样子的:
创建细节部分:
恩,现在是时候往 "恐怖虫子详细信息界面" 里面添加一些控件了.
在iOS里,一个典型 主/从 型的应用程序,做法是创建两个view,然后当列表中的某一行被点击,界面改变到不同的view.去显示需要的信息.
而在OSX开发中,该模式是不同的。没有iPhone屏幕大小的限制,因此可以在同一视图里面添加详细信息。你只需要调整它的大小就好了。这种方法类似于iPad的主/从应用程序的模式。
OK,动起来吧,, 打开MasterViewController.xib.选择界面,然后增加他的长款,你并不需要担心它的大小,拉大到可以适应新的控件就好,
就像这样:
下一步就是添加需要的控件,我们要显示的信息有:虫子的名字,恐怖等级,还有图片.
显示虫子名称,需要用到 NSTextField,它可以显示还可以编辑,,评级的话,你需要用到EDStarRating.显示图片呢,NSImageView就可以了.
然后呢,你需要添加两个有名字的label,让用户知道这几个控件是干嘛的就可以了,
要做到这些,只需要保持列表和之前一样,然后在屏幕右下角的控制面板中找到相应的控件拖到视图中即可.
拖一个Text Field (写名字) 两个Lables(标题) 一个图片控制器 (名叫:"Image well") 都在控制面板中.
这个EDStarRating师哥自定义控制器,所以它不在控件板中,.要使用它的花,你需要在控制面板中找到一个叫"Custom View"的东西, 拖到主界面中,然后你就可以配置它以便显示评级.
现在,咱们来排列这些控件,将他们放置在右边空白的地方,垂直,从上到下,就像这样:
- 第一个label 用来显示名字的标题, 下面方式Text Field
- 再下面,放第二个label(评级控件的标题)
- 这个label下面,放的是自定义view (这个将成为我们的评级控件)
- 最后呢,在自定义界面下面放上imageView;
尽量让它们左对齐,完成以后,你的界面看起来应该是这个样子:
最后一步是,我们将这些控件设置成auto-resize 以便适应父视图,这样做,我们就可以看到,这些控件会跟着主界面调整大小.
要做到这一点,选择主视图(通过点击它或在“自定义视图”中的对象面板的左边)。现在,在左边的公用事业板上,选择“Size Inspector”标签。
这是第五个标签,一个带有标尺图标。目前,设置autosizing属性如下:
-
让我们来配置 EDStarRating 控件。在前一步,你增加了自定义视图。这是一个基本的NSView。现在,你需要告诉Interface Builder,你想要的视图类是EDStarRating而不是NSView。
-
该怎么做呢?相当容易。点击自定义视图来选择它。在公用程序面板中,通过单击“第三”选项卡,切换到标识。
在该选项卡,更改类名以EDStarRating。
-
-
注意,您还可以通过双击它来更改标签的文本,并直接更改标签上的文本。 -
重复这一步,将第二个标签其标题改变为“Rating”
好吧,现在是运行应用程序的时候了。如果一切顺利,应用程序应该可以运行,你应该看到类似的窗口:
-
-
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
-
提示: 如果 有一部分控件没有显示全,你可以打开 MainMenu.xib 然后调整窗口的尺寸
-
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
-
.
你现在可以看到所有的控件,但是等级控制器不见了。不要担心。它一直在那里,但因为还没有配置,所以它没有显示任何东西.
目前所有的控件,可以显示我们需要的详细信息。现在,您需要添加视图控制器的出口(outlets),这样稍后就可以编写代码控制它们了。
来做到这一点,打开MasterViewController.xib,来到助理编辑(第二个按钮在顶部的工具栏中的“Editor”部分),并确保它的设置Automatic\MasterViewController.m. -
请选择“table View”(请记住,您可能需要单击两次或只是选择左侧的控制面板中的tableView选项)。当你确定选中了table View而不是scrollview选项后,将tableview拖线到MasterViewController.m 中的 @interface MasterViewController ()下面.
-
-
这时会出现一个弹出一个NSTableView的属性的框 填写名字为bugstableview,确保存储设置为weak 并单击“Connect”。
-
-
现在,你需要重复这些步骤为 图片,自定义视图,还有NSTextField 拖线(但不为标签拖线。我们不会改变任何label里的东西)。
你仅需要做相同的事情,选择text field 然后拖线到MasterViewController.m 改名为bugTitleView
重复,相同的事情,将image View拖线,改名为bugImageView..还有最后一个,那个评级视图,添加名字为:bugRating -
After creating those properties, your MasterViewController.m file should look like this:
-
添加完这些属性之后,你的MasterViewController.m 里面应该是这样的:
-
@interface MasterViewController () @property (weak) IBOutlet NSTableView *bugsTableView; @property (weak) IBOutlet NSTextField *bugTitleView; @property (weak) IBOutlet NSImageView *bugImageView; @property (weak) IBOutlet EDStarRating *bugRating; @end
这时你应该会看到一个警告"it can’t find the definition of EDStarRating " 因为你还没有import头文件,将这句放到最上面#import "EDStarRating.h"
-
展示细节:
-
现在是时候在这些新添加的控件中显示一些信息了。当用户单击我们的表格视图的任何一行时,您需要获得所选的虫子信息,并将这些信息显示在详细信息组中,也就是右边的这些控件中。
-
这包括三个步骤。首先,你需要知道哪一行是被选中的。table view是通过其代理方法‘tableViewSelectionDidChange’这个知道的。因此,您需要在我们的视图控制器中实现该方法以接收该通知。
-
之后,你需要从我们的虫子数组中取出选中的那组数据。第三步是在细节部分显示该虫子的信息。
-
到时候要添加代码了,选择MasterViewController.m 然后添加下面的代码,在numberOfRowsInTableView 这个方法下面:
-
-(ScaryBugDoc*)selectedBugDoc { NSInteger selectedRow = [self.bugsTableView selectedRow]; if( selectedRow >=0 && self.bugs.count > selectedRow ) { ScaryBugDoc *selectedBug = [self.bugs objectAtIndex:selectedRow]; return selectedBug; } return nil; } -(void)setDetailInfo:(ScaryBugDoc*)doc { NSString *title = @""; NSImage *image = nil; float rating=0.0; if( doc != nil ) { title = doc.data.title; image = doc.fullImage; rating = doc.data.rating; } [self.bugTitleView setStringValue:title]; [self.bugImageView setImage:image]; [self.bugRating setRating:rating]; } - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { ScaryBugDoc *selectedDoc = [self selectedBugDoc]; // Update info [self setDetailInfo:selectedDoc]; }
让我们更详细地看一下这个方法吧:- (void)tableViewSelectionDidChange:(NSNotification *)aNotification { ScaryBugDoc *selectedDoc = [self selectedBugDoc]; // Update info [self setDetailInfo:selectedDoc]; }
为了显示详细视图,您需要执行2个动作:首先,获取选定的虫子的信息。然后,你需要在细节部分显示这些信息。为了看起来更有条理,这里分成了两个方法:
让我们看看
selectedBugDoc中的代码吧:
-(ScaryBugDoc*)selectedBugDoc { NSInteger selectedRow = [self.bugsTableView selectedRow]; if( selectedRow >=0 && self.bugs.count > selectedRow ) { ScaryBugDoc *selectedBug = [self.bugs objectAtIndex:selectedRow]; return selectedBug; } return nil; }
你要做的第一件事是得到TableView的属性中“selectedrow”。有了这个,你就得到了选定的行的索引。
经过仔细检查,你只要得到scarybugdoc在虫子数组的位置,然后调用objectatindex:。得到函数返回相应的scarybugdoc。
setDetailInfo中的代码:-(void)setDetailInfo:(ScaryBugDoc*)doc { NSString *title = @""; NSImage *image = nil; float rating=0.0; if( doc != nil ) { title = doc.data.title; image = doc.fullImage; rating = doc.data.rating; } [self.bugTitleView setStringValue:title]; [self.bugImageView setImage:image]; [self.bugRating setRating:rating]; }
这个方法很简单。它只是从scarybugdoc里面获取图像,名字和评级,然后设置相应的控件。
为了改变这种虫子的标题,你调用bugtitleview的setstringvalue方法。为了改变图片,调用bugimageview控件的setImage:方法
这个就是用一些简单的代码来显示选定的虫子的细节信息。
然后改变评级,调用bugRating中的setrating:方法。
在第一次运行在屏幕上之前,你需要做的最后一步是配置Rating控件。如果你熟悉iOS,你就会知道视图控制器的生命周期。视图控制器中的viewwillload / viewDidLoad 方法经常用来配置子视图。
在OSX,NSViewController是不实现这些方法的。当视图控制器创建视图时,需要重写loadView方法。
所以您将重写此方法并添加您可能需要的任何初始配置。注意要在本方法开始时调用[ super loadView],否则视图将不被创建!
将下面的代码添加在-(scarybugdoc *)selectedbugdoc下面。-(void)loadView { [super loadView]; self.bugRating.starImage = [NSImage imageNamed:@"star.png"]; self.bugRating.starHighlightedImage = [NSImage imageNamed:@"shockedface2_full.png"]; self.bugRating.starImage = [NSImage imageNamed:@"shockedface2_empty.png"]; self.bugRating.maxRating = 5.0; self.bugRating.delegate = (id<EDStarRatingProtocol>) self; self.bugRating.horizontalMargin = 12; self.bugRating.editable=YES; self.bugRating.displayMode=EDStarRatingDisplayFull; self.bugRating.rating= 0.0; }
此外,如果你点击任何一行,选择的虫子信息和图像将出现在细节部分!
真棒,现在它开始看起来像一个真正的应用程序!"'__'"
然而,有一个小问题。这图片太小了,所以不够吓人!这是因为图像视图没有被设置为默认的缩放图像。
让我们来解决这个。选择masterviewcontroller.xib。现在选择图像视图,并在公用程序面板中使用属性检查程序(第四个标签)。在该选项卡中,将“Scaling”属性更改为“Proportionally Up and Down”。
再次编译和运行该应用程序。
现在的虫子图片可以缩放了,看起来更好–更可怕!哦,除了那个lady bug。
在这一点上,您可以选择一个错误的列表,并看到它的细节。您还可以更改文本和在细节部分的等级。但当你做出改变,虫子模型和列表都没有变化!
但是,如果我们希望能够添加新的虫子或删除现有的虫子呢? 好的,在下一节中,你将添加这些编辑功能到应用程序中! -
添加和删除虫子:
现在是实现编辑功能的时候了。首先,您将学习如何在列表中添加新的行和删除选定的错误。
首先你需要添加2个按钮。一个添加新的一行,另一个删除选定行。
在“控制面板”中找到“Gradient Button”按钮,将这些按钮拖到表格视图的下方。
选择一个按钮,并打开属性检查程序(实用程序面板中的第四个标签)。这将是“添加行”按钮。对于这些按钮,我们不打算设置一个标题。我们将会使用系统图片。
在属性检查中,查找Title属性,并删除所有文本。它应该是空的,所以我们的按钮没有显示任何文本。现在,在Image属性中,选择“+”标志的图像。
之后,重复相同的过程操作另一个按钮。删除它的标题,并设置图像属性”NSRemoveTemplate”,这是一个“-”符号图像。
切换按钮来使用图像,你可能要调整它们的大小,因为它们有点小。
现在你有2个按钮,但他们不能做任何事情,因为你没有连接到视图控制器。
你需要为每个按钮创建一个动作。这是你当你创建的控件的属性相同的方式差不多,就像在iOS开发中一样。
再次,调出助理编辑(“编辑”部分在顶部的工具栏二按钮),并确保它的设置在Automatic\MasterViewController.m
选择“添加”按钮,从按钮到 MasterViewController.m控制器拖线.拖在@end.之前
这是会出现一个弹出框让你对那个按钮创建一个新的动作。名字的作用addBug,单击Connect。
之后,会有一个新的方法"addbug:"在我们创建的视图里面。每次单击“添加虫子”按钮时,系统都会调用该方法。
"删除按钮"重复这个过程,方法名叫做"deletebug"。
是要在这些方法中添加代码来实现添加和删除虫子的时候了。让我们开始用代码来添加一个新的虫子。在addbug方法添加以下代码:
// 1. Create a new ScaryBugDoc object with a default name ScaryBugDoc *newDoc = [[ScaryBugDoc alloc] initWithTitle:@"New Bug" rating:0.0 thumbImage:nil fullImage:nil]; // 2. Add the new bug object to our model (insert into the array) [self.bugs addObject:newDoc]; NSInteger newRowIndex = self.bugs.count-1; // 3. Insert new row in the table view [self.bugsTableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:newRowIndex] withAnimation:NSTableViewAnimationEffectGap]; // 4. Select the new bug and scroll to make sure it's visible [self.bugsTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:newRowIndex] byExtendingSelection:NO]; [self.bugsTableView scrollRowToVisible:newRowIndex];
让我们看看到此,我们做了些什么。
第一,你创建一个新的scarybugdoc对象。之后,您将它添加到您的虫子数组。
最后一步是在tableview中插入一个新的行。之后,系统会自动调用的方法viewfortablecolumn:行和单元格将虫子信息更新。
最后2行只是选中新创建的行,然后将表视图滚动到该行,以使新创建的行是可见的。
现在,删除按钮,粘贴以下代码内的deleteBug方法:
// 1. Get selected doc ScaryBugDoc *selectedDoc = [self selectedBugDoc]; if (selectedDoc ) { // 2. Remove the bug from the model [self.bugs removeObject:selectedDoc]; // 3. Remove the selected row from the table view. [self.bugsTableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:self.bugsTableView.selectedRow] withAnimation:NSTableViewAnimationSlideRight]; // Clear detail info [self setDetailInfo:nil]; }
如果你能找到一个选择的虫子(也许是没有选择),你将通过调用array的方法:removeobject从数组中移除bug:。
该方法将定位我们的bug doc对象的数组,并将删除该对象。然后,你删除TableView中对应的行。
在最后一行中,你只需更新一个没有值的信息。这实际上会清除所有选定的虫子的信息。
然后就是编译和运行!如果一切顺利,现在当你点击添加虫子按钮,就会增加一个新的行。
您还可以通过选择一个行来删除一个虫子,然后单击“删除”按钮。
- 编辑虫子信息:
现在呢,您已经可以从我们的名单中添加和删除可怕的虫子了。现在是编辑现有的虫子的时候了。
你可以对一个虫子做出三个改变:改变它的名字,改变它的等级,改变它的形象。
首先,让我们看看你如何改变这个名字。当您选择一个虫子时,它的名称是显示在text filed中的。
现在,你可以改变它,但这些变化并没有被存储在模型中,所以这些变化是不可改变的。因此,在用户每次更改选定的虫子名称时,都需要更新该模型。
为了实现这一目的,首先,你需要知道,当前文本是否已改变。每次用户更改某个字符时,我们并不希望收到通知,只有当用户已完成编辑时,再收到通知。
当用户键入和按下回车时,或当他从text field改变到其他控制时,text filed 会发送一个action,同样的,当被点击时,按钮同样会发出一个动作。
因此,实现它的方法是相同的。选择MasterViewController.xib,,把助理编辑(“编辑”部分在顶部的工具栏二按钮),并确保它的设置自动masterviewcontroller。M.
选择text field,并拖动到MasterViewController。在addbug方法上面:
弹出框让你对text filed创建一个新的动作,名字叫做bugTitleDidEndEdit:
当用户完成编辑文本时,该方法将被调用。在该方法中添加下面的代码:
// 1. Get selected bug ScaryBugDoc *selectedDoc = [self selectedBugDoc]; if (selectedDoc ) { // 2. Get the new name from the text field selectedDoc.data.title = [self.bugTitleView stringValue]; // 3. Update the cell NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:[self.bugs indexOfObject:selectedDoc]]; NSIndexSet * columnSet = [NSIndexSet indexSetWithIndex:0]; [self.bugsTableView reloadDataForRowIndexes:indexSet columnIndexes:columnSet]; }
最后一步是在表视图中更改标题。对于这个,你只告诉表视图为当前的虫子重新加载行。这将导致viewForTableColumn被调用,这将刷新视图单元格。
//--------------------------------------------------------------------
提示: 这是更好地更新cell加载方式,而不是试图直接用viewfortablecolumn操作单元格外的内容。
//---------------------------------------------------------------------
编译和运行应用程序。现在,如果您选择一个虫子并编辑它的名称(记住按下回车),该名称将在表视图中更改!
如果您更改了选择,并返回到它,新的文本仍然存在,因为现在我们将它存储在我们的模型对象中。
Now it’s time to change the rating. EDStarRating works in a similar way as the tableview does. You need to define its delegate, and the OS will call a method to inform us that the rating has changed.
We’ve already configured all that in the loadView method in a previous step, so you just need to add the method that will be called.
Select MasterViewController.m and add this code at the bottom of the file, just before the @end:
现在是改变评级的时候了。EDStarRating 以类似TableView的方式运行。您需要定义它的代理,然后系统将调用一个方法来通知我们,该评级改变了。
在上一步我们已经配置了所有在loadView方法,所以你只需要添加,将要调用的方法。
选择MasterViewController.m 并添加下面代码在文件中,在@end前添加:
在这里,做的是同样的事情:你得到选定的文件,并用新的值更新它。-(void)starsSelectionChanged:(EDStarRating*)control rating:(float)rating { ScaryBugDoc *selectedDoc = [self selectedBugDoc]; if( selectedDoc ) { selectedDoc.data.rating = self.bugRating.rating; } }
编译和运行应用程序。现在你可以注意到评级的值是每次改变一个bug的评级后存储在模型的,评级是不变的,即使你稍后再选择其他昆虫。
现在,只有一件事情可以做了,允许用户改变虫子的图像!
要做到这一点,你要添加一个新的按钮。当用户点击它,你会出现一个窗口,让用户选择一个新的图像。
要做到这一点,选择MasterViewController.xib。查找对象库中的“Push Button”控件,并将它拖到我们的视图中,拖在图像视图下面就好。
更改按钮的标题为“更改图片”:
每次点击按钮,都会调用这个动作。下一步是向用户显示窗口来更改虫子的图片。
现在要使用OSX的一个特殊的控件,称为 IKPictureTaker。这允许您从您的计算机上选择一张图片,甚至可以使用网络摄像头来拍一张照片,并且只需要一行代码。你可以在苹果ImageKit编程指南了解更多关于这个控制。
一旦用户选定了图片,控件将通知您的视图控制器,该控制器可以通过委托回调来提供。
选择MasterViewController.m添加这些在文件的顶部:
#import <Quartz/Quartz.h> #import "NSImage+Extras.h"
现在,添加这些代码在changePicture方法中:
ScaryBugDoc *selectedDoc = [self selectedBugDoc]; if( selectedDoc ) { [[IKPictureTaker pictureTaker] beginPictureTakerSheetForWindow:self.view.window withDelegate:self didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:) contextInfo:nil]; }
有了这行代码,我们将显示一个窗口来选择新图像。用同样的方法,也可以拍照片什么的.
而当它完成后,它将调用您的委托方法pictureTakerDidEnd。在这种方法中,你会收集新的图像,并用来设置虫子图像。
添加下面的代码changePicture方法,在deleteBug方法上面:
- (void) pictureTakerDidEnd:(IKPictureTaker *) picker returnCode:(NSInteger) code contextInfo:(void*) contextInfo { NSImage *image = [picker outputImage]; if( image !=nil && (code == NSOKButton) ) { [self.bugImageView setImage:image]; ScaryBugDoc * selectedBugDoc = [self selectedBugDoc]; if( selectedBugDoc ) { selectedBugDoc.fullImage = image; selectedBugDoc.thumbImage = [image imageByScalingAndCroppingForSize:CGSizeMake( 44, 44 )]; NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:[self.bugs indexOfObject:selectedBugDoc]]; NSIndexSet * columnSet = [NSIndexSet indexSetWithIndex:0]; [self.bugsTableView reloadDataForRowIndexes:indexSet columnIndexes:columnSet]; } } }
所以,当被调用时,它意味着这个"picture taker"控件已经完成了它的工作。但用户可能已经取消了操作,你也不会有任何图像可用。
当你点击那个 DONE按钮(NSOKButton),你有一个新的图片。
你应该熟悉现在的代码的其余部分。首先你会得到选中的虫子,然后将单元格中的表格视图中的行选中。这里唯一的区别是在模型和单元格中你要更新图像。
现在,你可以编译应用程序。但它不会编译,因为有两个错误。
为什么是这样?这是因为IKPictureTaker控制使用Quartz框架,而框架是不添加默认的应用程序。让我们添加它。
在项目导航器中,选择Project。之后,选择在出现在Target部分的ScaryBugsMac。
然后,点击“Summary”标签。如果你向下滚动,你会看到一个列表的标题“Linked Frameworks And Libraries(链接框架和库)”。
点击小“+”按钮,该按钮位于下面的列表。
过滤列表中,点击"Quartz.framework"项,然后点击“添加”按钮。
现在可以编译无错误的项目并运行应用程序。
如果你选择一个虫子,然后点击选择按钮,你就可以选择一个图像在你的电脑上,甚至可以用您计算机的相机拍一张照片。这个图像将与选定的虫子关联。
好了,到现在我们的应用程序几乎已经准备好了。你可以看到虫子的细节,添加或删除错误,改变他们的名字,评级,甚至改变他们的图片!!
- 好了,本系列的第二部分就结束了,是不是很有成就感呢?(欢迎评论,有需要的话,第三部分也会翻译出来).