故事版_git 雨后小故事版 - CSDN
精华内容
参与话题
  • 比如一个页面跳转到几个界面的



    比如一个页面跳转到几个界面的 ,有一个按钮   点击进入其他界面   然后点击cell又进入其他界面 ,这个就要看sender的类型







    展开全文
  • ios 故事

    2013-11-23 00:44:17
    故事版(Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果,我贴上本教程所完成的Storyboard的截图: 现在,你就可以清楚的看到这个应用究竟是干...

    故事版(Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果,我贴上本教程所完成的Storyboard的截图:


    The full storyboard we'll be making in this tutorial.

    现在,你就可以清楚的看到这个应用究竟是干些什么的,也可以清楚的看到其中的各种关系,这就是Storyboard的强大之处了。如果你要制作一个页面很多很复杂的App,Storyboard可以帮助你解决写很多重复的跳转方法的麻烦,节省很多时间,以便你能够完全的专注于核心功能的实现上。

     

    开始

     

    首先启动Xcode,新建一个工程,我们在这里使用Single View App Template,这个模板会提供一个类和一个Storyboard,免去我们自己创建的麻烦。

    Xcode template options

     

     

    创建完成之后,Xcode的界面大概是这样的:

     

    Xcode window after creating project

     

     

    这个新的工程由两个类:AppDelegate和ViewController以及一个Storyboard组成(如果你选择了两个设备会有两个Storyboard),注意这个项目没有xib文件,让我们首先看看Storyboard是什么样的,双击Storyboard打开他:

     

    Storyboard editor

     

     

    Storyboard的样子和工作方式都和Interface Builder(以下简称为IB)像极了,你可以从左下方的控件库中拖动控件到你的View之中并且组织他们的排放顺序,唯一不同的地方就是,Storyboard不止是包含一个视图控件,而是所有的视图控件以及他们之间的关系。

     

     

     

    Storyboard对一个视图的官方术语是一个场景,但是一个场景其实就是一个ViewController,在iPhone中一次只能够展示一个场景,而在iPad中一次可以展示多个场景,比如Mail应用程序。

    通过尝试添加一些控件,你可以感受一下Storyboard的工作方式。

    Dragging controls from Object Library

    这个是数据显示器,显示所有场景及其控件的结构。

    Document outline

     

    在IB中,这个位置显示的是你的NIB文件中的文件,而在Storyboard中这里显示的是ViewController,目前这里只有一个ViewController,我们接下来可能会增加一些。

    这是一个文档管理器的缩小版,叫做dock。

     

    The dock in the Storyboard Editor

     

    Dock展示场景中第一级的控件,每个场景至少有一个ViewController和一个FirstReponder,但是也可以有其他的控件,Dock还用来简单的连接控件,如果你需要向ViewController传递一个关系时,只需要将其按住Ctrl键拖到ViewController上就可以了。

    Note:你大概不会太长使用FirstResponder,因为它只是一个代理控件,代表着当前你所使用的控件。

    现在运行这个应用,他会向我们设计的界面一样。

     

    App with objects

     

     

    如果你以前制作过NIB型的应用的话,你也许回去寻找MainWindow.xib ,这个文件包括所有的ViewController,Appdelegate等等,但是在Storyboard中这个特性已经被废止了。

     

    No more MainWindow.xib

    那么,没有这个文件,应用从那里起始呢?

    让我们打开AppDelegate文件,看看那上面是怎么说的:

    #import <UIKit/UIKit.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    
    @end

    如果要使用Storyboard特性,那么AppDelegate必须继承自UIResponder类, 之前则是继承自NSObject类的,而且必须有一个不是UIOutlet类的Window属性声明才可以。

    如果你再去看AppDelegate的执行文件,里面大概什么都没有,甚至连 application:didFinishLaunchingWithOptions: 也只是返回了一个 YES,而之前,这里则需声明一个ViewController并且将他设置成起始页面,但是现在这些都没有了。

    秘密就在info.plist文件中, 打开Ratings-Info.plist (在 Supporting Files group里) 你就会看到这些:

     

    Setting the main storyboard file base name in Info.plist

     

    在NIB为UI的应用里,info.plist文件中有一个键兼做NSMainNibFile,或者叫做Main nib file base name,他用来指示UIApplication载入MainWindow.xib,并且将他与应用链接起来,而现在这个键值消失了。

    而Storyboard应用则利用 UIMainStoryboardFile,或者 “Main storyboard file base name” 键值来表示当App初始化时的Storyboard名称,当程序运行时,UIApplication会使用MainStoryboard.sotryboard作为第一加载项,并且将他的UIWindow展示在屏幕上,不需要任何编程工作。

    在项目总结面板上,你也可以看到并且编辑这些信息:

     

    Setting Main Storyboard in Target summary

    如果你还想设置nib文件的话,另外有地方去设置的。

    为了完成这个实验性的小程序,我们打开main.m,加入

    #import <UIKit/UIKit.h>
    
    #import "AppDelegate.h"
    
    int main(int argc, char *argv[])
    {
    	@autoreleasepool {
    		return UIApplicationMain(argc, argv, nil,
    			NSStringFromClass([AppDelegate class]));
        }
    }

    之前是UIApplicationMain()的函数现在是空的, 变成了 NSStringFromClass([AppDelegate class]).

    与之前使用MainWindow.xib的一个最大的不同是:现在app delegate已经不是Storyboard的一部分了,这是因为app delegate不再从nib文件中,而侍从Storyboard中加载了,我们必须告诉 UIApplicationMain 我们的app delegate类的名字是什么,否则他将无法找到。

     

    制作一个Tab类型的应用

     

    本教程中的Rating App拥有两个Tab,在Storyboard中,很轻松就能够做出一个Tab视图。

    回到MainStoryboard.storyboard中,直接从左边的Library拖进来一个TabViewController就可以了。

    Adding a new tab bar controller into the Storyboard

     

    新的Tab Bar Controller附带了两个View controller,分别作为Tab的视图使用,UITabBarController被称为包含视图,因为他包含这其他一些View,其他常见的包含视图还有那vi嘎提鸥鸟 Controller和SplitView Controller。

     

    在iOS 5中,你还可以自己写一个自定义的Controller,这在以前是做不到的。

     

    包含关系在Storyboard中用一下这种箭头表示。

     

    Relationship arrow in the Storyboard editor

     

    拉一个Label控件到第一个子试图中,命名为“First Tab”,再在第二个子视图中添加一个Label,命名为“Second Tab”。

    注意:当屏幕的缩放大于100%时,你无法在单个场景中添加控件。

    选中Tab Bar Controller,进入属性检查器,选中“作为起始场景”,如下图:

     

    Is Initial View Controller attribute

     

    现在那个没有头的虚虚的小箭头指向了Tab Bar Controller,说明他是起始场景。

     

    Arrow indicating initial view controller in Storyboard editor

     

    这意味着,当你启动这个应用的时候,UIApplication将会将这个场景作为应用的主屏幕。

    Storyboard一定要有一个场景是起始场景才行。

    现在运行试试吧

     

    App with tab bar

    code专门为创造这种Tab Bar的应用准备了一个模板,我们也可以使用他,但是自己有能力不用模板自己做一个Tab Bar也是不错的事。

     

     

    如果你添加了多于五个子视图到一个TabBarcontroller的话,并不会创造五个Tab,第四个tab会自动变成More标签,不错吧

     

    制作一个表格视图

     

    目前连接到Tab bar Controller的视图都是普通的View Controller,现在,我要用一个TableViewController来代替其中的一个ViewController。

    单击第一个视图并删除,从Library中拖出一个TableViewController。

     

     

    Adding a new table view controller to the Storyboard

     

     

    在选中这个TableViewController的前提下,从Library中拖出一个NavController,将会直接附着在上面。

    Embedding in a navigation controller

     

    当然也可以调换顺序,我完全没意见。

    由于NavController和TabBarController一样也是一个包含控制器视图,所以他也必须包含另一个视图,你可以看到同样的箭头连接者这两个View。

     

    View controller relationships in outline of Storyboard editor

     

    请注意所有嵌套在NavController下的View都会有一个Navigation Bar,你无法移除它,因为他是一个虚拟的Bar。

     

    如果你检视属性检测器,你就会发现所有bar的属性都在一起:

     

    Simulated metrics in Storyboard editor

     

    “Inferred”是Storyboard中的默认设置,他意味着继承的关系,但是你也可以改变他。但是请注意这些设置都是为了让你更好的进行设计和这样设置的,随意修改默认设置会带来不可遇见的后果,施主自重。

     

    现在让我们把这个新的场景连接到Tab Bar Controller中,按住Ctrl拖动,或者右键。

     

     

    Connecting scenes in the storyboard

    当你放手的时候,一个提示框会出现。

    Create relationship segue

    当然是选第一个了,Relationship – viewControllers ,这将自动创建两个场景之间的关系。

     

    Relationship arrow in the Storyboard editor

     

    Rearranging tabs in the Storyboard editor

    直接拖动就可以改变Tab Item的顺序,同时也会改变显示Tab的顺序,放在最左边的Tab会第一个显示。

     

    现在运行试试看吧

    App with table view

     

    在我们在这个应用中加入任何实质性的功能之前,我们先来清理一下Storyboard,你不需要改变TabBarController中的任何内容而只需要改变他的子视图就可以了。

     

    每当你连接一个新的视图到TabBarController中的时候,他就会自动增加一个Tab Item,你可以使用他的子视图来修改该Item的图片和名称。

     

    在NavController中选中Tab Item并且在属性编辑其中将其修改为Player。

     

    Setting the title of a Tab Bar Item

     

    将第二个Tab Item命名为“Gesture”

    我们接下来把自定义的图片加入到这些item中, 源码 中包含一个名为“Image”的文件夹,在那里你可以找到我们用到的资源。

    接下来,将NavController的title改为Player,也可以使用代码··

     

    Changing the title in a Navigation Item

     

    运行看一看,难以置信吧,你到现在也没写一条代码。

    App with the final tabs

    原型表格单元

     

    你也许已经注意到了,自从我们加入了Table View Controller之后,Xcode便会现实下面这样一条警告。

    Xcode warning: Prototype cells must have reuse identifiers

     

    这条警告是:“Unsupported Configuration: Prototype table cells must have reuse identifiers”意思是,原型表格单元必须有一个身份证(意译啦)

    原型单元格是另一个Storyboard的好特性之一。在之前,如果你想要自定义一个Table Cell,那么你就不得不用代码来实现,要么就要单独创建一个Nib文件来表示单元格内容,现在你也可以这样做,不过原型单元格可以帮你把这一过程大大的简化,你现在可以直接在Storyboard设计器中完成这一过程。

     

    Table View现在默认的会带有一个空白的原型单元格,选中他,在属性控制器中将他的Style改为subtitle,这样的话,每一格就会有两行字。

     

    Creating a Prototype cell

     

    Creating a view controller with the table view controller template

    将附件设置为Disclosure Indicator并且将这个原型单元格的Reuse Identifier 设置喂“PlayerCell”,这将会解决Xcode所警告的问题。

    试着运行一个,发现什么都没变,这并不奇怪,因为我们还没有给这个表格设置一个数据来源(DataSource),用以显示。

     

    新建一个文件,使用UIViewContoller模板,命名为 PlayersViewController ,设置喂UITableViewController的子类,不要勾选建立XIB文件。

     

    回到Storyboard编辑器,选择Table View Controller,在身份控制器中,把他的类设置为PlayerViewController,这对于把Storyboard中的场景和你自定义的子类挂钩是十分重要的。要是不这么做,你的子类根本没用。

    Setting the class name in the identity inspector

     

    现在起,当你运行这个应用时,table view controller其实是PlayersViewContoller的一个实例。

    在 PlayersViewController.h 中声明一个MutableArray(可变数组)

     

    #import <UIKit/UIKit.h>
    
    @interface PlayersViewController : UITableViewController
    
    @property (nonatomic, strong) NSMutableArray *players;
    
    @end

    这个数组将会包含我们的应用的主要数据模型。我们现在加一些东西到这个数组之中,新建一个使用Obj-c模板的文件,命名为player,设置喂NSObject的子类,这将会作为数组的数据容器。

     

    编写Player.h如下:

    @interface Player : NSObject
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *game;
    @property (nonatomic, assign) int rating;
    
    @end

    编写Player.m如下:

    #import "Player.h"
    
    @implementation Player
    
    @synthesize name;
    @synthesize game;
    @synthesize rating;
    
    @end

    这里没有什么复杂的,Player类只是一个容器罢了,包含三个内容:选手的名字、项目和他的评级。

    接下来我们在App Delegate中声明数组和一些Player对象,并把他们分配给PlayerViewController的players属性。

    在AppDelegate.m中,分别引入(import)Player和PlayerViewController这两个类,之后新增一个名叫players的可变数组。

     

     
    #import "AppDelegate.h"
    #import "Player.h"
    #import "PlayersViewController.h"
    
    @implementation AppDelegate {
    	NSMutableArray *players;
    }
    
    // Rest of file...

    修改didFinishLaunchingWithOptions方法如下:

     
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    	players = [NSMutableArray arrayWithCapacity:20];
    	Player *player = [[Player alloc] init];
    	player.name = @"Bill Evans";
    	player.game = @"Tic-Tac-Toe";
    	player.rating = 4;
    	[players addObject:player];
    	player = [[Player alloc] init];
    	player.name = @"Oscar Peterson";
    	player.game = @"Spin the Bottle";
    	player.rating = 5;
    	[players addObject:player];
    	player = [[Player alloc] init];
    	player.name = @"Dave Brubeck";
    	player.game = @"Texas Hold’em Poker";
    	player.rating = 2;
    	[players addObject:player];
    	UITabBarController *tabBarController =
         (UITabBarController *)self.window.rootViewController;
    	UINavigationController *navigationController =
         [[tabBarController viewControllers] objectAtIndex:0];
    	PlayersViewController *playersViewController =
         [[navigationController viewControllers] objectAtIndex:0];
    	playersViewController.players = players;
        return YES;
    }

    这将会创造一些Player对象并把他们加到数组中去。之后在加入:

     

     
    UITabBarController *tabBarController = (UITabBarController *)
      self.window.rootViewController;
    UINavigationController *navigationController =
      [[tabBarController viewControllers] objectAtIndex:0];
    PlayersViewController *playersViewController =
      [[navigationController viewControllers] objectAtIndex:0];
    playersViewController.players = players;

    咦,这是什么?目前的情况是:我们希望能够将players数组连接到PlayersViewController的players属性之中以便让这个VC能够用做数据来源。但是app delegate根本不了解PlayerViewController究竟是什么,他将需要在storyboard中寻找它。

     

    这是一个我不是很喜欢storyboard特性,在IB中,你在MainWindow.xib中总是会有一个指向App delegate的选项,在那里你可以在顶级的ViewController中向Appdelegate设置输出口,但是在Storyboard中目前这还不可能,目前只能通过代码来做这样的事情。

    UITabBarController *tabBarController = (UITabBarController *)
      self.window.rootViewController;

    我们知道storyboard的起始场景是Tab Bar Controller,所以我们可以直接到这个场景的第一个子场景来设置数据源。

     

    PlayersViewController 在一个NavController的框架之中,所以我们先看一看UINavigationController类:

    UINavigationController *navigationController = [[tabBarController
      viewControllers] objectAtIndex:0];

    然后询问它的根试图控制器,哪一个是我们要找的PlayersViewController:

    PlayersViewController *playersViewController =
      [[navigationController viewControllers] objectAtIndex:0];

    但是,UIViewController根本就没有一个rootViewController属性,所以我们不能把数组加入进去,他又一个topViewController但是指向最上层的视图,与我们这里的意图没有关系。

     

     

    现在我们有了一个装在了players物体合集的数组,我们继续为PlayersViewController设置数据源。

     

    打开PlayersViewController.m,加入以下数据源方法:

     
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    	return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView
      numberOfRowsInSection:(NSInteger)section
    {
    	return [self.players count];
    }

    真正起作用的代码在cellForRowAtIndexPath方法里,默认的模板是如下这样的:

     
    - (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
    
        UITableViewCell *cell = [tableView
          dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc]
              initWithStyle:UITableViewCellStyleDefault
              reuseIdentifier:CellIdentifier];
        }
    
        // Configure the cell...
        return cell;
    }

    无疑这就是以前设置一个表格视图的方法,不过现在已经革新了,把这些代码修改如下:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    	UITableViewCell *cell = [tableView
          dequeueReusableCellWithIdentifier:@"PlayerCell"];
    	Player *player = [self.players objectAtIndex:indexPath.row];
    	cell.textLabel.text = player.name;
    	cell.detailTextLabel.text = player.game;
        return cell;
    }

    这看上去简单多了,为了新建单元格,你只需使用如下代码:

    UITableViewCell *cell = [tableView
      dequeueReusableCellWithIdentifier:@"PlayerCell"];

    如果没有现存的单元格可以回收,程序会自动创造一个原型单元格的复制品之后返回给你,你只需要提供你之前在Storyboard编辑视图中设置的身份证就可以的,在这里就是“PlayerCell”,如果不设置这个,这个程序就无法工作。

     

    由于这个类对于Player容器目前一无所知,所以我们需要在文件的开头加入一个引入来源

     

    #import "Player.h"

    记得要创建synthesize语句哦亲

    @synthesize players;

    现在运行应用,会看到Table里有着players容器。

    Table view with data

    请注意:我们这里只使用一种单元格原型,如果你需要使用不同类型的单元格的话,只需要在storyboard中另外加入一个单元格原型就可以了,不过不要忘记给他们指派不同的身份证。

     

    设计自定义的原型单元格

     

    对于很多应用来说,使用默认的单元格风格就OK了,但是我偏偏要在每一个单元格的右边加上一个一个图片来表示选手的评级,但是添加图片对于默认类型的单元格来说并不支持,我们需要自定义一个设计。

     

    让我们转回MainStoryboard.storyboard,选中table view中的prototype cell,把它的Style attribute改为Custom,所有默认的标签都会消失。

    首先把单元格变得更高一些,你可以直接拉它,也可以在大小控制器中修改数字,我在这里使用55点的高度。

     

    从 Objects Library中拖出两个标签物体,按照之前的样式安插到单元格里,记得设置label的Highlighted颜色为白色,那样的话当单元格被选中的时候会看起来更好看一些。

     

    之后添加一个Image View对象,将它放置在单元格的右边,设置他的宽度为81点,高度并不重要,在属性检查器中设置模式为置中。

    我把标签设置为210点长以确保他不会和ImageView重合,最后整体的设计会看起来象下面这样:


    Prototype cells with a custom design

    由于这是一个自定义的单元格,所以我们不能够使用UITableView默认的textLabel和detailLabel来设置数据,这些属性也不再指向我们的单元格了,我们使用标签(tags)来指定标签。

     

    将Name标签的tag设置为100,Game的设置喂101,image的设置喂102,在属性检查器里设置哦亲。

     

    之后打开 PlayersViewController.m ,在PlayersViewcontroller中将cellForRowatIndexPath修改为:

     

    - (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    	UITableViewCell *cell = [tableView
          dequeueReusableCellWithIdentifier:@"PlayerCell"];
    	Player *player = [self.players objectAtIndex:indexPath.row];
    	UILabel *nameLabel = (UILabel *)[cell viewWithTag:100];
    	nameLabel.text = player.name;
    	UILabel *gameLabel = (UILabel *)[cell viewWithTag:101];
    	gameLabel.text = player.name;
    	UIImageView * ratingImageView = (UIImageView *)
          [cell viewWithTag:102];
    	ratingImageView.image = [self imageForRating:player.rating];
        return cell;
    }

    这里是用了一个新的方法,叫做ImageRating,在 cellForRowAtIndexPath方法之前加入这个方法:

    - (UIImage *)imageForRating:(int)rating
    {
    	switch (rating)
    	{
    		case 1: return [UIImage imageNamed:@"1StarSmall.png"];
    		case 2: return [UIImage imageNamed:@"2StarsSmall.png"];
    		case 3: return [UIImage imageNamed:@"3StarsSmall.png"];
    		case 4: return [UIImage imageNamed:@"4StarsSmall.png"];
    		case 5: return [UIImage imageNamed:@"5StarsSmall.png"];
    	}
    	return nil;
    }

    这就完成了,运行看看:

    Wrong cell height for custom cells made in Storyboard editor

    这和我们想象的结果并不是很符合,我们修改了原型单元格的属性和高度,但是table view却没有考虑进去,有两种方法可以修复它,我们可以改变table view的行高或者加入 heightForRowAtIndexPath 方法来修改,地一种方法更简单,我们就用他。

     

    注意:在一下两种情况下,你应该使用 heightForRowAtIndexPath 方法:一是,你不能预先知道你的单元格的高度,二是不同的单元格会有不同的高度。

     

    回到MainStoryboard.storyboard,在大小检查器中将高度设置为55:

    Setting the table view row height

    通过这种方式的话,如果之前你是使用拖动而不是键入数值的方式改变高度的属性的话,则table view的数值也会自动改变。

     

    现在运行看看,好多了吧

     

    为原型单元格设置子类

     

    我们的表格视图已经相当像模像样了,但是我并不是很喜欢使用tag来访问label,要是我们能够把这些lable连接到输出口,之后在回应属性中使用他们,该多好,而且不出所料,我们可以这样做。

     

    使用 Objective-C class模板新建一个文件,命名为PlayerCell,继承UITableViewCell。

    修改PlayerCell.h

    @interface PlayerCell : UITableViewCell
    
    @property (nonatomic, strong) IBOutlet UILabel *nameLabel;
    @property (nonatomic, strong) IBOutlet UILabel *gameLabel;
    @property (nonatomic, strong) IBOutlet UIImageView
      *ratingImageView;
    
    @end

    修改PlayerCell.m

    #import "PlayerCell.h"
    
    @implementation PlayerCell
    
    @synthesize nameLabel;
    @synthesize gameLabel;
    @synthesize ratingImageView;
    
    @end

    这个类本身并不其很大的作用,只是为nameLabel、gameLabel和ratingImageView声明了属性。

    回到MainStoryboard.storyboard选中原型单元格,将他的class属性修改为“PlayerCell”,现在当你向table view请求dequeueReusableCellWithIdentifier,他会返回一个PlayerCell实例而不是一个普通的UITableViewCell实例。

    请注意我将这个类和reuse Indetifier的名字命名的一样,只是营卫我喜欢这样哦亲,这两个之间其实没啥关系。

    现在你可以将标签和image view连接到输出口去了,选中或者将他从链接检查器拖动到table view cell。

     

    Connecting the player cell

    I

    请注意:要把这个control连接到table view cell而不是view controller哦亲,别选错了。

     

    现在我们把一切都链接好了,只需要加入数据源的代码就可以了。

     

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    	PlayerCell *cell = (PlayerCell *)[tableView
         dequeueReusableCellWithIdentifier:@"PlayerCell"];
    	Player *player = [self.players objectAtIndex:indexPath.row];
    	cell.nameLabel.text = player.name;
    	cell.gameLabel.text = player.game;
    	cell.ratingImageView.image = [self
          imageForRating:player.rating];
        return cell;
    }

    我们现在将接收到 dequeueReusableCellWithIdentifier 的控件指派到PlayerCell,只需要简单的使用已经链接labels和image view到设置好的属性上就可以了,这会让这个设计看上去更加好控制,更加简明。

    当然,在PlayerCell前要引入资源:

     

    #import "PlayerCell.h"

    试着运行,你会发现其实什么都没有变化,可是我们都知道,内部已经有了变化。

    在这相同的场景下面,我们可是在使用子类呢。

    这里还有一些设计小窍门:第一点:一定要设置标签被选中时的颜色。

    Selecting the proper highlight color

    第二点,确保你加入单元格的字符大小是可以变化的,这样,当单元格大小变化时,他的内容的大小也会跟着变化,比如说:

    在PlayersViewController.m中加入如下方法:

    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
    	if (editingStyle == UITableViewCellEditingStyleDelete)
    	{
    		[self.players removeObjectAtIndex:indexPath.row];
    		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    	}
    }

    这个方法加入好了之后,用手指轻扫一行单元格,会出现一个删除键,试试看

    The delete button overlapping a table view cell's content

     

    Delete按钮出现在右边,遮住了一部分评级图片,怎么解决呢?

    打开MainStoryBoard.storyboard,选中table view cell中的image view,在大小检查器中修改Autosizing属性,是它能够跟随上级view的边缘。

     

    Autosizing attributes for the image view

    为labels设置同样的属性。

    Autosizing attributes for the labels

    加入了这些变动之后,删除按钮如我们意料的出现了:

    Delete button appearing with proper autosizing

    其实,最好的做法是让这些星星在出现delete按钮的时候消失,不过这只是一个练习,不要太较真哦亲

    展开全文
  • 关于故事版

    2019-08-13 06:36:34
    故事板,起源于广告行业。在电影电视中,故事板的作用是来安排剧情中的重要镜头...故事版的几个侧重点:故事板是用特定的脚本连贯的分镜头,来展示一系列的交互动作。故事板用于突出显示某个关键交互动作,从而使整...

    故事板,起源于广告行业。在电影电视中,故事板的作用是来安排剧情中的重要镜头。他们相当于一个可视化的剧本。故事板展示了各个镜头之间的关系,以及他们是如何串联起来,给观众一个完整的体验。

    故事板在交互设计领域的定义:
    用图文结合的形式来描述一个完整任务或是交互动作的可视化剧本。

    故事版的几个侧重点:
    故事板是用特定的脚本连贯的分镜头,来展示一系列的交互动作。
    故事板用于突出显示某个关键交互动作,从而使整个用户体验过程中相对应的某个关键任务得以凸显。
    故事板用于寻找产品的用户群。

    故事板可以根据不同的目标侧重选择不同的表现形式。
    采用何种形式基本取决于你构建的故事情节和屏幕任务或线下任务的相关度。
    如果着重研究线下任务,则故事板中线下场景居多,如关注屏幕任务则会展现界面居多。当然如果完全关注屏幕任务就是我们的线框图和原型了。

    故事板关注的是屏幕任务和线下任务结合的边缘地带。

    故事版是传统交互设计方法的重要补充工具,平时我们的原型设计仅仅局限于屏幕环境的设计,忽略了屏幕之外的使用情境,通过故事板绘制的关键使用场景有利于我们理解屏幕之外的用户目标和动机。其实有经验的设计师会在产品设计初期假想一些应用情境,只不过他们没有画在纸上而已。

    另外,故事板不仅仅是设计师头脑中假想情境的具象化,他还可以使一些模糊的用户需求更加具象更有说服力,在设计沟通的过程中能发挥巨大的作用。

    以iphone为例,iphone的界面非常简洁,按钮都“傻大傻大”的,这种设计遇到的挑战是产品的许多功能不得不在简洁的界面风格中被隐藏或者被直接忽略,这时候设计师如果简单的对产品方说“这是视觉风格的要求你不能加这么多任务进来,”显然是很苍白没有说服力的,如果设计师通过故事板说明任务情境,如:用户在使用iphone时有可能正在吃早餐,正在挤公交,他需要快速准确的知道某个功能如何操作,他们不能理解太复杂的界面任务。在这种背景下,简洁的设计就不仅仅是视觉风格的问题,而是用户需求和使用情境的客观限制。因此,产品方很容易就被你说服了。

    故事板的具体应用过程中可能会受一些手绘能力的限制。大家可以尝试做一下,画的丑一点没关系,只要能表达清楚关键任务场景就可以了。

    转载于:https://www.cnblogs.com/yuexx/archive/2009/06/22/1508224.html

    展开全文
  • Storyboard故事版

    2019-06-27 08:36:25
    Storyboard故事版 ** 开发工具与关键技术:Visual Studio 2015、WPF 作者:黄元进 撰写时间: 2019年6月25日 首先来了解一下故事版: 1、Storyboard(故事板)是动画的基本单元 2、Storyboard用于控制动画的播放...

    **

    Storyboard故事版

    **

    
    开发工具与关键技术:Visual Studio 2015、WPF
    
    作者:黄元进
    
    撰写时间: 2019年6月25日
    
    

    首先来了解一下故事版:

    1、Storyboard(故事板)是动画的基本单元

    2、Storyboard用于控制动画的播放,暂停,停止等操作

    3、需要指定TargetName和TargetProperty属性

    4、动画类型声明过之后,需要使用EventTrigger(事件触发器)触发在这里插入图片描述在这里插入图片描述
    然后用Storyboard(故事板)来做了一个例子,见下用XAML代码实现:

    <Window x:Class="Wpf1.Window5"
    
           
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
           
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
           
    Title="Window5" Height="300" Width="300"
    Name="win" WindowStartupLocation="CenterScreen">
    
       
    <Window.Triggers>
    
           
    <!--BeginStoryboard:要在EventTrigger中触发调用,RoutedEvent是响应的事件-->
    
           
    <EventTrigger RoutedEvent="Window.Loaded"
    SourceName="win">
    
               
    <EventTrigger.Actions>
    
                   
    <BeginStoryboard>
    
                       
    <Storyboard>
    
                            <DoubleAnimation
    From="1" To="100" RepeatBehavior="Forever"
    Duration="0:0:5" Storyboard.TargetName="Line1"
    Storyboard.TargetProperty="1"/>
    
                            <DoubleAnimation
    From="1" To="100" RepeatBehavior="Forever"
    Duration="0:0:5" Storyboard.TargetName="Line2"
    Storyboard.TargetProperty="2"/>
    
                            <DoubleAnimation
    From="1" To="100" RepeatBehavior="Forever"
    Duration="0:0:5" Storyboard.TargetName="Line3"
    Storyboard.TargetProperty="3"/>
    
                       
    </Storyboard>
    
                   
    </BeginStoryboard>
    
               
    </EventTrigger.Actions>
    
           
    </EventTrigger>
    
       
    </Window.Triggers>
    
        <!--画布-->
    
        <Canvas
    Background="AliceBlue" x:Name="c" Margin="0,0,-6.4,-1.6">
    
           
    <Line Name="Line1" X1="0" Y1="0"
    X2="0" Y2="200" Stroke="Black"
    StrokeDashArray="2,1" StrokeThickness="4"
    Canvas.Left="152" Canvas.Top="34"
    RenderTransformOrigin="0.5,0.5" Width="2">
    
               
    <Line.RenderTransform>
    
                    <TransformGroup>
    
                       
    <ScaleTransform ScaleY="1.139"
    ScaleX="0.878"/>
    
                       
    <SkewTransform AngleX="16.321"/>
    
                       
    <RotateTransform Angle="-38.047"/>
    
                       
    <TranslateTransform/>
    
                    </TransformGroup>
    
               
    </Line.RenderTransform>
    
           
    </Line>
    
           
    <Line Name="Line2" X1="0" Y1="0"
    X2="0" Y2="200" Stroke="Black"
    StrokeDashArray="2,1" StrokeThickness="4"
    Canvas.Left="139" Canvas.Top="30"
    RenderTransformOrigin="0.5,0.5" Width="2">
    
               
    <Line.RenderTransform>
    
                   
    <TransformGroup>
    
                       
    <ScaleTransform ScaleY="1.14" ScaleX="0.877"/>
    
                       
    <SkewTransform AngleY="-15.914"/>
    
                       
    <RotateTransform Angle="-133.478"/>
    
                        <TranslateTransform/>
    
                   
    </TransformGroup>
    
               
    </Line.RenderTransform>
    
           
    </Line>
    
           
    <Path Name="Line3" Stroke="White"
    StrokeThickness="5" Canvas.Left="23.3"
    Stretch="Fill" Width="254.2" Height="225.4" Canvas.Top="24.9">
    
               
    <Path.Data>
    
                   
    <EllipseGeometry Center="100,100" RadiusX="50"
    RadiusY="50"/>
    
               
    </Path.Data>
    
           
    </Path>
    
       
    </Canvas>
    
    </Window>
    

    实现效果:
    在这里插入图片描述

    展开全文
  • WPF动画之故事

    2019-07-28 20:33:08
    故事板是BeginAnimation()方法的XAML等价物,通过故事板将动画指定到合适的元素和属性。 故事板是增强的时间线,可用来分组多个动画,而且具有控制动画播放的能力---暂停、停止以及播放位置。 而Storyboard类提供...
  • 继上一篇文章继续讲解 此时故事版为导航栏+选项卡默认样子 无约束 3.添加约束(important) 选中item1 这是一个普通的vc 拖一个按钮button上去 此时button是被选中状态,哪个控件是被选中状态就为哪个控件...
  • 今天你敏捷了没有?“敏捷”在互联网和软件开发领域从涓涓细流逐渐演变为行业潮流,往小了说是改进了开发方法,往大了说是革了瀑布流式的命——把产品开发引向了快速迭代、小步快跑的路线上。...
  • 敏捷开发中如何写好用户故事

    万次阅读 2018-08-21 14:04:04
    什么是用户故事? 用户故事(user story)是一个用来确认用户和用户需求的简短描述,作为什么用户,希望如何,这样做的目的或者价值何在。用户故事在软件研发中又被描述为需求。用户故事通常的格式为:作为一个&...
  • 之一:需求与故事结构之二:编辑故事,产品管理,组织结构之三:迭代,计划会,分配任务之四:故事板,燃尽图,我的工作项之五:常见问题问答之六:我的空间,我的通知之七:自定义字段 本人除了做培训、写博客、编...
  • Toon Boom Storyboard Pro是艺术家创建数码故事板的不二之选。Storyboard Pro的开发使经验丰富的故事板艺术家能很大程度上加速创作过程和修改过程,当使用先进的绘图工具时,能够提供艺术自由性。无论是进行个人项目...
  • 之一:需求与故事结构之二:编辑故事,产品管理,组织结构之三:迭代,计划会,分配任务之四:故事板,燃尽图,我的工作项之五:常见问题问答之六:我的空间,我的通知之七:自定义字段 日常跟进截图故事板:燃尽图...
  • 转自:http://duweizhong.blogbus.com/logs/112151436.html 、http://www.zentao.net/book/zentaopmshelp/103.html http://www.iamniu.com/2013/06/30/user-story-and-use-case/ Invest描述: I dependent(独
  • 在这样一个周六的下午,小编参加了一次北京敏捷社区(微信号:Agile1001)组织的活动:《用户故事地图User Story Mapping 实战工坊》,虽然对用户故事地图是第一次接触,但也有一些小小的体会,回到家中是在按捺不住...
  • 数据可视化-Tableau-故事

    千次阅读 2018-05-13 11:11:00
    故事 故事非常适合叙述你从数据中发现的规律。它们和显示面板相似,你可以创建工作表,然后将工作表拖到故事中。但是,每个工作表都单独显示,并且会有按顺序显示的叙述性文字。 这是创建的一个故事,我想查看为何...
  • nib、xib与故事板 如果大家使用过苹果的官方资料,一定会发现某些资料上会提到nib文件,那么nib与xib是怎样的一种关系呢? 最初只有nib文件,后来将其更名为xib,但大家一直沿袭nib这个叫法(即称xib文件为nib文件...
  • 敏捷开发中,团队成员认领的是任务还是用户故事
  • 用户故事详解

    万次阅读 2019-01-29 10:55:35
    在敏捷开发中, 用户故事 (user stories) 是一种轻量级,更灵活的替代品指定软件需求的传统方法 - 软件需求规范,用例规格等。 实际上,可以说用户故事是最重要的敏捷开发 (Agile Development) 中的工件 ...
  • iOS 5 故事板入门(1)

    万次阅读 2013-09-09 11:16:14
    原文: ...要想明白什么是故事板,请看下图。这同时也是本教程将创建的故事板:你也许不知道这个程序是干什么的,但它的主要屏幕界面及每个屏幕窗口之间的关系则通过这张图一目了然了。这就是使用故事
  • 如何用7个步骤开发用户故事地图 (User Story Map)什么是用户故事映射 (User Story Mapping)?用户故事映射是一种技术,允许您为积压 (backlog) 添加第二个维度。可视化使您能够看到Product Backlog的大图。它给你...
  • 在软件开发和产品管理中,用户故事是对软件系统的一个或多个特征的非正式的自然语言描述。用户故事是敏捷软件开发中使用的工具,用于从最终用户的角度捕获软件功能的描述。用户故事描述了用户的类型,他们想要什么...
1 2 3 4 5 ... 20
收藏数 100,650
精华内容 40,260
关键字:

故事版