iPhone SMS气泡UI

iPhone 户对内置的短信应用程序并不陌生以,它用一个超可爱的气泡方式显示短信,如图1。

图1

 

但是,这种创新的UI功能并没有开放给iPhone开发者,因此如果你想开发一款类似的app,你必须自己实现它。我命名这种UI叫着Bubble UI,它以聊天的方式显示信息。一个很好的例子就是你开发一款聊天app,两人聊天的内容用气泡显示。

 

本文我将向大家介绍开发类似sms应用程序的详细步骤。

 

 

准备气泡图片

首先,你需要像气泡的图片。我用是图2这张图片。

图2

 

如果细心的朋友可能发现内置的短信应用它的气泡大小不是固定的,它根据字的多少而变化。因此, 我们的消息气泡应能相应的扩展与收缩。在不影响气泡外貌的情况下最简单的方法就是将它分成9个小图片,像图3那样。

图3

 

 

如果你想扩展气泡的高度,只需要在垂直方向上将中间一排的图片简单的延伸(如图4的左图)。如果你想扩展气泡的宽度,只需要在水平方向上将中间一列的图片简单的延伸(如图4右图)。

图4

 

 

要显示的消息就覆盖在气泡上面就行了。

 

在此提醒大家,如果你想减少工作量,你可以不用将图片分成9张小图片,而只需要将整张气泡延伸。但这也要看你用的气泡图片样式,如果只一张矩图图片,那么延伸整张图片是最简单的方法。

 

 

创建工程

现在你知道生成消息气泡的方法,那进一步是创建代码工程。开启xcode并新建一个View-based(iphone)工程,并名命为BubbleUI。在Resources目录新建一个名叫icons的组。并把上面说到的9张小图拖到Icons分组中,如图5。

图5

 

双击 BubbleUIViewController.xib 激活interface Builder(xcode3 xcode 与IB是分开的,xcode4中内置了IB). 在View中添加一个TextFild,一个Round Rect Button,一个Table View,如 6。

图6

 

选择 了Table View去展 消息气泡。 是因 它可以滚 ,用 可以容易地看到所有消息,并且 一个消息气泡就是一个cell。这样 你就可以在Table View自定义每 个消息占用空

 

中Table View的属性 看器,并设置如图7所示。

图7

设置背景色为亮蓝(RGB值为219,226,237),这个色与我所使用的气片图片更搭配。Separator属性设为none是为了隐藏TableView每排的分隔线,这样一来就不像是Table View了。

 

下一步,设置View的背景色,使其与Table View更协调,如图8

图8

 

 

修改BubbleUIViewController.h的代码如下:

  1. #import <UIKit/UIKit.h>   
  2.    
  3. @interface BubbleUIViewController : UIViewController {  
  4.     //---add this---   
  5.     IBOutlet UITextField *itemName;  
  6.     IBOutlet UITableView *tableView;  
  7.     //--------------   
  8. }  
  9.    
  10. //---add this---   
  11. @property (nonatomic, retain) UITextField *itemName;  
  12. @property (nonatomic, retain) UITableView *tableView;  
  13.    
  14. -(IBAction) doneEditing:(id) sender;  
  15. -(IBAction) btnAdd:(id) sender;  
  16. //--------------   
  17.    
  18. @end  
 

 

回到IB, 设置Table View的数据源与代理为File's Owner item. 并前联变量tableView 到Table View, 如图9.

图9

 

下一步,连接Text Field view的事件Did End On Exit到响应方法doneEditing: 上, 出口到 itemName, 10.

图10

最后,连接圆形 button的事件Touch Up Inside到响 方法btnAdd: ,如 11

图11

BubbleUIViewController.m中,添加如下代

首先,声明一些变 量与常量:

  1. #import "BubbleUIViewController.h"   
  2.    
  3. @implementation BubbleUIViewController  
  4.    
  5. //---add this---   
  6. @synthesize itemName;  
  7. @synthesize tableView;  
  8.    
  9. NSMutableArray *listOfMessages;  
  10. NSMutableArray *dateOfMessages;  
  11.    
  12. static  CGFloat  const  FONTSIZE = 14.0;  
  13. static   int   const  DATELABEL_TAG = 1;  
  14. static   int   const  MESSAGELABEL_TAG = 2;  
  15. static   int   const  IMAGEVIEW_TAG_1 = 3;  
  16. static   int   const  IMAGEVIEW_TAG_2 = 4;  
  17. static   int   const  IMAGEVIEW_TAG_3 = 5;  
  18. static   int   const  IMAGEVIEW_TAG_4 = 6;  
  19. static   int   const  IMAGEVIEW_TAG_5 = 7;  
  20. static   int   const  IMAGEVIEW_TAG_6 = 8;  
  21. static   int   const  IMAGEVIEW_TAG_7 = 9;  
  22. static   int   const  IMAGEVIEW_TAG_8 = 10;  
  23. static   int   const  IMAGEVIEW_TAG_9 = 11;  
  24.    
  25. int  bubbleFragment_width, bubbleFragment_height;  
  26. int  bubble_x, bubble_y;  
  27. //--------------   
 

 

方法 doneEditing:实现 如下:

  1. -(IBAction) doneEditing9id) sender {  
  2.     [sender resignFirstResponder];  
  3. }  
 

 

viewDidLoad 初始化各种变量与数组:

  1. - ( void )viewDidLoad {  
  2.    
  3.     //---add this---   
  4.     //---location to display the bubble fragment---    
  5.     bubble_x = 10;  
  6.     bubble_y = 20;  
  7.    
  8.     //---size of the bubble fragment---   
  9.     bubbleFragment_width = 56;  
  10.     bubbleFragment_height = 32;  
  11.    
  12.     //---contains the messages---   
  13.     listOfMessages = [[NSMutableArray alloc] init];  
  14.    
  15.     //---contains the date for each message---   
  16.     dateOfMessages = [[NSMutableArray alloc] init];      
  17.    
  18.     //---add a message---   
  19.     [listOfMessages addObject:@"Hello there!" ];  
  20.     [dateOfMessages addObject:[NSString stringWithFormat:@"%@" ,[NSDate date]]];  
  21.     //--------------   
  22.    
  23.     [super viewDidLoad];  
  24. }  
 

 

设置Table View的sections数量为1:

  1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  
  2.     return  1;  
  3. }  

listOfMessages包括了所有要 显示 的消息,因此 Table View的排数就是数 的元 个数:

  1. - (NSInteger)tableView:(UITableView *)tableView     
  2.  numberOfRowsInSection:(NSInteger)section {  
  3.     return  [listOfMessages count];  
  4. }  
 

 

 

简单 ,所有的消息气泡都用固定的 度,差不多是 片的3倍大小。所有要显示 的消息也受限于该长 度。左右各25像边缘。因此,只需要计算要显示字符串的需要高度。用下面代码就可以解决问题:

  1. //---calculate the height for the message---   
  2. -(CGFloat) labelHeight:(NSString *) text {  
  3.     CGSize maximumLabelSize = CGSizeMake((bubbleFragment_width * 3) - 25,9999);  
  4.     CGSize expectedLabelSize = [text sizeWithFont:[UIFont systemFontOfSize: FONTSIZE]   
  5.                                 constrainedToSize:maximumLabelSize   
  6.                                     lineBreakMode:UILineBreakModeWordWrap];   
  7.     return  expectedLabelSize.height;  
  8. }  
 

 

上面这个方法输入参数为一个字符串,然后根据规定长度计算所占空间的高度。由于Table View每一排显示一个消息气泡,每一个消息气泡高度不一样,那就要设置每一排的高度。能过下面代码可以办到:

  1. //---returns the height for the table view row---   
  2. - (CGFloat)tableView:(UITableView *)tableView   
  3. heightForRowAtIndexPath:(NSIndexPath *)indexPath {    
  4.    
  5.     int  labelHeight = [self labelHeight:[listOfMessages  
  6.                           objectAtIndex:indexPath.row]];  
  7.     labelHeight -= bubbleFragment_height;  
  8.     if  (labelHeight<0) labelHeight = 0;  
  9.    
  10.     return  (bubble_y + bubbleFragment_height * 2 + labelHeight) + 5;      
  11. }  
 

 

最有挑占的部份就是把要显示的气泡消息交给Table View显示出来。让我们先来总览代码,我等一下再介绍之。这是该方法全部代码:

  1. - (UITableViewCell *)tableView:(UITableView *)tableView   
  2.          cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
  3.    
  4.     static  NSString *CellIdentifier = @ "Cell" ;  
  5.    
  6.     //---add this---   
  7.     UILabel* dateLabel = nil;  
  8.     UILabel* messageLabel = nil;  
  9.     UIImageView *imageView_top_left = nil;  
  10.     UIImageView *imageView_top_middle = nil;  
  11.     UIImageView *imageView_top_right = nil;  
  12.    
  13.     UIImageView *imageView_middle_left = nil;  
  14.     UIImageView *imageView_middle_right = nil;  
  15.     UIImageView *imageView_middle_middle = nil;  
  16.    
  17.     UIImageView *imageView_bottom_left = nil;  
  18.     UIImageView *imageView_bottom_middle = nil;  
  19.     UIImageView *imageView_bottom_right = nil;  
  20.     //--------------   
  21.    
  22.     UITableViewCell *cell = [tableView   
  23.         dequeueReusableCellWithIdentifier:CellIdentifier];  
  24.    
  25.     if  (cell == nil) {  
  26.         cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero  
  27.                                        reuseIdentifier:CellIdentifier]   
  28.                                        autorelease];  
  29.    
  30.         //---add this---   
  31.         //---date---   
  32.         dateLabel = [[[UILabel alloc] init] autorelease];  
  33.         dateLabel.tag = DATELABEL_TAG;  
  34.         [cell.contentView addSubview: dateLabel];  
  35.    
  36.         //---top left---   
  37.         imageView_top_left = [[[UIImageView alloc] init] autorelease];  
  38.         imageView_top_left.tag = IMAGEVIEW_TAG_1;          
  39.         [cell.contentView addSubview: imageView_top_left];  
  40.    
  41.         //---top middle---   
  42.         imageView_top_middle = [[[UIImageView alloc] init] autorelease];  
  43.         imageView_top_middle.tag = IMAGEVIEW_TAG_2;  
  44.         [cell.contentView addSubview: imageView_top_middle];  
  45.    
  46.         //---top right---   
  47.         imageView_top_right = [[[UIImageView alloc] init] autorelease];  
  48.         imageView_top_right.tag = IMAGEVIEW_TAG_3;  
  49.         [cell.contentView addSubview: imageView_top_right];  
  50.    
  51.         //---middle left---   
  52.         imageView_middle_left = [[[UIImageView alloc] init] autorelease];  
  53.         imageView_middle_left.tag = IMAGEVIEW_TAG_4;  
  54.         [cell.contentView addSubview: imageView_middle_left];  
  55.    
  56.         //---middle middle---   
  57.         imageView_middle_middle = [[[UIImageView alloc] init] autorelease];  
  58.         imageView_middle_middle.tag = IMAGEVIEW_TAG_5;  
  59.         [cell.contentView addSubview: imageView_middle_middle];  
  60.    
  61.         //---middle right---   
  62.         imageView_middle_right = [[[UIImageView alloc] init] autorelease];  
  63.         imageView_middle_right.tag = IMAGEVIEW_TAG_6;  
  64.         [cell.contentView addSubview: imageView_middle_right];  
  65.    
  66.         //---bottom left---   
  67.         imageView_bottom_left = [[[UIImageView alloc] init] autorelease];  
  68.         imageView_bottom_left.tag = IMAGEVIEW_TAG_7;  
  69.         [cell.contentView addSubview: imageView_bottom_left];  
  70.    
  71.         //---bottom middle---   
  72.         imageView_bottom_middle = [[[UIImageView alloc] init] autorelease];  
  73.         imageView_bottom_middle.tag = IMAGEVIEW_TAG_8;  
  74.         [cell.contentView addSubview: imageView_bottom_middle];  
  75.    
  76.         //---bottom right---   
  77.         imageView_bottom_right = [[[UIImageView alloc] init] autorelease];  
  78.         imageView_bottom_right.tag = IMAGEVIEW_TAG_9;  
  79.         [cell.contentView addSubview: imageView_bottom_right];  
  80.    
  81.         //---message---   
  82.         messageLabel = [[[UILabel alloc] init] autorelease];  
  83.         messageLabel.tag = MESSAGELABEL_TAG;          
  84.         [cell.contentView addSubview: messageLabel];  
  85.    
  86.         //---set the images to display for each UIImageView---   
  87.         imageView_top_left.image =   
  88.             [UIImage imageNamed:@"bubble_top_left.png" ];  
  89.         imageView_top_middle.image =   
  90.             [UIImage imageNamed:@"bubble_top_middle.png" ];  
  91.         imageView_top_right.image =   
  92.             [UIImage imageNamed:@"bubble_top_right.png" ];  
  93.    
  94.         imageView_middle_left.image =   
  95.             [UIImage imageNamed:@"bubble_middle_left.png" ];  
  96.         imageView_middle_middle.image =   
  97.             [UIImage imageNamed:@"bubble_middle_middle.png" ];  
  98.         imageView_middle_right.image =   
  99.             [UIImage imageNamed:@"bubble_middle_right.png" ];  
  100.    
  101.         imageView_bottom_left.image =   
  102.             [UIImage imageNamed:@"bubble_bottom_left.png" ];  
  103.         imageView_bottom_middle.image =   
  104.             [UIImage imageNamed:@"bubble_bottom_middle.png" ];  
  105.         imageView_bottom_right.image =   
  106.             [UIImage imageNamed:@"bubble_bottom_right.png" ];          
  107.    
  108.     } else  {          
  109.         //---reuse the old views---           
  110.        dateLabel = (UILabel*)[cell.contentView viewWithTag: DATELABEL_TAG];  
  111.        messageLabel = (UILabel*)[cell.contentView viewWithTag: MESSAGELABEL_TAG];          
  112.    
  113.         imageView_top_left =   
  114.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_1];  
  115.         imageView_top_middle =   
  116.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_2];  
  117.         imageView_top_right =   
  118.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_3];  
  119.    
  120.         imageView_middle_left =   
  121.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_4];  
  122.         imageView_middle_middle =   
  123.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_5];  
  124.         imageView_middle_right =   
  125.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_6];  
  126.    
  127.         imageView_bottom_left =   
  128.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_7];  
  129.         imageView_bottom_middle =   
  130.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_8];  
  131.         imageView_bottom_right =   
  132.             (UIImageView*)[cell.contentView viewWithTag: IMAGEVIEW_TAG_9];                  
  133.     }  
  134.    
  135.     //---calculate the height for the label---   
  136.     int  labelHeight = [self labelHeight:[listOfMessages objectAtIndex:indexPath.row]];  
  137.     labelHeight -= bubbleFragment_height;  
  138.     if  (labelHeight<0) labelHeight = 0;     
  139.    
  140.     //---you can customize the look and feel for the date for each message here---   
  141.     dateLabel.frame = CGRectMake(0.0, 0.0, 200, 15.0);  
  142.     dateLabel.font = [UIFont boldSystemFontOfSize: FONTSIZE];  
  143.     dateLabel.textAlignment = UITextAlignmentLeft;  
  144.     dateLabel.textColor = [UIColor darkGrayColor];  
  145.     dateLabel.backgroundColor = [UIColor clearColor];  
  146.    
  147.     //---top left---   
  148.     imageView_top_left.frame =   
  149.         CGRectMake(bubble_x, bubble_y, bubbleFragment_width, bubbleFragment_height);          
  150.     //---top middle---   
  151.     imageView_top_middle.frame =   
  152.         CGRectMake(bubble_x + bubbleFragment_width, bubble_y,   
  153.                    bubbleFragment_width, bubbleFragment_height);          
  154.     //---top right---   
  155.     imageView_top_right.frame =   
  156.         CGRectMake(bubble_x + (bubbleFragment_width * 2), bubble_y,   
  157.                    bubbleFragment_width, bubbleFragment_height);          
  158.     //---middle left---   
  159.     imageView_middle_left.frame =   
  160.         CGRectMake(bubble_x, bubble_y + bubbleFragment_height,   
  161.                    bubbleFragment_width, labelHeight);          
  162.     //---middle middle---   
  163.     imageView_middle_middle.frame =   
  164.         CGRectMake(bubble_x + bubbleFragment_width, bubble_y + bubbleFragment_height,   
  165.                    bubbleFragment_width, labelHeight);          
  166.     //---middle right---   
  167.     imageView_middle_right.frame =   
  168.         CGRectMake(bubble_x + (bubbleFragment_width * 2),   
  169.                    bubble_y + bubbleFragment_height,   
  170.                    bubbleFragment_width, labelHeight);          
  171.     //---bottom left---   
  172.     imageView_bottom_left.frame =   
  173.         CGRectMake(bubble_x, bubble_y + bubbleFragment_height + labelHeight,   
  174.                    bubbleFragment_width, bubbleFragment_height );           
  175.     //---bottom middle---   
  176.     imageView_bottom_middle.frame =   
  177.         CGRectMake(bubble_x + bubbleFragment_width,   
  178.                    bubble_y + bubbleFragment_height + labelHeight,  
  179.                    bubbleFragment_width, bubbleFragment_height);          
  180.     //---bottom right---   
  181.     imageView_bottom_right.frame =   
  182.         CGRectMake(bubble_x + (bubbleFragment_width * 2),   
  183.                    bubble_y + bubbleFragment_height + labelHeight,   
  184.                    bubbleFragment_width, bubbleFragment_height );  
  185.    
  186.     //---you can customize the look and feel for each message here---       
  187.     messageLabel.frame =   
  188.         CGRectMake(bubble_x + 10, bubble_y + 5,   
  189.                   (bubbleFragment_width * 3) - 25,   
  190.                   (bubbleFragment_height * 2) + labelHeight - 10);  
  191.    
  192.     messageLabel.font = [UIFont systemFontOfSize:FONTSIZE];          
  193.     messageLabel.textAlignment = UITextAlignmentCenter;  
  194.     messageLabel.textColor = [UIColor darkTextColor];  
  195.     messageLabel.numberOfLines = 0; //---display multiple lines---   
  196.     messageLabel.backgroundColor = [UIColor clearColor];  
  197.     messageLabel.lineBreakMode = UILineBreakModeWordWrap;          
  198.    
  199.     dateLabel.text = [dateOfMessages objectAtIndex:indexPath.row];  
  200.     messageLabel.text = [listOfMessages objectAtIndex:indexPath.row];      
  201.     //--------------   
  202.    
  203.     return  cell;  
  204. }  
 

 

这个方法看起来很长,但是读起来却是一目了然。下面的伪代码展示它的主要逻辑:

  1. if  (cell == nil) {  
  2.      //---create and instantiate all the Label and UIImageView views---   
  3.      //---then add them to the cell---   
  4.   
  5.  } else  {          
  6.      //---reuse the old views previously added to the cell---           
  7.  }  
  8.  //---customize the size, font, etc of all the views in the cell---   
 

 

其实就是由UIImageView与Label View构造成了消息气泡.  总共有9个UIImageView,每一个就是那张气泡图片的一部份。把这些view再放在cell里,这个cell就是UITableViewCell 类的一个例。 当用户滚动TableView的时候,为了让离屏的view能重复利用, 我们在加入cell的时候就加入了tag标志,如下:

  1. messageLabel.tag = MESSAGELABEL_TAG;  
 

 

当你要重复用view的时候,你只需要像下面一样的方法就可以得到它:

  1. messageLabel = (UILabel*)[cell.contentView viewWithTag: MESSAGELABEL_TAG];  
 

 

当用户点击了add按钮,就需要将消息加入到listOfMessages这个数组中,并通知TableView重新加载。相应的你也要把当前时间加到dateOfMessage这个数组当中:

  1. //---add a message to the table view---   
  2. -(IBAction) btnAdd:(id) sender {  
  3.     [listOfMessages addObject:itemName.text];      
  4.     [dateOfMessages addObject:[NSString stringWithFormat:@"%@" ,[NSDate date]]];  
  5.     [self.tableView reloadData];  
  6. }  
 

 

最后, release这两个数组:

  1. - ( void )dealloc {  
  2.     [listOfMessages release];  
  3.     [dateOfMessages release];       
  4.     [super dealloc];  
  5. }  
 

 

按Commond+R在iPhone模拟器上运行,图12是程序的最终效果:

图12

 

 

 

总结


在本文中,你可以学到如何创建一个sms UI风格的应用程序。你可以修改代码,可以修改气泡的颜色,形状与大小。最重要的是,它可以让你的应用程序更加有趣,更具人性化。

 

源码下载

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值