相关文章推荐
大鼻子的煎鸡蛋  ·  Java ...·  6 月前    · 
重情义的椰子  ·  String.Contains 方法 ...·  7 月前    · 
任性的包子  ·  flying-saucer/iText ...·  1 年前    · 
绅士的冰淇淋  ·  hostname | Microsoft ...·  1 年前    · 
 1 @interface ViewController : UIViewController
 3 @property(nonatomic, weak)IBOutlet UILabel *lable;
 5 @end
 9 @interface ViewController ()
11 @end
13 @implementation ViewController
15 /**
16  红色按钮
17  */
18 - (IBAction)redBtnClick
20 //    -[ViewController redBtnClick]
21     NSLog(@"%s", __func__);
22     // 拿到UILabel对象, 修改对象的属性, 让label对象变为红色
23     self.lable.textColor = [UIColor redColor];
24     self.lable.text = @"我是红色文字";
25     self.lable.backgroundColor = [UIColor purpleColor];
26     self.lable.font = [UIFont systemFontOfSize:30];
27     self.lable.textAlignment = NSTextAlignmentCenter;
29 /**
30  绿色按钮
31  */
32 - (IBAction)greenBtnClick
34     NSLog(@"%s", __func__);
35     self.lable.textColor = [UIColor greenColor];
37 /**
38  蓝色按钮
39  */
40 - (IBAction)blueBtnClick
42     NSLog(@"%s", __func__);
43     self.lable.textColor = [UIColor blueColor];
45 @end

一、控制器

1.什么是控制器:

任何继承于UIViewController的类,都称之为控制器

2.控制器的作用:

管理UI界面(负责管理UI界面的创建和一些事件的处理)

3.注意点:

UI界面是可以和它与之对应的控制器进行连线的,我们可以通过连线的方式,让UI界面上的元素和控制器中的代码产生一定的关系;默认情况下,UI界面中的元素是不能和方法进行关联的,要想关联UI界面中的元素必须将方法的返回值修改为IBAction。

二、IBAction和IBOutlet

  • IBAction
  • - (IBAction)redBtnClick;

    1. IBAction

    1.1 从返回值角度上看,作用相当于void

    1.2 只有返回值声明为IBAction的方法,才能跟storyboard中的控件进行连线

    1.3 IBAction只能加在方法上, 不能加在属性上

    2. IBAction几种连线方式

    从"控制器"往"Storyboard"连线

    从"Storyboard"往"控制器"连线

    直接在"Storyboard"中往"Storyboard"上的界面顶部连线

    直接在"Storyboard"中往"Storyboard"上的工具条连线

    不用先定义方法, 直接从"Storyboard"往"控制器"连线(常用)

    3.IBAction连线的注意点:

    3.1 在Storyboard中拷贝元素的时候需要注意

    拷贝的同时会将以前的连线一起拷贝

    一个方法可以很多个控件关联

    一个控件可以和很多方法进行连线,在开发中, 一般情况下不会这样写

    3.2 如果将按钮关联的方法删除, 运行之后会报一个经典错误

    reason: '-[ViewController redBtnClick]: unrecognized selector sent to instance 0x7fb4aa618e50'

    3.3 IBAction只能作为方法的返回值

  • IBOutlet
  • @property(nonatomic, weak)IBOutlet UILabel *lable;

    1. IBOutlet

    1.1 只有声明为IBOutlet的属性,才能跟storyboard中的控件进行连线

    1.2 属性要想能够连线必须在数据类型前面加上IBOutlet

    2. IBOutlet的几种连线方式

    从"控制器"往"Storyboard"连线

    从"Storyboard"往"控制器"连线

    直接在"Storyboard"中往"Storyboard"上的界面顶部连线

    直接在"Storyboard"中往"Storyboard"上的工具条连线

    不用先定义方法, 直接从"Storyboard"往"控制器"连线

    3. 注意点:

    一个控件可以关联多个属性

    一个属性不可以关联多个控件

    在进行属性连线的时候, Xcode会自动帮我们进行类型检测, 如果类型不匹配那么不能连线

    如果将属性和控件连线之后又将属性删除了, 那么只要程序运行就会报一个经典错误

    '[<ViewController 0x7fe9d9f1a5d0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key lable.'

    任何UI控件都可以和属性进行连线, 但是并不是任何控件都可以和方法连线. 只有继承于UIControl的控件才可以连线

    三、UIView

    + 什么是控件?

    - 屏幕上的所有UI元素都叫做控件,也有人叫做视图、组件

    - 按钮(UIButton)、文本(UILabel)都是控件

    + 控件的共同属性有哪些?

    - 背景色

    - ......

    + 苹果将控件的共同属性都抽取到父类UIView中

    - 所有的控件最终都继承自UIView

    - UIButton、UILabel都是继承自UIView(可以查看头文件)

    +  每一个控制器(UIViewController)内部都有个默认的UIView属性

    - @property(nonatomic,retain) UIView *view;

    - 控制器中管理的其他所有控件都是这个view的子控件(直接或者间接)

    + UIView常见属性和方法

     1 + @property(nonatomic,readonly) UIView *superview;
     2  //获得自己的父控件对象
     4 + @property(nonatomic,readonly,copy) NSArray *subviews;
     5  //获得自己的所有子控件对象
     7 + @property(nonatomic) NSInteger tag;
     8  //控件的ID(标识),父控件可以通过tag来找到对应的子控件
    10 + @property(nonatomic) CGAffineTransform transform;
    11 // 控件的形变属性(可以设置旋转角度、比例缩放、平移等属性)
    13 + @property(nonatomic) CGRect frame;
    14 // 控件矩形框在父控件中的位置和尺寸(以父控件的左上角为坐标原点)
    16 + @property(nonatomic) CGRect bounds;
    17  //控件矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x、y一般为0)
    19 + @property(nonatomic) CGPoint center;
    20 // 控件中点的位置(以父控件的左上角为坐标原点)
    25 - (void)addSubview:(UIView *)view;
    26  //添加一个子控件view
    28 - (void)removeFromSuperview;
    29  //从父控件中移除
    31 - (UIView *)viewWithTag:(NSInteger)tag;
    32  //根据一个tag标识找出对应的控件(一般都是子控件)

    normal(普通状态)

    默认情况(Default) 对应的枚举常量:UIControlStateNormal

    highlighted(高亮状态) 按钮被按下去的时候(手指还未松开) 对应的枚举常量:UIControlStateHighlighted

    disabled(失效状态,不可用状态) 如果enabled属性为NO,就是处于disable状态,代表按钮不可以被点击 对应的枚举常量:UIControlStateDisabled

    设置按钮的背景图片

    设置按钮在不同状态下的背景图片 (为了保证高亮状态下的图片正常显示,必须设置按钮的type为custom)

    实际上,UIButton自带了很多种不同的样式

    在用代码创建按钮的同时指定按钮样式 UIButton *b tn = [UIButton buttonWithType:UIButtonTypeCustom];

    UIButtonTypeCustom:无类型,按钮的内容需 要自定义

    UIButtonTypeDetailDisclosure:

    UIButtonTypeInfoLight:

    UIButtonTypeInfoDark:

    UIButtonTypeContactAdd:

    UIButton的常见设置

    - (void)setTitle:(NSString *)title forState:(UIControlState)state、;

    设置按钮的文字

    - (void)setTitleColor:(UIColor *)color forState:(UIControlState)state;

    设置按钮的文字颜色

    - (void)setImage:(UIImage *)image forState:(UIControlState)state;

    设置按钮内部的小图片

    - (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;

    设置按钮的背景图片

    设置按钮的文字字体(需要拿到按钮内部的label来设置)

    btn.titleLabel.font = [UIFont systemFontOfSize:13];

    - (NSString *)titleForState:(UIControlState)state;

    获得按钮的文字

    - (UIColor *)titleColorForState:(UIControlState)state;

    获得按钮的文字颜色

    - (UIImage *)imageForState:(UIControlState)state;

    获得按钮内部的小图片

    - (UIImage *)backgroundImageForState:(UIControlState)state;

    获得按钮的背景图片

    创建UIButton

    UIButton *btn = [ UIButton buttonWithType :UIButtonTypeRoundedRect ];

    btn. frame = CGRectMake( 30, 360, 90, 35);

    [btn setTitle : @"ZoomIn" forState :UIControlStateNormal ];

    [btn setTitle : @"ZoomIn" forState :UIControlStateHighlighted ];

    [btn addTarget : self action : @selector ( zoomInAction :) forControlEvents :UIControlEventTouchUpInside ];

    //@selector可以理解为"选择子",selector是一个指针变量,类似于sender。 这里是将method的方法指定给新建的这个btn。

    /*在 method 方法里可以将 sender 看作是 btn 了
    比如设置btn的hidden属性等等
    btn.hidden = YES;
    这样btn被隐藏了

    [view addSubview:btn];
    -(void)zoomInAction:(id)sender {
    

    UIButton的类是一个UIControl子类,它实现了在触摸屏上的按钮。触摸一个按钮拦截事件和动作消息发送到目标对象时,它的挖掘。设定的目标和行动方法都继承自UIControl。这个类提供了方法来设置标题,图像,按钮等外观属性。通过使用set方法,你可以指定一个不同的外观为每个按钮状态。

    创建按钮+ buttonWithType:配置按钮的标题

     ButtonType属性字体属性lineBreakMode财产titleShadowOffset财产reversesTitleShadowWhenHighlighted财产  
    

    - setTitle:forState: - setTitleColor:forState: - setTitleShadowColor:forState: - titleColorForState: - titleForState: - titleShadowColorForState:配置按钮图像

     adjustsImageWhenHighlighted财产adjustsImageWhenDisabled财产showsTouchWhenHighlighted财产  
    

    - backgroundImageForState: - imageForState: - setBackgroundImage:forState: - setImage:forState:配置边缘的Insets

     titleEdgeInsets财产imageEdgeInsets财产contentEdgeInsets财产  
    

    获取当前状态

     currentTitle财产currentTitleColor财产currentTitleShadowColor财产currentImage财产currentBackgroundImage财产  
    

    尺寸入门 - backgroundRectForBounds: - contentRectForBounds: - titleRectForContentRect: - imageRectForContentRect:

    Objective - C的属性,看到的Objective - C 2.0编程语言中的“属性”。

    adjustsImageWhenDisabled

    一个布尔值,决定是否形象的变化时,该按钮被禁用。

    @属性(非原子)BOOL adjustsImageWhenDisabled讨论,如果是的话,图像绘制较深时,按钮被禁用。默认值是YES。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产adjustsImageWhenHighlighted
    

    在UIButton.h宣布相关的示例代码BubbleLevel

    adjustsImageWhenHighlighted

    一个布尔值,决定是否按钮时,突出显示图像的变化。

    @属性(非原子)BOOL adjustsImageWhenHighlighted讨论,如果是,绘制图像较轻的按钮时,突出显示。默认值是YES。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产adjustsImageWhenDisabled
    

    在UIButton.h宣布相关的示例代码BubbleLevel

    按钮类型。(只读)

    @属性(非原子,只读)UIButtonType按钮类型的讨论,见UIButtonType的可能值。

    供货情况在iPhone OS 2.0和更高版本。声明在UIButton.h

    contentEdgeInsets

    内容的插图或一开始就为每个边缘。

    @属性(非原子)UIEdgeInsets contentEdgeInsets如果每条边的价值是积极的,指定的插图,否则,指定一开始。一个插图是周围绘制矩形的保证金;每边(左,右,顶部和底部),可以有不同的值。使用UIEdgeInsetsMake功能设置此属性。默认值是UIEdgeInsetsZero。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     _AT_财产imageEdgeInsets
    

    宣布UIButton.h currentBackgroundImage按钮上显示当前的背景图像。(只读)

    @属性(只读,非原子,保留)的UIImage * currentBackgroundImage讨论这个值可以为零。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     _AT_财产currentImage
    

    声明在UIButton.h

    currentImage

    当前图像上显示的按钮。(只读)

    @属性(只读,非原子,保留)的UIImage * currentImage讨论这个值可以为零。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     _AT_财产currentBackgroundImage
    

    声明在UIButton.h

    currentTitle

    当前标题,按钮上显示的。(只读)

    @属性(只读,非原子,保留)的NSString * currentTitle讨论这个值可能为零。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产currentTitleColor财产currentTitleShadowColor
    

    声明在UIButton.h

    currentTitleColor

    颜色用于显示标题。(只读)

    @属性(只读,非原子,保留)UIColor * currentTitleColor讨论这个值是保证不会是零。默认值是白色。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产currentTitle财产currentTitleShadowColor
    

    声明在UIButton.h

    currentTitleShadowColor

    标题的阴影的颜色。(只读)

    @属性(只读,非原子,保留)UIColor * currentTitleShadowColor讨论默认值是白色。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产currentTitle财产currentTitleColor
    

    声明在UIButton.h

    字体用来显示按钮上的文字。

    @属性(非原子,保留)UIFont *字体的讨论,如果为零,使用系统字体。默认值是零。

    供货情况在iPhone OS 2.0和更高版本。声明在UIButton.h

    imageEdgeInsets

    图像插图或一开始就为每个边缘。

    @属性(非原子)UIEdgeInsets imageEdgeInsets如果每条边的价值是积极的,指定的插图,否则,指定一开始。一个插图是周围绘制矩形的保证金;每边(左,右,顶部和底部),可以有不同的值。使用UIEdgeInsetsMake功能设置此属性。默认值是UIEdgeInsetsZero。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     _AT_财产titleEdgeInsets
    

    声明在UIButton.h

    lineBreakMode

    绘制文本时使用的换行模式。

    属性(非原子)UILineBreakMode lineBreakMode讨论这个属性是UILineBreakMode描述的常量之一。默认值是UILineBreakModeMiddleTruncation。

    供货情况在iPhone OS 2.0和更高版本。在UIButton.h声明reversesTitleShadowWhenHighlighted一个布尔值,决定是否按钮时,突出的标题阴影的变化。

    如果有属性(非原子)BOOL reversesTitleShadowWhenHighlighted讨论,从雕刻的影子时,突出浮雕外观的变化。默认值是NO。

    供货情况在iPhone OS 2.0和更高版本。声明在UIButton.h

    showsTouchWhenHighlighted

    一个布尔值,决定是否点击按钮会导致其发光。

    @属性(非原子)BOOL showsTouchWhenHighlighted讨论,如果是的话,按钮发光时挖掘出来,否则,它不会。图像和按钮的行为是没有改变的辉光。默认值是NO。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     @财产adjustsImageWhenHighlighted
    

    声明在UIButton.h

    titleEdgeInsets

    标题插图或一开始就为每个边缘。

    @属性(非原子)UIEdgeInsets titleEdgeInsets如果每条边的价值是积极的,指定的插图,否则,指定一开始。一个插图是周围绘制矩形的保证金;每边(左,右,顶部和底部),可以有不同的值。使用UIEdgeInsetsMake功能设置此属性。默认值是UIEdgeInsetsZero。

    供货情况在iPhone OS 2.0和更高版本。另请参见

     _AT_财产imageEdgeInsets
    

    声明在UIButton.h

    titleShadowOffset

    用于显示接收的标题阴影的偏移。

    属性(非原子)CGSize titleShadowOffset讨论的水平和垂直偏移值,使用CGSize数据类型的宽度和高度场指定的。正面的价值观总是向上延伸的权利,从用户的角度来看。默认值是CGSizeZero。

    供货情况在iPhone OS 2.0和更高版本。宣布UIButton.h类方法

    buttonWithType:创建并返回一个指定类型的新按钮。

    +(ID)buttonWithType:(UIButtonType)按钮类型

    按钮类型。见的可能值UIButtonType。

    返回值一个新创建的按钮。

    供货情况在iPhone OS 2.0和更高版本。相关的示例代码配件BubbleLevel TheElements TouchCells UICatalog宣布UIButton.h实例方法

    backgroundImageForState:

    返回一个按钮的状态中使用的背景图像。

    - (UIImage的*)backgroundImageForState:(UIControlState)状态

    参数状态的状态使用的背景图像。可能的值是在UIControlState描述。

    返回值用于指定的状态背景图像。

    供货情况在iPhone OS 2.0和更高版本。又见 - setBackgroundImage:forState:UIButton.h声明

    backgroundRectForBounds:

    返回矩形的接收绘制其背景。

    - (CGRect)backgroundRectForBounds:(CGRect)边界

    参数范围接收器的边界矩形。

    返回值的矩形接收机,绘制其背景。

    供货情况在iPhone OS 2.0和更高版本。又见 - contentRectForBounds:UIButton.h声明

    contentRectForBounds:

    返回矩形的接收提请其全部内容。

    - (CGRect)contentRectForBounds:(CGRect)边界

    参数限定为接收器的边界矩形。

    返回值的矩形接收提请其全部内容。

    讨论内容的矩形来显示图像和标题对齐和其他设置,包括任何填充和调整所需的面积。

    供货情况在iPhone OS 2.0和更高版本。 - titleRectForContentRect: - imageRectForContentRect: - backgroundRectForBounds:UIButton.h imageForState中声明:返回一个按钮的状态所使用的图像。

    - (UIImage的*)imageForState:(UIControlState)状态

    参数状态使用图像的状态。可能的值是在UIControlState描述。

    返回值用于指定状态的图像。

    供货情况在iPhone OS 2.0和更高版本。又见 - setImage:forState:UIButton.h imageRectForContentRect宣布:返回接收绘制其图像的矩形。

    - (CGRect)imageRectForContentRect:(CGRect)contentRect

    参数contentRect接收的内容矩形。

    返回值接收绘制其图像的矩形。

    供货情况在iPhone OS 2.0和更高版本。又见 - contentRectForBounds: - titleRectForContentRect:forState::UIButton.h setBackgroundImage宣布设置背景图像使用指定的按钮状态。

    - (无效)setBackgroundImage:(UIImage的*)图像forState:(UIControlState)状态

    参数图像背景图像使用指定的状态。

    状态的状态使用指定的图像。在UIControlState值的描述。

    在一般性讨论,如果没有一个国家指定一个属性,默认是使用UIControlStateNormal的价值。如果UIControlStateNormal值未设置,则属性默认为一个系统的价值。因此,至少,你应该设置为正常状态的价值。

    供货情况在iPhone OS 2.0和更高版本。又见 - backgroundImageForState:相关示例代码配件BubbleLevel TheElements UICatalog UIButton.h setImage宣布:forState:设置图像使用指定的状态。

    - (无效)setImage:(UIImage的*)图像forState:(UIControlState)状态

    参数图像的图像使用指定的状态。

    状态的状态使用指定的标题。在UIControlState值的描述。

    在一般性讨论,如果没有一个国家指定一个属性,默认是使用UIControlStateNormal的价值。如果UIControlStateNormal值未设置,则属性默认为一个系统的价值。因此,至少,你应该设置为正常状态的价值。

    供货情况在iPhone OS 2.0和更高版本。又见 - imageForState:forState::相关示例代码BubbleLevel在UIButton.h setTitle声明TouchCells设置标题使用指定的状态。

    - (无效)setTitle是:(NSString的*)forState标题:(UIControlState)状态

    参数标题标题使用指定的状态。

    状态的状态使用指定的标题。在UIControlState值的描述。

    在一般性讨论,如果没有一个国家指定一个属性,默认是使用UIControlStateNormal的价值。如果UIControlStateNormal价值不设置,则属性默认为系统值。因此,至少,你应该设置为正常状态的价值。

    供货情况在iPhone OS 2.0和更高版本。又见 - titleForState:UIButton.h setTitleColor:forState相关的示例代码BubbleLevel UICatalog宣布:设置标题使用指定的状态的颜色。

    - (无效)setTitleColor:(UIColor *)颜色forState:(UIControlState)状态

    参数颜色的标题使用指定的状态的颜色。

    状态的状态使用指定的颜色。在UIControlState值的描述。

    在一般性讨论,如果没有一个国家指定一个属性,默认是使用UIControlStateNormal的价值。如果UIControlStateNormal值未设置,则属性默认为一个系统的价值。因此,至少,你应该设置为正常状态的价值。

    供货情况在iPhone OS 2.0和更高版本。又见 - titleColorForState:UIButton.h setTitleShadowColor:forState相关的示例代码BubbleLevel UICatalog宣布:设置标题阴影的颜色,使用指定的状态。

    - (无效)setTitleShadowColor:(UIColor *)颜色forState:(UIControlState)状态

    参数颜色的标题阴影的颜色,使用指定的状态。

    状态的状态使用指定的颜色。在UIControlState值的描述。

    在一般性讨论,如果没有一个国家指定一个属性,默认是使用UIControlStateNormal的价值。如果UIControlStateNormal值未设置,则属性默认为一个系统的价值。因此,至少,你应该设置为正常状态的价值。

    供货情况在iPhone OS 2.0和更高版本。又见 - titleShadowColorForState:UIButton.h titleColorForState宣布:返回一个国家使用的标题的颜色。

    - (UIColor *)titleColorForState:(UIControlState)状态

    参数状态的国家,使用的标题颜色。可能的值是在UIControlState描述。

    返回值指定的状态标题的颜色。

    供货情况在iPhone OS 2.0和更高版本。又见 - setTitleColor:forState:UIButton.h titleForState宣布:返回一个国家所使用的标题。

    - (NSString的*)titleForState:(UIControlState)状态

    参数状态的国家,使用的标题。可能的值是在UIControlState描述。

    返回值指定的状态标题。

    供货情况在iPhone OS 2.0和更高版本。又见 - setTitle:forState:UIButton.h titleRectForContentRect宣布:返回矩形的接收器绘制它的标题。

    - (CGRect)titleRectForContentRect:(CGRect)contentRect

    参数contentRect接收的内容矩形。

    返回值的矩形接收器绘制它的标题。

    供货情况在iPhone OS 2.0和更高版本。又见 - contentRectForBounds: - imageRectForContentRect:UIButton.h titleShadowColorForState宣布:返回的阴影颜色为国家所用的标题。

    - (UIColor *)titleShadowColorForState:(UIControlState)状态

    参数状态的国家,使用的标题阴影颜色。可能的值是在UIControlState描述。

    返回值指定的状态标题的影子颜色。

    供货情况在iPhone OS 2.0和更高版本。又见 - setTitleShadowColor:forState:UIButton.h常量声明

    UIButtonType指定一个按钮的风格。

    的typedef枚举{

    UIButtonTypeCustom = 0,UIButtonTypeRoundedRect,UIButtonTypeDetailDisclosure,UIButtonTypeInfoLight,UIButtonTypeInfoDark,UIButtonTypeContactAdd
    

    } UIButtonType;常量UIButtonTypeCustom无按钮的样式。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    UIButtonTypeRoundedRect一个圆角矩形样式的按钮。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    UIButtonTypeDetailDisclosure一个详细披露按钮。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    UIButtonTypeInfoLight一个信息按钮,有一个浅色背景。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    UIButtonTypeInfoDark一个信息按钮,有一个黑暗的背景。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    UIButtonTypeContactAdd一个联系人添加“按钮。

    在iPhone OS 2.0及更高版本。

    声明中UIButton.h。

    供货情况在iPhone OS 2.0和更高版本。声明在UIButton.h

     (一)2.UILabel

    UILabel极其常用,功能比较专一:显示文字

    UILabel的常见属性

    @property(nonatomic,copy) NSString *text;

    显示的文字

    @property(nonatomic,retain) UIFont *font;

    @property(nonatomic,retain) UIColor *textColor;

    @property(nonatomic) NSTextAlignment textAlignment;

    对齐模式(比如左对齐、居中对齐、右对齐)

    @property(nonatomic) NSInteger numberOfLines;

    @property(nonatomic) NSLineBreakMode lineBreakMode;

    UIFont

    UIFont代表字体,常见创建方法有以下几个:

    + (UIFont *)systemFontOfSize:(CGFloat)fontSize; 系统默认字体

    + (UIFont *)boldSystemFontOfSize:(CGFloat)fontSize; 粗体

     + (UIFont *)italicSystemFontOfSize:(CGFloat)fontSize; 斜体

    #import "LabelTestViewController.h"     

    @implementation LabelTestViewController     

     Accessing the Text Attributes   

     text  property     

     font  property     

     textColor  property     

     textAlignment  property     

     lineBreakMode  property       

     enabled  property     

     Sizing the Label’s Text   

     adjustsFontSizeToFitWidth  property     

     baselineAdjustment  property     

     minimumFontSize  property   无例   

     numberOfLines  property     

     Managing Highlight Values   

     highlightedTextColor  property     

     highlighted  property     

     Drawing a Shadow   

     shadowColor  property     

     shadowOffset  property     

     Drawing and Positioning Overrides   

     – textRectForBounds:limitedToNumberOfLines: 无例    

     – drawTextInRect:  无例   

     Setting and Getting Attributes   

     userInteractionEnabled  property     

    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.     

    - (void)viewDidLoad {     

        UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 20.0, 200.0, 50.0)];     

        UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 80.0, 200.0, 50.0)];     

        UILabel *label3 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 140.0, 200.0, 50.0)];     

        UILabel *label4 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 200.0, 200.0, 50.0)];     

        UILabel *label5 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 260.0, 200.0, 50.0)];     

        UILabel *label6 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 320.0, 200.0, 50.0)];     

        UILabel *label7 = [[UILabel alloc]initWithFrame:CGRectMake(50.0, 380.0, 200.0, 50.0)];     

        //设置显示文字     

        label1.text = @"label1";     

        label2.text = @"label2";     

        label3.text = @"label3--label3--label3--label3--label3--label3--label3--label3--label3--label3--label3--";     

        label4.text = @"label4--label4--label4--label4--";     

        label5.text = @"label5--label5--label5--label5--label5--label5--";     

        label6.text = @"label6";     

        label7.text = @"label7";     

        //设置字体:粗体,正常的是 SystemFontOfSize     

        label1.font = [UIFont boldSystemFontOfSize:20];     

        //设置文字颜色  

        label1.textColor = [UIColor orangeColor];     

        label2.textColor = [UIColor purpleColor];     

        //设置文字位置     

        label1.textAlignment = UITextAlignmentRight;     

        label2.textAlignment = UITextAlignmentCenter;     

        //设置字体大小适应label宽度     

        label4.adjustsFontSizeToFitWidth = YES;     

        //设置label的行数     

        label5.numberOfLines = 2;    

        UIlabel.backgroudColor=[UIColor clearColor]; //可以去掉背景色   

        //设置高亮     

        label6.highlighted = YES;     

        label6.highlightedTextColor = [UIColor orangeColor];     

        //设置阴影     

        label7.shadowColor = [UIColor redColor];     

        label7.shadowOffset = CGSizeMake(1.0,1.0);     

        //设置是否能与用户进行交互     

        label7.userInteractionEnabled = YES;     

        //设置label中的文字是否可变,默认值是YES     

        label3.enabled = NO;     

        //设置文字过长时的显示格式     

        label3.lineBreakMode = UILineBreakModeMiddleTruncation;//截去中间     

    //  typedef enum {     

    //      UILineBreakModeWordWrap = 0,     

    //      UILineBreakModeCharacterWrap,     

    //      UILineBreakModeClip,//截去多余部分     

    //      UILineBreakModeHeadTruncation,//截去头部     

    //      UILineBreakModeTailTruncation,//截去尾部     

    //      UILineBreakModeMiddleTruncation,//截去中间     

    //  } UILineBreakMode;     

        //如果adjustsFontSizeToFitWidth属性设置为YES,这个属性就来控制文本基线的行为     

        label4.baselineAdjustment = UIBaselineAdjustmentNone;     

    //  typedef enum {     

    //      UIBaselineAdjustmentAlignBaselines,     

    //      UIBaselineAdjustmentAlignCenters,     

    //      UIBaselineAdjustmentNone,     

    //  } UIBaselineAdjustment;     

        [self.view addSubview:label1];     

        [self.view addSubview:label2];     

        [self.view addSubview:label3];     

        [self.view addSubview:label4];     

        [self.view addSubview:label5];     

        [self.view addSubview:label6];     

        [self.view addSubview:label7];     

        [label1 release];     

        [label2 release];     

        [label3 release];     

        [label4 release];     

        [label5 release];     

        [label6 release];     

        [label7 release];     

        [super viewDidLoad];     

     // Override to allow orientations other than the default portrait orientation.   

     - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {   

     // Return YES for supported orientations   

     return (interfaceOrientation == UIInterfaceOrientationPortrait);   

    - (void)didReceiveMemoryWarning {     

        // Releases the view if it doesn't have a superview.     

        [super didReceiveMemoryWarning];     

        // Release any cached data, images, etc that aren't in use.     

    - (void)viewDidUnload {     

        // Release any retained subviews of the main view.     

        // e.g. self.myOutlet = nil;     

    - (void)dealloc {     

        [super dealloc];     

     UITextField – 文本输入框

    1.UITextField的初始化和设置
    textField = [[UITextField alloc] initWithFrame:CGRectMake(120.0f, 80.0f, 150.0f, 30.0f)];
    [textField setBorderStyle:UITextBorderStyleRoundedRect]; //外框类型

    textField.placeholder = @"password"; //默认显示的字

    textField.secureTextEntry = YES; //密码

    textField.autocorrectionType = UITextAutocorrectionTypeNo;
    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
    textField.returnKeyType = UIReturnKeyDone;
    textField.clearButtonMode = UITextFieldViewModeWhileEditing; //编辑时会出现个修改X

    textField.delegate = self;
    2.要实现的Delegate方法,关闭键盘
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    [self.textField resignFirstResponder];
    return YES;
    }
    3. 可以在UITextField使用下面方法,按return键返回
    -(IBAction) textFieldDone:(id) sender
    {
    [textFieldName resignFirstResponder];
    }
    链接TextField控件的"Did end on exit"
    最右侧加图片是以下代码,
    UIImageView *imgv=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"right.png"]];
    text.rightView=imgv;
    text.rightViewMode = UITextFieldViewModeAlways;

    如果是在最左侧加图片就换成:
    text.leftView=imgv;
    text.leftViewMode = UITextFieldViewModeAlways;
    UITextField 继承自 UIControl,此类中有一个属性contentVerticalAlignment
    所以想让UITextField里面的text垂直居中可以这样写:
    text.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    查看函数的方法:
    按住command键双击进入函数声明
    按住alt键双击进入doc文档
    ///////////////////////////////////////////////////////////////
    文本框常用方法:
    如何用程序删除文本框中选中的文本
    [textView delete: nil];
    ///////////////////////////////////////////////////////////////
    如何限制文本框只能输入数字:
    建立NSNumberFormatter的子类,增加这个方法,将formatter链接至文本框。

    - (BOOL) isPartialStringValid: (NSString **) partialStringPtr
    proposedSelectedRange: (NSRangePointer) proposedSelRangePtr
    originalString: (NSString *) origString
    originalSelectedRange: (NSRange) origSelRange
    errorDescription: (NSString **) error
    {
    NSCharacterSet *nonDigits;
    NSRange newStuff;
    NSString *newStuffString;

    nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
    newStuff = NSMakeRange(origSelRange.location,
    proposedSelRangePtr->location
    - origSelRange.location);
    newStuffString = [*partialStringPtr substringWithRange: newStuff];

    if ([newStuffString rangeOfCharacterFromSet: nonDigits
    options: NSLiteralSearch].location != NSNotFound) {
    *error = @"不是数字";
    return (NO);
    } else {
    *error = nil;
    return (YES);
    }

    }
    ///////////////////////////////////////////////////////////////
    从文本框获取十六进制数据的代码
    char singleNumberString[3] = {'\0','\0','\0'};
    uint32_t singleNumber = 0;
    uint32_t i = 0;
    NSMutableData *data = [NSMutableData data];
    //从文本框获取到得数据
    const char *buf = [[_hexToSendTextField text] UTF8String];
    //转换为十六进制
    for(i = 0; i < strlen(buf); i+=2)
    {
    if(((i+1) < len && isxdigit(buf) && (isxdigit(buf[i+1])))
    {
    singleNumberString[0] = buf;
    singleNumberString[1] = buf[i+1];
    sscanf(singleNumberString, "%x", &singleNumber);
    [data appendBytes:(void*)(&tmp) length:1];
    }
    else
    {
    break;
    }
    }
    //输出
    NSLog(@"%@", data);
    /////////////////////////////////////////////////////////////
    点击 UITextView 输入文字,光标都从最初点开始
    - (void)textViewDidChangeSelection:(UITextView *)textView
    {
    NSRange range;
    range.location = 0;
    range.length = 0;
    textView.selectedRange = range;
    }
    ///////////////////////////////////////////////////////////
    软键盘
    在登录页面要实现用户名和密码,密码要是点点格式,引入当前页面光标要停留在用户名选项,软键盘要弹出界面。如下图:
    弹出键盘:
    [username becomeFirstResponder];
    取消键盘:
    [username resignFirstResponder];
    密码保护:
    password.secureTextEntry=YES;
    //////////////////////////////////////////////////////////////////
    1.UITextField的初始化和设置
    textField = [[UITextField alloc] initWithFrame:CGRectMake(120.0f, 80.0f, 150.0f, 30.0f)];
    [textField setBorderStyle:UITextBorderStyleRoundedRect]; //外框类型
    textField.placeholder = @"password"; //默认显示的字
    textField.secureTextEntry = YES; //密码
    textField.autocorrectionType = UITextAutocorrectionTypeNo;
    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
    textField.returnKeyType = UIReturnKeyDone;
    textField.clearButtonMode = UITextFieldViewModeWhileEditing; //编辑时会出现个修改X
    textField.delegate = self;
    2.要实现的Delegate方法,关闭键盘
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    [self.textField resignFirstResponder];
    return YES;
    }
    3. 可以在UITextField使用下面方法,按return键返回
    -(IBAction) textFieldDone:(id) sender
    {
    [textFieldName resignFirstResponder];
    }
    链接TextField控件的"Did end on exit"
    ////////////////////////////////////////////////////////////////////
    限制输入文本的长度
    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
    if (range.location >= MAX_LENGTH)
    return NO; // return NO to not change text
    return YES;
    }
    if (textField.text.length >= 10 && range.length == 0)
    return NO;
    return YES;
    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
    if ([textField.text length] > MAXLENGTH)
    {
    textField.text = [textField.text substringToIndex:MAXLENGTH-1];
    return NO;
    }
    return YES;
    }
    //////////////////////////////////////////////////////////////////////
    使用UITextFieldDelegate来隐藏键盘
    在iPhone界面上,时常会需要当用户输入完内容后,隐藏键盘。 当然有很多方法,今天只介绍使用UITextFieldDelegate这个协议实现隐藏键盘。
    其实很简单, 需要三步:
    1. 在你的控制器类中,加入UITextFieldDelegate这个协议
    如:@interface AddItemViewController : UIViewController <UITextFieldDelegate>
    2. 在使用了UITextFieldDelegate协议的控制器类的实现中,加入- (BOOL)textFieldShouldReturn:方法。
    - (BOOL)textFieldShouldReturn:(UITextField *)textField {

    [textField resignFirstResponder];
    return YES;
    }
    //设置焦点:

    [UITextField becomeFirstResponder];

    3. 将xib文件中的TextField控件的delegate变量指向到之前使用UITextFieldDelegate协议的那个控制器类,将 TextField的delegate IBOutlet变量右键链接到前面的控制器类的实例上。或者使用代码方式,指定相关TextField的delegate变量。

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    itemNameField.delegate = self;

    priceField.delegate = self;

    }

    (一)4.UIImageView

    UIImageView的常见属性

    @property(nonatomic,retain) UIImage *image;

    显示的图片

    @property(nonatomic,copy) NSArray *animationImages;

    显示的动画图片

    @property(nonatomic) NSTimeInterval animationDuration;

    动画图片的持续时间

    @property(nonatomic) NSInteger animationRepeatCount;

    动画的播放次数(默认是0,代表无限播放)

    UIImageView的常见方法

    - (void)startAnimating; // 开始动画

    - (void)stopAnimating; // 停止动画

    - (BOOL)isAnimating; // 是否正在执行动画

    UIImage

    一个UIImage对象代表一张图片,一般通过imageNamed:方法就可以通过文件名加载项目中的图片

    UIImage *image = [UIImage imageNamed:@"lufy"];

    (一)5.UIScrollvView

    UIScrollView – 滚动的控件

    1.UIScrollView控件是什么?

    (1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限

    (2)当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容

    (3)普通的UIView不具备滚动功能,不能显⽰示过多的内容

    (4)UIScrollView是一个能够滚动的视图控件,可以⽤用来展⽰示⼤大量的内容,并且可以通过滚 动查看所有的内容

     (5)  举例:手机上的“设置”、其他⽰示例程序 

    (1)将需要展⽰的内容添加到UIScrollView中

    (2)设置UIScrollView的contentSize属性,告诉UIScrollView所有内容的尺⼨寸,也就是告诉 它滚动的范围(能滚多远,滚到哪⾥里是尽头) 

    (1)常用属性:

    1)@property(nonatomic)CGPointcontentOffset; 这个属性⽤用来表⽰示UIScrollView滚动的位置

    2)@property(nonatomic)CGSizecontentSize;这个属性⽤用来表⽰示UIScrollView内容的尺⼨寸,滚动范围(能滚多远)

    3)@property(nonatomic)UIEdgeInsetscontentInset; 这个属性能够在UIScrollView的4周增加额外的滚动区域 

    (2)其他属性:

    (2) scrollEnabled = NO

    (3) 没有接收到触摸事件:userInteractionEnabled = NO

    (4)没有取消autolayout功能(要想scrollView滚动,必须取消autolayout) 

    二、关于UIScrollView常见属性的一些说明

    1.属性使用的代码示例

     1 #import "MJViewController.h"
     3 @interface MJViewController ()
     5     //在私有扩展中创建一个属性
     6     UIScrollView *_scrollView;
     8 @end
    10 @implementation MJViewController
    12 - (void)viewDidLoad
    14     [super viewDidLoad];
    16     // 1.创建UIScrollView
    17     UIScrollView *scrollView = [[UIScrollView alloc] init];
    18     scrollView.frame = CGRectMake(0, 0, 250, 250); // frame中的size指UIScrollView的可视范围
    19     scrollView.backgroundColor = [UIColor grayColor];
    20     [self.view addSubview:scrollView];
    22     // 2.创建UIImageView(图片)
    23     UIImageView *imageView = [[UIImageView alloc] init];
    24     imageView.image = [UIImage imageNamed:@"big.jpg"];
    25     CGFloat imgW = imageView.image.size.width; // 图片的宽度
    26     CGFloat imgH = imageView.image.size.height; // 图片的高度
    27     imageView.frame = CGRectMake(0, 0, imgW, imgH);
    28     [scrollView addSubview:imageView];
    30     // 3.设置scrollView的属性
    32     // 设置UIScrollView的滚动范围(内容大小)
    33     scrollView.contentSize = imageView.image.size;
    35     // 隐藏水平滚动条
    36     scrollView.showsHorizontalScrollIndicator = NO;
    37     scrollView.showsVerticalScrollIndicator = NO;
    39     // 用来记录scrollview滚动的位置
    40 //    scrollView.contentOffset = ;
    42     // 去掉弹簧效果
    43 //    scrollView.bounces = NO;
    45     // 增加额外的滚动区域(逆时针,上、左、下、右)
    46     // top  left  bottom  right
    47     scrollView.contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
    49     _scrollView = scrollView;
    52 - (IBAction)down:(UIButton *)sender {
    53     [UIView animateWithDuration:1.0 animations:^{
    54         //三个步骤
    55         CGPoint offset = _scrollView.contentOffset;
    56         offset.y += 150;
    57         _scrollView.contentOffset = offset;
    59         //_scrollView.contentOffset = CGPointMake(0, 0);
    60     }];
    62 @end

    2.几个属性坐标示意图

    3.重要说明

    (1)UIScrollView的frame与contentsize属性的区分:UIScrollView的frame指的是这个scrollview的可视范围(可看见的区域),contentsize是其滚动范围。

    (2)contentinset(不带*号的一般不是结构体就是枚举),为UIScrollView增加额外的滚动区域。(上,左,下,右)逆时针。contentinset可以使用代码或者是视图控制器进行设置,但两者有区别(注意区分)。

    (3)contentsize属性只能使用代码设置。

    (4)contentoffset是个CGpoint类型的结构体,用来记录ScrollView的滚动位置,即记录着“框”跑到了哪里。知道了这个属性,就知道了其位置,可以通过设置这个属性来控制这个“框”的移动。

    (5)不允许直接修改某个对象内部结构体属性的成员,三个步骤(先拿到值,修改之,再把修改后的值赋回去)。

    (6)增加了额外区域后,contentoffset的原点在哪里?

    三、有助于理解的几个截图

    在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似于微信、QQ、新浪微博等软件基本上随处都是UITableView。当然它的广泛使用自然离不开它强大的功能,今天这篇文章将针对UITableView重点展开讨论。今天的主要内容包括:

  • UITableViewCell
  • UITableViewController
  • MVC模式
  • UITableView有两种风格:UITableViewStylePlain和UITableViewStyleGrouped。这两者操作起来其实并没有本质区别,只是后者按分组样式显示前者按照普通样式显示而已。大家先看一下两者的应用:

    1>分组样式

    2>不分组样式

    大家可以看到在UITableView中数据只有行的概念,并没有列的概念,因为在手机操作系统中显示多列是不利于操作的。UITableView中每行数据都是一个UITableViewCell,在这个控件中为了显示更多的信息,iOS已经在其内部设置好了多个子控件以供开发者使用。如果我们查看UITableViewCell的声明文件可以发现在内部有一个UIView控件(contentView,作为其他元素的父控件)、两个UILable控件(textLabel、detailTextLabel)、一个UIImage控件(imageView),分别用于容器、显示内容、详情和图片。使用效果类似于微信、QQ信息列表:

    当然,这些子控件并不一定要全部使用,具体操作时可以通过UITableViewCellStyle进行设置,具体每个枚举表示的意思已经在代码中进行了注释:

    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
        UITableViewCellStyleDefault,    // 左侧显示textLabel(不显示detailTextLabel),imageView可选(显示在最左边)
        UITableViewCellStyleValue1,        // 左侧显示textLabel、右侧显示detailTextLabel(默认蓝色),imageView可选(显示在最左边)
        UITableViewCellStyleValue2,        // 左侧依次显示textLabel(默认蓝色)和detailTextLabel,imageView可选(显示在最左边)
        UITableViewCellStyleSubtitle    // 左上方显示textLabel,左下方显示detailTextLabel(默认灰色),imageView可选(显示在最左边)
    

    由于iOS是遵循MVC模式设计的,很多操作都是通过代理和外界沟通的,但对于数据源控件除了代理还有一个数据源属性,通过它和外界进行数据交互。 对于UITableView设置完dataSource后需要实现UITableViewDataSource协议,在这个协议中定义了多种 数据操作方法,下面通过创建一个简单的联系人管理进行演示:

    首先我们需要创建一个联系人模型KCContact

    KCContact.h

    // Contact.h // UITableView // Created by Kenshin Cui on 14-3-1. #import <Foundation/Foundation.h> @interface KCContact : NSObject #pragma mark 姓 @property (nonatomic,copy) NSString *firstName; #pragma mark 名 @property (nonatomic,copy) NSString *lastName; #pragma mark 手机号码 @property (nonatomic,copy) NSString *phoneNumber; #pragma mark 带参数的构造函数 -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber; #pragma mark 取得姓名 -(NSString *)getName; #pragma mark 带参数的静态对象初始化方法 +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber;

    KCContact.m

    // Contact.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCContact.h" @implementation KCContact -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{ if(self=[super init]){ self.firstName=firstName; self.lastName=lastName; self.phoneNumber=phoneNumber; return self; -(NSString *)getName{ return [NSString stringWithFormat:@"%@ %@",_lastName,_firstName]; +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{ KCContact *contact1=[[KCContact alloc]initWithFirstName:firstName andLastName:lastName andPhoneNumber:phoneNumber]; return contact1;

    为了演示分组显示我们不妨将一组数据也抽象成模型KCContactGroup

    KCContactGroup.h

    // KCContactGroup.h // UITableView // Created by Kenshin Cui on 14-3-1. #import <Foundation/Foundation.h> #import "KCContact.h" @interface KCContactGroup : NSObject #pragma mark 组名 @property (nonatomic,copy) NSString *name; #pragma mark 分组描述 @property (nonatomic,copy) NSString *detail; #pragma mark 联系人 @property (nonatomic,strong) NSMutableArray *contacts; #pragma mark 带参数个构造函数 -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts; #pragma mark 静态初始化方法 +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts;

    KCContactGroup.m

    // KCContactGroup.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCContactGroup.h" @implementation KCContactGroup -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{ if (self=[super init]) { self.name=name; self.detail=detail; self.contacts=contacts; return self; +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{ KCContactGroup *group1=[[KCContactGroup alloc]initWithName:name andDetail:detail andContacts:contacts]; return group1;

    然后在viewDidLoad方法中创建一些模拟数据同时实现数据源协议方法:

    KCMainViewController.m

    // KCMainViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCMainViewController.h" #import "KCContact.h" #import "KCContactGroup.h" @interface KCMainViewController ()<UITableViewDataSource>{ UITableView *_tableView; NSMutableArray *_contacts;//联系人模型 @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //创建一个分组样式的UITableView _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 _tableView.dataSource=self; [self.view addSubview:_tableView]; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark - 数据源方法 #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ NSLog(@"计算分组数"); return _contacts.count; #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSLog(@"计算每组(组%i)行数",section); KCContactGroup *group1=_contacts[section]; return group1.contacts.count; #pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个结构体,记录了组和行信息 NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row); KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; return cell; #pragma mark 返回每组头标题名称 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ NSLog(@"生成组(组%i)名称",section); KCContactGroup *group=_contacts[section]; return group.name; #pragma mark 返回每组尾部说明 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ NSLog(@"生成尾部(组%i)详情",section); KCContactGroup *group=_contacts[section]; return group.detail;

    运行可以看到如下效果:

    大家在使用iPhone通讯录时会发现右侧可以按字母检索,使用起来很方便,其实这个功能使用UITableView实现很简单,只要实现数据源协议的一个方法,构建一个分组标题的数组即可实现。数组元素的内容和组标题内容未必完全一致,UITableView是按照数组元素的索引和每组数据索引顺序来定位的而不是按内容查找。

    #pragma mark 返回每组标题索引
    -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
        NSLog(@"生成组索引");
        NSMutableArray *indexs=[[NSMutableArray alloc]init];
        for(KCContactGroup *group in _contacts){
            [indexs addObject:group.name];
        return indexs;
    

    效果如下:

    需要注意的是上面几个重点方法的执行顺序,请看下图:

    值得指出的是生成单元格的方法并不是一次全部调用,而是只会生产当前显示在界面上的单元格,当用户滚动操作时再显示其他单元格。

    注意:随着我们的应用越来越复杂,可能经常需要调试程序,在iOS中默认情况下不能定位到错误代码行,我们可以通过如下设置让程序定位到出错代码行:Show the Breakpoint  navigator—Add Exception breakpoint。

    上面我们已经看到通讯录的简单实现,但是我们发现单元格高度、分组标题高度以及尾部说明的高度都需要调整,此时就需要使用代理方法。UITableView代理方法有很多,例如监听单元格显示周期、监听单元格选择编辑操作、设置是否高亮显示单元格、设置行高等。

    1.设置行高

    #pragma mark - 代理方法
    #pragma mark 设置分组标题内容高度
    -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
        if(section==0){
            return 50;
        return 40;
    #pragma mark 设置每行高度(每行高度可以不一样)
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return 45;
    #pragma mark 设置尾部说明内容高度
    -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
        return 40;
    

    2.监听点击

    在iOS中点击某联系个人就可以呼叫这个联系人,这时就需要监听点击操作,这里就不演示呼叫联系人操作了,我们演示一下修改人员信息的操作。

    KCMainViewContrller.m

    // KCMainViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCMainViewController.h" #import "KCContact.h" #import "KCContactGroup.h" @interface KCMainViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{ UITableView *_tableView; NSMutableArray *_contacts;//联系人模型 NSIndexPath *_selectedIndexPath;//当前选中的组和行 @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //创建一个分组样式的UITableView _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 _tableView.dataSource=self; //设置代理 _tableView.delegate=self; [self.view addSubview:_tableView]; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark - 数据源方法 #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ NSLog(@"计算分组数"); return _contacts.count; #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSLog(@"计算每组(组%i)行数",section); KCContactGroup *group1=_contacts[section]; return group1.contacts.count; #pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个对象,记录了组和行信息 NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row); KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil]; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; return cell; #pragma mark 返回每组头标题名称 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ NSLog(@"生成组(组%i)名称",section); KCContactGroup *group=_contacts[section]; return group.name; #pragma mark 返回每组尾部说明 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ NSLog(@"生成尾部(组%i)详情",section); KCContactGroup *group=_contacts[section]; return group.detail; #pragma mark 返回每组标题索引 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ NSLog(@"生成组索引"); NSMutableArray *indexs=[[NSMutableArray alloc]init]; for(KCContactGroup *group in _contacts){ [indexs addObject:group.name]; return indexs; #pragma mark - 代理方法 #pragma mark 设置分组标题内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ if(section==0){ return 50; return 40; #pragma mark 设置每行高度(每行高度可以不一样) -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 45; #pragma mark 设置尾部说明内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 40; #pragma mark 点击行 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ _selectedIndexPath=indexPath; KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; //创建弹出窗口 UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"System Info" message:[contact getName] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; alert.alertViewStyle=UIAlertViewStylePlainTextInput; //设置窗口内容样式 UITextField *textField= [alert textFieldAtIndex:0]; //取得文本框 textField.text=contact.phoneNumber; //设置文本框内容 [alert show]; //显示窗口 #pragma mark 窗口的代理方法,用户保存数据 -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ //当点击了第二个按钮(OK) if (buttonIndex==1) { UITextField *textField= [alertView textFieldAtIndex:0]; //修改模型数据 KCContactGroup *group=_contacts[_selectedIndexPath.section]; KCContact *contact=group.contacts[_selectedIndexPath.row]; contact.phoneNumber=textField.text; //刷新表格 [_tableView reloadData]; #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent;

    在上面的代码中我们通过修改模型来改变UI显示,这种方式是经典的MVC应用,在后面的代码中会经常看到。当然UI的刷新使用了UITableView的reloadData方法,该方法会重新调用数据源方法,包括计算分组、计算每个分组的行数,生成单元格等刷新整个UITableView。当然这种方式在实际开发中是不可取的,我们不可能因为修改了一个人的信息就刷新整个UITableViewView,此时我们需要采用局部刷新。局部刷新使用起来很简单,只需要调用UITableView的另外一个方法:

    #pragma mark 窗口的代理方法,用户保存数据
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
        //当点击了第二个按钮(OK)
        if (buttonIndex==1) {
            UITextField *textField= [alertView textFieldAtIndex:0];
            //修改模型数据
            KCContactGroup *group=_contacts[_selectedIndexPath.section];
            KCContact *contact=group.contacts[_selectedIndexPath.row];
            contact.phoneNumber=textField.text;
            //刷新表格
            NSArray *indexPaths=@[_selectedIndexPath];//需要局部刷新的单元格的组、行
            [_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//后面的参数代表更新时的动画
    

    前面已经说过UITableView中的单元格cell是在显示到用户可视区域后创建的,那么如果用户往下滚动就会继续创建显示在屏幕上的单元格,如果用户向上滚动返回到查看过的内容时同样会重新创建之前已经创建过的单元格。如此一来即使UITableView的内容不是太多,如果用户反复的上下滚动,内存也会瞬间飙升,更何况很多时候UITableView的内容是很多的(例如微博展示列表,基本向下滚动是没有底限的)。

    前面一节中我们曾经提到过如何优化UIScrollView,当时就是利用有限的UIImageView动态切换其内容来尽可能减少资源占用。同样的,在UITableView中也可以采用类似的方式,只是这时我们不是在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell重新显示在将要显示的Cell的位置然后更新其内容。原因就是UITableView中的Cell结构布局可能是不同的,通过重新定位是不可取的,而是需要重用已经不再界面显示的已创建过的Cell。

    当然,听起来这么做比较复杂,其实实现起来很简单,因为UITableView已经为我们实现了这种机制。在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。

    #pragma mark返回每行的单元格
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        //NSIndexPath是一个对象,记录了组和行信息
        NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
        KCContactGroup *group=_contacts[indexPath.section];
        KCContact *contact=group.contacts[indexPath.row];
        //由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化
        static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
        //首先根据标识去缓存池取
        UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        //如果缓存池没有到则重新创建并放到缓存池中
        if(!cell){
            cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
        cell.textLabel.text=[contact getName];
        cell.detailTextLabel.text=contact.phoneNumber;
        NSLog(@"cell:%@",cell);
        return cell;
    

    上面的代码中已经打印了cell的地址,如果大家运行测试上下滚动UITableView会发现滚动时创建的cell地址是初始化时已经创建的。

    这里再次给大家强调两点:

  • -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)方法调用很频繁,无论是初始化、上下滚动、刷新都会调用此方法,所有在这里执行的操作一定要注意性能;
  • 可重用标识可以有多个,如果在UITableView中有多类结构不同的Cell,可以通过这个标识进行缓存和重新;
  • UITableViewCell

    1.自带的UITableViewCell

    UITableViewCell是构建一个UITableView的基础,在UITableViewCell内部有一个UIView控件作为其他内容的容器,它上面有一个UIImageView和两个UILabel,通过UITableViewCellStyle属性可以对其样式进行控制。其结构如下:

    有时候我们会发现很多UITableViewCell右侧可以显示不同的图标,在iOS中称之为访问器,点击可以触发不同的事件,例如设置功能:

    要设置这些图标只需要设置UITableViewCell的accesoryType属性,这是一个枚举类型具体含义如下:

    typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
        UITableViewCellAccessoryNone,                   // 不显示任何图标
        UITableViewCellAccessoryDisclosureIndicator,    // 跳转指示图标
        UITableViewCellAccessoryDetailDisclosureButton, // 内容详情图标和跳转指示图标
        UITableViewCellAccessoryCheckmark,              // 勾选图标
        UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) // 内容详情图标
    

    例如在最近通话中我们通常设置为详情图标,点击可以查看联系人详情:

    很明显iOS设置中第一个accessoryType不在枚举之列,右侧的访问器类型是UISwitch控件,那么如何显示自定义的访问器呢?其实只要设置UITableViewCell的accessoryView即可,它支持任何UIView控件。假设我们在通讯录每组第一行放一个UISwitch,同时切换时可以输出对应信息:

    // KCMainViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCMainViewController.h" #import "KCContact.h" #import "KCContactGroup.h" @interface KCMainViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{ UITableView *_tableView; NSMutableArray *_contacts;//联系人模型 NSIndexPath *_selectedIndexPath;//当前选中的组和行 @implementation KCMainViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //创建一个分组样式的UITableView _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 _tableView.dataSource=self; //设置代理 _tableView.delegate=self; [self.view addSubview:_tableView]; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark - 数据源方法 #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ NSLog(@"计算分组数"); return _contacts.count; #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSLog(@"计算每组(组%i)行数",section); KCContactGroup *group1=_contacts[section]; return group1.contacts.count; #pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个对象,记录了组和行信息 NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row); KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; //由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化 static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; static NSString *cellIdentifierForFirstRow=@"UITableViewCellIdentifierKeyWithSwitch"; //首先根据标示去缓存池取 UITableViewCell *cell; if (indexPath.row==0) { cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifierForFirstRow]; }else{ cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有取到则重新创建并放到缓存池中 if(!cell){ if (indexPath.row==0) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFirstRow]; UISwitch *sw=[[UISwitch alloc]init]; [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged]; cell.accessoryView=sw; }else{ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; cell.accessoryType=UITableViewCellAccessoryDetailButton; if(indexPath.row==0){ ((UISwitch *)cell.accessoryView).tag=indexPath.section; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; NSLog(@"cell:%@",cell); return cell; #pragma mark 返回每组头标题名称 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ NSLog(@"生成组(组%i)名称",section); KCContactGroup *group=_contacts[section]; return group.name; #pragma mark 返回每组尾部说明 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ NSLog(@"生成尾部(组%i)详情",section); KCContactGroup *group=_contacts[section]; return group.detail; #pragma mark 返回每组标题索引 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ NSLog(@"生成组索引"); NSMutableArray *indexs=[[NSMutableArray alloc]init]; for(KCContactGroup *group in _contacts){ [indexs addObject:group.name]; return indexs; #pragma mark - 代理方法 #pragma mark 设置分组标题内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ if(section==0){ return 50; return 40; #pragma mark 设置每行高度(每行高度可以不一样) -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 45; #pragma mark 设置尾部说明内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 40; #pragma mark 点击行 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ _selectedIndexPath=indexPath; KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; //创建弹出窗口 UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"System Info" message:[contact getName] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; alert.alertViewStyle=UIAlertViewStylePlainTextInput; //设置窗口内容样式 UITextField *textField= [alert textFieldAtIndex:0]; //取得文本框 textField.text=contact.phoneNumber; //设置文本框内容 [alert show]; //显示窗口 #pragma mark 窗口的代理方法,用户保存数据 -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ //当点击了第二个按钮(OK) if (buttonIndex==1) { UITextField *textField= [alertView textFieldAtIndex:0]; //修改模型数据 KCContactGroup *group=_contacts[_selectedIndexPath.section]; KCContact *contact=group.contacts[_selectedIndexPath.row]; contact.phoneNumber=textField.text; //刷新表格 NSArray *indexPaths=@[_selectedIndexPath];//需要局部刷新的单元格的组、行 [_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//后面的参数代码更新时的动画 #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; #pragma mark 切换开关转化事件 -(void)switchValueChange:(UISwitch *)sw{ NSLog(@"section:%i,switch:%i",sw.tag, sw.on);

    最终运行效果:

  • 由于此时我们需要两种UITableViewCell样式,考虑到性能我们需要在缓存池缓存两种Cell。
  • UISwitch继承于UIControl而不是UIView(当然UIControl最终也是继承于UIView),继承于UIControl的控件使用addTarget添加对应事件而不是代理,同时有“是否可用”、“是否高亮”、“是否选中”等属性;
  • 上面代码中如果有些UITableViewCell的UISwitch设置为on当其他控件重用时状态也是on,解决这个问题可以在模型中设置对应的属性记录其状态,在生成cell时设置当前状态(为了尽可能简化上面的代码这里就不再修复这个问题);
  • 2.自定义UITableViewCell

    虽然系统自带的UITableViewCell已经够强大了,但是很多时候这并不能满足我们的需求。例如新浪微博的Cell就没有那么简单:

    没错,这个界面布局也是UITableView实现的,其中的内容就是UITableViewCell,只是这个UITableViewCell是用户自定义实现的。当然要实现上面的UITableViewCell三言两语我们是说不完的,这里我们实现一个简化版本,界面原型如下:

    我们对具体控件进行拆分:

    在这个界面中有2个UIImageView控件和4个UILabel,整个界面显示效果类似于新浪微博的消息内容界面,但是又在新浪微博基础上进行了精简以至于利用现有知识能够顺利开发出来。

    在前面的内容中我们的数据都是手动构建的,在实际开发中自然不会这么做,这里我们不妨将微博数据存储到plist文件中然后从plist文件读取数据构建模型对象(实际开发微博当然需要进行网络数据请求,这里只是进行模拟就不再演示网络请求的内容)。假设plist文件内容如下:

    接下来就定义一个KCStatusTableViewCell实现UITableViewCell,一般实现自定义UITableViewCell需要分为两步:第一初始化控件;第二设置数据,重新设置控件frame。原因就是自定义Cell一般无法固定高度,很多时候高度需要随着内容改变。此外由于在单元格内部是无法控制单元格高度的,因此一般会定义一个高度属性用于在UITableView的代理事件中设置每个单元格高度。

    1.首先看一下微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:

    KCStatus.h

    // KCStatus.h // UITableView // Created by Kenshin Cui on 14-3-1. #import <Foundation/Foundation.h> @interface KCStatus : NSObject #pragma mark - 属性 @property (nonatomic,assign) long long Id;//微博id @property (nonatomic,copy) NSString *profileImageUrl;//头像 @property (nonatomic,copy) NSString *userName;//发送用户 @property (nonatomic,copy) NSString *mbtype;//会员类型 @property (nonatomic,copy) NSString *createdAt;//创建时间 @property (nonatomic,copy) NSString *source;//设备来源 @property (nonatomic,copy) NSString *text;//微博内容 #pragma mark - 方法 #pragma mark 根据字典初始化微博对象 -(KCStatus *)initWithDictionary:(NSDictionary *)dic; #pragma mark 初始化微博对象(静态方法) +(KCStatus *)statusWithDictionary:(NSDictionary *)dic;

    KCStatus.m

    // KCStatus.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCStatus.h" @implementation KCStatus #pragma mark 根据字典初始化微博对象 -(KCStatus *)initWithDictionary:(NSDictionary *)dic{ if(self=[super init]){ self.Id=[dic[@"Id"] longLongValue]; self.profileImageUrl=dic[@"profileImageUrl"]; self.userName=dic[@"userName"]; self.mbtype=dic[@"mbtype"]; self.createdAt=dic[@"createdAt"]; self.source=dic[@"source"]; self.text=dic[@"text"]; return self; #pragma mark 初始化微博对象(静态方法) +(KCStatus *)statusWithDictionary:(NSDictionary *)dic{ KCStatus *status=[[KCStatus alloc]initWithDictionary:dic]; return status; -(NSString *)source{ return [NSString stringWithFormat:@"来自 %@",_source];

    2.然后看一下自定义的Cell

    KCStatusTableViewCell.h

    // KCStatusTableViewCell.h // UITableView // Created by Kenshin Cui on 14-3-1. #import <UIKit/UIKit.h> @class KCStatus; @interface KCStatusTableViewCell : UITableViewCell #pragma mark 微博对象 @property (nonatomic,strong) KCStatus *status; #pragma mark 单元格高度 @property (assign,nonatomic) CGFloat height;

    KCStatusTableViewCell.m

    // KCStatusTableViewCell.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCStatusTableViewCell.h" #import "KCStatus.h" #define KCColor(r,g,b) [UIColor colorWithHue:r/255.0 saturation:g/255.0 brightness:b/255.0 alpha:1] //颜色宏定义 #define kStatusTableViewCellControlSpacing 10 //控件间距 #define kStatusTableViewCellBackgroundColor KCColor(251,251,251) #define kStatusGrayColor KCColor(50,50,50) #define kStatusLightGrayColor KCColor(120,120,120) #define kStatusTableViewCellAvatarWidth 40 //头像宽度 #define kStatusTableViewCellAvatarHeight kStatusTableViewCellAvatarWidth #define kStatusTableViewCellUserNameFontSize 14 #define kStatusTableViewCellMbTypeWidth 13 //会员图标宽度 #define kStatusTableViewCellMbTypeHeight kStatusTableViewCellMbTypeWidth #define kStatusTableViewCellCreateAtFontSize 12 #define kStatusTableViewCellSourceFontSize 12 #define kStatusTableViewCellTextFontSize 14 @interface KCStatusTableViewCell(){ UIImageView *_avatar;//头像 UIImageView *_mbType;//会员类型 UILabel *_userName; UILabel *_createAt; UILabel *_source; UILabel *_text; @implementation KCStatusTableViewCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self initSubView]; return self; #pragma mark 初始化视图 -(void)initSubView{ //头像控件 _avatar=[[UIImageView alloc]init]; [self.contentView addSubview:_avatar]; //用户名 _userName=[[UILabel alloc]init]; _userName.textColor=kStatusGrayColor; _userName.font=[UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]; [self.contentView addSubview:_userName]; //会员类型 _mbType=[[UIImageView alloc]init]; [self.contentView addSubview:_mbType]; _createAt=[[UILabel alloc]init]; _createAt.textColor=kStatusLightGrayColor; _createAt.font=[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]; [self.contentView addSubview:_createAt]; _source=[[UILabel alloc]init]; _source.textColor=kStatusLightGrayColor; _source.font=[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]; [self.contentView addSubview:_source]; _text=[[UILabel alloc]init]; _text.textColor=kStatusGrayColor; _text.font=[UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]; _text.numberOfLines=0; // _text.lineBreakMode=NSLineBreakByWordWrapping; [self.contentView addSubview:_text]; #pragma mark 设置微博 -(void)setStatus:(KCStatus *)status{ //设置头像大小和位置 CGFloat avatarX=10,avatarY=10; CGRect avatarRect=CGRectMake(avatarX, avatarY, kStatusTableViewCellAvatarWidth, kStatusTableViewCellAvatarHeight); _avatar.image=[UIImage imageNamed:status.profileImageUrl]; _avatar.frame=avatarRect; //设置会员图标大小和位置 CGFloat userNameX= CGRectGetMaxX(_avatar.frame)+kStatusTableViewCellControlSpacing ; CGFloat userNameY=avatarY; //根据文本内容取得文本占用空间大小 CGSize userNameSize=[status.userName sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]}]; CGRect userNameRect=CGRectMake(userNameX, userNameY, userNameSize.width,userNameSize.height); _userName.text=status.userName; _userName.frame=userNameRect; //设置会员图标大小和位置 CGFloat mbTypeX=CGRectGetMaxX(_userName.frame)+kStatusTableViewCellControlSpacing; CGFloat mbTypeY=avatarY; CGRect mbTypeRect=CGRectMake(mbTypeX, mbTypeY, kStatusTableViewCellMbTypeWidth, kStatusTableViewCellMbTypeHeight); _mbType.image=[UIImage imageNamed:status.mbtype]; _mbType.frame=mbTypeRect; //设置发布日期大小和位置 CGSize createAtSize=[status.createdAt sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]}]; CGFloat createAtX=userNameX; CGFloat createAtY=CGRectGetMaxY(_avatar.frame)-createAtSize.height; CGRect createAtRect=CGRectMake(createAtX, createAtY, createAtSize.width, createAtSize.height); _createAt.text=status.createdAt; _createAt.frame=createAtRect; //设置设备信息大小和位置 CGSize sourceSize=[status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]}]; CGFloat sourceX=CGRectGetMaxX(_createAt.frame)+kStatusTableViewCellControlSpacing; CGFloat sourceY=createAtY; CGRect sourceRect=CGRectMake(sourceX, sourceY, sourceSize.width,sourceSize.height); _source.text=status.source; _source.frame=sourceRect; //设置微博内容大小和位置 CGFloat textX=avatarX; CGFloat textY=CGRectGetMaxY(_avatar.frame)+kStatusTableViewCellControlSpacing; CGFloat textWidth=self.frame.size.width-kStatusTableViewCellControlSpacing*2; CGSize textSize=[status.text boundingRectWithSize:CGSizeMake(textWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]} context:nil].size; CGRect textRect=CGRectMake(textX, textY, textSize.width, textSize.height); _text.text=status.text; _text.frame=textRect; _height=CGRectGetMaxY(_text.frame)+kStatusTableViewCellControlSpacing; #pragma mark 重写选择事件,取消选中 -(void)setSelected:(BOOL)selected animated:(BOOL)animated{

    这是我们自定义Cell这个例子的核心,自定义Cell分为两个步骤:首先要进行各种控件的初始化工作,这个过程中只要将控件放到Cell的View中同时设置控件显示内容的格式(字体大小、颜色等)即可;然后在数据对象设置方法中进行各个控件的布局(大小、位置)。在代码中有几点需要重点提示大家:

  • 对于单行文本数据的显示调用- (CGSize)sizeWithAttributes:(NSDictionary *)attrs;方法来得到文本宽度和高度。
  • 对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;方法来得到文本宽度和高度;同时注意在此之前需要设置文本控件的numberOfLines属性为0。
  • 通常我们会在自定义Cell中设置一个高度属性,用于外界方法调用,因为Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会重新设置高度。
  • 3.最后我们看一下自定义Cell的使用过程:

    KCStatusViewController.m

    // KCCutomCellViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCStatusCellViewController.h" #import "KCStatus.h" #import "KCStatusTableViewCell.h" @interface KCStatusCellViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{ UITableView *_tableView; NSMutableArray *_status; NSMutableArray *_statusCells;//存储cell,用于计算高度 @implementation KCStatusCellViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //创建一个分组样式的UITableView _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 _tableView.dataSource=self; //设置代理 _tableView.delegate=self; [self.view addSubview:_tableView]; #pragma mark 加载数据 -(void)initData{ NSString *path=[[NSBundle mainBundle] pathForResource:@"StatusInfo" ofType:@"plist"]; NSArray *array=[NSArray arrayWithContentsOfFile:path]; _status=[[NSMutableArray alloc]init]; _statusCells=[[NSMutableArray alloc]init]; [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [_status addObject:[KCStatus statusWithDictionary:obj]]; KCStatusTableViewCell *cell=[[KCStatusTableViewCell alloc]init]; [_statusCells addObject:cell]; #pragma mark - 数据源方法 #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return _status.count; #pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; KCStatusTableViewCell *cell; cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if(!cell){ cell=[[KCStatusTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; //在此设置微博,以便重新布局 KCStatus *status=_status[indexPath.row]; cell.status=status; return cell; #pragma mark - 代理方法 #pragma mark 重新设置单元格高度 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ //KCStatusTableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath]; KCStatusTableViewCell *cell= _statusCells[indexPath.row]; cell.status=_status[indexPath.row]; return cell.height; #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent;

    这个类中需要重点强调一下:Cell的高度需要重新设置(前面说过无论Cell内部设置多高都没有用,需要重新设置),这里采用的方法是首先创建对应的Cell,然后在- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;方法中设置微博数据计算高度通知UITableView。

    最后我们看一下运行的效果:

    UITableView和UITableViewCell提供了强大的操作功能,这一节中会重点讨论删除、增加、排序等操作。为了方便演示我们还是在之前的通讯录的基础上演示,在此之前先来给视图控制器添加一个工具条,在工具条左侧放一个删除按钮,右侧放一个添加按钮:

    #pragma mark 添加工具栏
    -(void)addToolbar{
        CGRect frame=self.view.frame;
        _toolbar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, kContactToolbarHeight)];
        //    _toolbar.backgroundColor=[UIColor colorWithHue:246/255.0 saturation:246/255.0 brightness:246/255.0 alpha:1];
        [self.view addSubview:_toolbar];
        UIBarButtonItem *removeButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(remove)];
        UIBarButtonItem *flexibleButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
        UIBarButtonItem *addButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)];
        NSArray *buttonArray=[NSArray arrayWithObjects:removeButton,flexibleButton,addButton, nil];
        _toolbar.items=buttonArray;
    

    在UITableView中无论是删除操作还是添加操作都是通过修改UITableView的编辑状态来改变的(除非你不用UITableView自带的删除功能)。在删除按钮中我们设置UITableView的编辑状态:

    #pragma mark 删除
    -(void)remove{
        //直接通过下面的方法设置编辑状态没有动画
        //_tableView.editing=!_tableView.isEditing;
        [_tableView setEditing:!_tableView.isEditing animated:true];
    

    点击删除按钮会在Cell的左侧显示删除按钮:

    此时点击左侧删除图标右侧出现删除:

    用过iOS的朋友都知道,一般这种Cell如果向左滑动右侧就会出现删除按钮直接删除就可以了。其实实现这个功能只要实现代理-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;方法,只要实现了此方法向左滑动就会显示删除按钮。只要点击删除按钮这个方法就会调用,但是需要注意的是无论是删除还是添加都是执行这个方法,只是第二个参数类型不同。下面看一下具体的删除实现:

    #pragma mark 删除操作
    //实现了此方法向左滑动就会显示删除按钮
    -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
        KCContactGroup *group =_contacts[indexPath.section];
        KCContact *contact=group.contacts[indexPath.row];
        if (editingStyle==UITableViewCellEditingStyleDelete) {
            [group.contacts removeObject:contact];
            //考虑到性能这里不建议使用reloadData
            //[tableView reloadData];
            //使用下面的方法既可以局部刷新又有动画效果
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
            //如果当前组中没有数据则移除组刷新整个表格
            if (group.contacts.count==0) {
                [_contacts removeObject:group];
                [tableView reloadData];
    

    从这段代码我们再次看到了MVC的思想,要修改UI先修改数据。而且我们看到了另一个刷新表格的方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;,使用这个方法可以再删除之后刷新对应的单元格。效果如下:

    添加和删除操作都是设置UITableView的编辑状态,具体是添加还是删除需要根据代理方法-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;的返回值来确定。因此这里我们定义一个变量来记录点击了哪个按钮,根据点击按钮的不同在这个方法中返回不同的值。

    #pragma mark 取得当前操作状态,根据不同的状态左侧出现不同的操作按钮
    -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
        if (_isInsert) {
            return UITableViewCellEditingStyleInsert;
        return UITableViewCellEditingStyleDelete;
    }
    #pragma mark 编辑操作(删除或添加) //实现了此方法向左滑动就会显示删除(或添加)图标 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ KCContactGroup *group =_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; if (editingStyle==UITableViewCellEditingStyleDelete) { [group.contacts removeObject:contact]; //考虑到性能这里不建议使用reloadData //[tableView reloadData]; //使用下面的方法既可以局部刷新又有动画效果 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; //如果当前组中没有数据则移除组刷新整个表格 if (group.contacts.count==0) { [_contacts removeObject:group]; [tableView reloadData]; }else if(editingStyle==UITableViewCellEditingStyleInsert){ KCContact *newContact=[[KCContact alloc]init]; newContact.firstName=@"first"; newContact.lastName=@"last"; newContact.phoneNumber=@"12345678901"; [group.contacts insertObject:newContact atIndex:indexPath.row]; [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];//注意这里没有使用reladData刷新

    运行效果:

    只要实现-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;代理方法当UITableView处于编辑状态时就可以排序。

    #pragma mark 排序
    //只要实现这个方法在编辑状态右侧就有排序图标
    -(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
        KCContactGroup *sourceGroup =_contacts[sourceIndexPath.section];
        KCContact *sourceContact=sourceGroup.contacts[sourceIndexPath.row];
        KCContactGroup *destinationGroup =_contacts[destinationIndexPath.section];
        [sourceGroup.contacts removeObject:sourceContact];
        if(sourceGroup.contacts.count==0){
            [_contacts removeObject:sourceGroup];
            [tableView reloadData];
        [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row];
    

    运行效果:

    最后给大家附上上面几种操作的完整代码:

    // KCContactViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCContactViewController.h" #import "KCContact.h" #import "KCContactGroup.h" #define kContactToolbarHeight 44 @interface KCContactViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{ UITableView *_tableView; UIToolbar *_toolbar; NSMutableArray *_contacts;//联系人模型 NSIndexPath *_selectedIndexPath;//当前选中的组和行 BOOL _isInsert;//记录是点击了插入还是删除按钮 @implementation KCContactViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //创建一个分组样式的UITableView _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; _tableView.contentInset=UIEdgeInsetsMake(kContactToolbarHeight, 0, 0, 0); [self.view addSubview:_tableView]; //添加工具栏 [self addToolbar]; //设置数据源,注意必须实现对应的UITableViewDataSource协议 _tableView.dataSource=self; //设置代理 _tableView.delegate=self; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark 添加工具栏 -(void)addToolbar{ CGRect frame=self.view.frame; _toolbar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, kContactToolbarHeight)]; // _toolbar.backgroundColor=[UIColor colorWithHue:246/255.0 saturation:246/255.0 brightness:246/255.0 alpha:1]; [self.view addSubview:_toolbar]; UIBarButtonItem *removeButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(remove)]; UIBarButtonItem *flexibleButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIBarButtonItem *addButton=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)]; NSArray *buttonArray=[NSArray arrayWithObjects:removeButton,flexibleButton,addButton, nil]; _toolbar.items=buttonArray; #pragma mark 删除 -(void)remove{ //直接通过下面的方法设置编辑状态没有动画 //_tableView.editing=!_tableView.isEditing; _isInsert=false; [_tableView setEditing:!_tableView.isEditing animated:true]; #pragma mark 添加 -(void)add{ _isInsert=true; [_tableView setEditing:!_tableView.isEditing animated:true]; #pragma mark - 数据源方法 #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return _contacts.count; #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ KCContactGroup *group1=_contacts[section]; return group1.contacts.count; #pragma mark返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一个对象,记录了组和行信息 KCContactGroup *group=_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; //首先根据标识去缓存池取 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有取到则重新创建并放到缓存池中 if(!cell){ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; return cell; #pragma mark - 代理方法 #pragma mark 设置分组标题 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ KCContactGroup *group=_contacts[section]; return group.name; #pragma mark 编辑操作(删除或添加) //实现了此方法向左滑动就会显示删除(或添加)图标 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ KCContactGroup *group =_contacts[indexPath.section]; KCContact *contact=group.contacts[indexPath.row]; if (editingStyle==UITableViewCellEditingStyleDelete) { [group.contacts removeObject:contact]; //考虑到性能这里不建议使用reloadData //[tableView reloadData]; //使用下面的方法既可以局部刷新又有动画效果 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; //如果当前组中没有数据则移除组刷新整个表格 if (group.contacts.count==0) { [_contacts removeObject:group]; [tableView reloadData]; }else if(editingStyle==UITableViewCellEditingStyleInsert){ KCContact *newContact=[[KCContact alloc]init]; newContact.firstName=@"first"; newContact.lastName=@"last"; newContact.phoneNumber=@"12345678901"; [group.contacts insertObject:newContact atIndex:indexPath.row]; [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];//注意这里没有使用reladData刷新 #pragma mark 排序 //只要实现这个方法在编辑状态右侧就有排序图标 -(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{ KCContactGroup *sourceGroup =_contacts[sourceIndexPath.section]; KCContact *sourceContact=sourceGroup.contacts[sourceIndexPath.row]; KCContactGroup *destinationGroup =_contacts[destinationIndexPath.section]; [sourceGroup.contacts removeObject:sourceContact]; [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row]; if(sourceGroup.contacts.count==0){ [_contacts removeObject:sourceGroup]; [tableView reloadData]; #pragma mark 取得当前操作状态,根据不同的状态左侧出现不同的操作按钮 -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{ if (_isInsert) { return UITableViewCellEditingStyleInsert; return UITableViewCellEditingStyleDelete; #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent;

    通过前面的演示这里简单总结一些UITableView的刷新方法:

    - (void)reloadData;刷新整个表格。

    - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);刷新指定的分组和行。

    - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);刷新指定的分组。

    - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;删除时刷新指定的行数据。

    - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;添加时刷新指定的行数据。

    UITableViewController

    很多时候一个UIViewController中只有一个UITableView,因此苹果官方为了方便大家开发直接提供了一个UITableViewController,这个控制器 UITableViewController实现了UITableView数据源和代理协议,内部定义了一个tableView属性供外部访问,同时自动铺满整个屏幕、自动伸缩以方便我们的开发。当然UITableViewController也并不是简单的帮我们定义完UITableView并且设置了数据源、代理而已,它还有其他强大的功能,例如刷新控件、滚动过程中固定分组标题等。

    有时候一个表格中的数据特别多,检索起来就显得麻烦,这个时候可以实现一个搜索功能帮助用户查找数据,其实搜索的原理很简单:修改模型、刷新表格。下面使用UITableViewController简单演示一下这个功能:

    // KCContactTableViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCContactTableViewController.h" #import "KCContact.h" #import "KCContactGroup.h" #define kSearchbarHeight 44 @interface KCContactTableViewController ()<UISearchBarDelegate>{ UITableView *_tableView; UISearchBar *_searchBar; //UISearchDisplayController *_searchDisplayController; NSMutableArray *_contacts;//联系人模型 NSMutableArray *_searchContacts;//符合条件的搜索联系人 BOOL _isSearching; @implementation KCContactTableViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //添加搜索框 [self addSearchBar]; #pragma mark - 数据源方法 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if (_isSearching) { return 1; return _contacts.count;; - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (_isSearching) { return _searchContacts.count; KCContactGroup *group1=_contacts[section]; return group1.contacts.count; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { KCContact *contact=nil; if (_isSearching) { contact=_searchContacts[indexPath.row]; }else{ KCContactGroup *group=_contacts[indexPath.section]; contact=group.contacts[indexPath.row]; static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; //首先根据标识去缓存池取 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有取到则重新创建并放到缓存池中 if(!cell){ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; return cell; #pragma mark - 代理方法 #pragma mark 设置分组标题 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ KCContactGroup *group=_contacts[section]; return group.name; #pragma mark - 搜索框代理 #pragma mark 取消搜索 -(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{ _isSearching=NO; _searchBar.text=@""; [self.tableView reloadData]; #pragma mark 输入搜索关键字 -(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ if([_searchBar.text isEqual:@""]){ _isSearching=NO; [self.tableView reloadData]; return; [self searchDataWithKeyWord:_searchBar.text]; #pragma mark 点击虚拟键盘上的搜索时 -(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ [self searchDataWithKeyWord:_searchBar.text]; [_searchBar resignFirstResponder];//放弃第一响应者对象,关闭虚拟键盘 #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark 搜索形成新数据 -(void)searchDataWithKeyWord:(NSString *)keyWord{ _isSearching=YES; _searchContacts=[NSMutableArray array]; [_contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { KCContactGroup *group=obj; [group.contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { KCContact *contact=obj; if ([contact.firstName.uppercaseString containsString:keyWord.uppercaseString]||[contact.lastName.uppercaseString containsString:keyWord.uppercaseString]||[contact.phoneNumber containsString:keyWord]) { [_searchContacts addObject:contact]; //刷新表格 [self.tableView reloadData]; #pragma mark 添加搜索栏 -(void)addSearchBar{ CGRect searchBarRect=CGRectMake(0, 0, self.view.frame.size.width, kSearchbarHeight); _searchBar=[[UISearchBar alloc]initWithFrame:searchBarRect]; _searchBar.placeholder=@"Please input key word..."; //_searchBar.keyboardType=UIKeyboardTypeAlphabet;//键盘类型 //_searchBar.autocorrectionType=UITextAutocorrectionTypeNo;//自动纠错类型 //_searchBar.autocapitalizationType=UITextAutocapitalizationTypeNone;//哪一次shitf被自动按下 _searchBar.showsCancelButton=YES;//显示取消按钮 //添加搜索框到页眉位置 _searchBar.delegate=self; self.tableView.tableHeaderView=_searchBar;

    运行效果:

    在上面的搜索中除了使用一个_contacts变量去保存联系人数据还专门定义了一个_searchContact变量用于保存搜索的结果。在输入搜索关键字时我们刷新了表格,此时会调用表格的数据源方法,在这个方法中我们根据定义的搜索状态去决定显示原始数据还是搜索结果。

    我们发现每次搜索完后都需要手动刷新表格来显示搜索结果,而且当没有搜索关键字的时候还需要将当前的tableView重新设置为初始状态。也就是这个过程中我们要用一个tableView显示两种状态的不同数据,自然会提高程序逻辑复杂度。为了简化这个过程,我们可以使用UISearchDisplayController,UISearchDisplayController内部也有一个UITableView类型的对象searchResultsTableView,如果我们设置它的数据源代理为当前控制器,那么它完全可以像UITableView一样加载数据。同时它本身也有搜索监听的方法,我们不必在监听UISearchBar输入内容,直接使用它的方法即可自动刷新其内部表格。为了和前面的方法对比在下面的代码中没有直接删除原来的方式而是注释了对应代码大家可以对照学习:

    // KCContactTableViewController.m // UITableView // Created by Kenshin Cui on 14-3-1. #import "KCContactTableViewControllerWithUISearchDisplayController.h" #import "KCContact.h" #import "KCContactGroup.h" #define kSearchbarHeight 44 @interface KCContactTableViewControllerWithUISearchDisplayController ()<UISearchBarDelegate,UISearchDisplayDelegate>{ UITableView *_tableView; UISearchBar *_searchBar; UISearchDisplayController *_searchDisplayController; NSMutableArray *_contacts;//联系人模型 NSMutableArray *_searchContacts;//符合条件的搜索联系人 //BOOL _isSearching; @implementation KCContactTableViewControllerWithUISearchDisplayController - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //添加搜索框 [self addSearchBar]; #pragma mark - 数据源方法 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // if (_isSearching) { // return 1; // } //如果当前是UISearchDisplayController内部的tableView则不分组 if (tableView==self.searchDisplayController.searchResultsTableView) { return 1; return _contacts.count;; - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // if (_isSearching) { // return _searchContacts.count; // } //如果当前是UISearchDisplayController内部的tableView则使用搜索数据 if (tableView==self.searchDisplayController.searchResultsTableView) { return _searchContacts.count; KCContactGroup *group1=_contacts[section]; return group1.contacts.count; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { KCContact *contact=nil; // if (_isSearching) { // contact=_searchContacts[indexPath.row]; // }else{ // KCContactGroup *group=_contacts[indexPath.section]; // contact=group.contacts[indexPath.row]; // } //如果当前是UISearchDisplayController内部的tableView则使用搜索数据 if (tableView==self.searchDisplayController.searchResultsTableView) { contact=_searchContacts[indexPath.row]; }else{ KCContactGroup *group=_contacts[indexPath.section]; contact=group.contacts[indexPath.row]; static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1"; //首先根据标识去缓存池取 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //如果缓存池没有取到则重新创建并放到缓存池中 if(!cell){ cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; cell.textLabel.text=[contact getName]; cell.detailTextLabel.text=contact.phoneNumber; return cell; #pragma mark - 代理方法 #pragma mark 设置分组标题 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ if (tableView==self.searchDisplayController.searchResultsTableView) { return @"搜索结果"; KCContactGroup *group=_contacts[section]; return group.name; #pragma mark 选中之前 -(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [_searchBar resignFirstResponder];//退出键盘 return indexPath; #pragma mark - 搜索框代理 //#pragma mark 取消搜索 //-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{ // //_isSearching=NO; // _searchBar.text=@""; // //[self.tableView reloadData]; // [_searchBar resignFirstResponder]; //#pragma mark 输入搜索关键字 //-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ // if([_searchBar.text isEqual:@""]){ // //_isSearching=NO; // //[self.tableView reloadData]; // return; // } // [self searchDataWithKeyWord:_searchBar.text]; //#pragma mark 点击虚拟键盘上的搜索时 //-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ // [self searchDataWithKeyWord:_searchBar.text]; // [_searchBar resignFirstResponder];//放弃第一响应者对象,关闭虚拟键盘 #pragma mark - UISearchDisplayController代理方法 -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{ [self searchDataWithKeyWord:searchString]; return YES; #pragma mark 重写状态样式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; #pragma mark 加载数据 -(void)initData{ _contacts=[[NSMutableArray alloc]init]; KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"]; KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"]; KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C" andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]]; [_contacts addObject:group1]; KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"]; KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"]; KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"]; KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L" andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]]; [_contacts addObject:group2]; KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"]; KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"]; KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S" andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]]; [_contacts addObject:group3]; KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"]; KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"]; KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"]; KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"]; KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"]; KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W" andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]]; [_contacts addObject:group4]; KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"]; KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"]; KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"]; KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z" andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]]; [_contacts addObject:group5]; #pragma mark 搜索形成新数据 -(void)searchDataWithKeyWord:(NSString *)keyWord{ //_isSearching=YES; _searchContacts=[NSMutableArray array]; [_contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { KCContactGroup *group=obj; [group.contacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { KCContact *contact=obj; if ([contact.firstName.uppercaseString containsString:keyWord.uppercaseString]||[contact.lastName.uppercaseString containsString:keyWord.uppercaseString]||[contact.phoneNumber containsString:keyWord]) { [_searchContacts addObject:contact]; //刷新表格 //[self.tableView reloadData]; #pragma mark 添加搜索栏 -(void)addSearchBar{ _searchBar=[[UISearchBar alloc]init]; [_searchBar sizeToFit];//大小自适应容器 _searchBar.placeholder=@"Please input key word..."; _searchBar.autocapitalizationType=UITextAutocapitalizationTypeNone; _searchBar.showsCancelButton=YES;//显示取消按钮 //添加搜索框到页眉位置 _searchBar.delegate=self; self.tableView.tableHeaderView=_searchBar; _searchDisplayController=[[UISearchDisplayController alloc]initWithSearchBar:_searchBar contentsController:self]; _searchDisplayController.delegate=self; _searchDisplayController.searchResultsDataSource=self; _searchDisplayController.searchResultsDelegate=self; [_searchDisplayController setActive:NO animated:YES];

    运行效果:

    注意如果使用Storyboard或xib方式创建上述代码则无需定义UISearchDisplayController成员变量,因为每个UIViewController中已经有一个searchDisplayController对象。

    MVC模式

    通过UITableView的学习相信大家对于iOS的MVC已经有一个大致的了解,这里简单的分析一下iOS中MVC模式的设计方式。在iOS中多数数据源视图控件(View)都有一个dataSource属性用于和控制器(Controller)交互,而数据来源我们一般会以数据模型(Model)的形式进行定义,View不直接和模型交互,而是通过Controller间接读取数据。

    就拿前面的联系人应用举例,UITableView作为视图(View)并不能直接访问模型Contact,它要显示联系人信息只能通过控制器(Controller)来提供数据源方法。同样的控制器本身就拥有视图控件,可以操作视图,也就是说视图和控制器之间可以互相访问。而模型既不能访问视图也不能访问控制器。具体依赖关系如下图:

     (一)UICollevtionView
    (一)8.UIWebView

    UIWebView是iOS sdk中一个最常用的控件。是内置的浏览器控件,我们可以用它来浏览网页、打开文档等等。这篇文章我将使用这个控件,做一个简易的浏览器。如下图:

    我们创建一个Window-based Application程序命名为:UIWebViewDemo

    UIWebView的loadRequest可以用来加载一个url地址,它需要一个NSURLRequest参数。我们定义一个方法用来加载url。在UIWebViewDemoViewController中定义下面方法:

    - (void)loadWebPageWithString:(NSString*)urlString
    {
    NSURL *url =[NSURL URLWithString:urlString];
    NSLog(urlString);
    NSURLRequest *request =[NSURLRequest requestWithURL:url];
    [webView loadRequest:request];
    }

    在界面上放置3个控件,一个textfield、一个button、一个uiwebview,布局如下:

    在代码中定义相关的控件:webView用于展示网页、textField用于地址栏、activityIndicatorView用于加载的动画、buttonPress用于按钮的点击事件。

    @interface UIWebViewDemoViewController :UIViewController<UIWebViewDelegate> {   
        IBOutlet UIWebView *webView;
        IBOutlet UITextField *textField;
        UIActivityIndicatorView *activityIndicatorView;
    - (IBAction)buttonPress:(id) sender;
    - (void)loadWebPageWithString:(NSString*)urlString;
    - (void)viewDidLoad
    {
    [super viewDidLoad];
    webView.scalesPageToFit =YES;
    webView.delegate =self;
    activityIndicatorView = [[UIActivityIndicatorView alloc]
    initWithFrame : CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)] ;
    [activityIndicatorView setCenter: self.view.center] ;
    [activityIndicatorView setActivityIndicatorViewStyle: UIActivityIndicatorViewStyleWhite] ;
    [self.view addSubview : activityIndicatorView] ;
    [self buttonPress:nil];
    // Do any additional setup after loading the view from its nib.
    }

    UIWebView主要有下面几个委托方法:

    1、- (void)webViewDidStartLoad:(UIWebView *)webView;开始加载的时候执行该方法。
    2、- (void)webViewDidFinishLoad:(UIWebView *)webView;加载完成的时候执行该方法。
    3、- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;加载出错的时候执行该方法。

    我们可以将activityIndicatorView放置到前面两个委托方法中。

    - (void)webViewDidStartLoad:(UIWebView *)webView
    {
    [activityIndicatorView startAnimating] ;
    }
    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
    [activityIndicatorView stopAnimating];
    }

    buttonPress方法很简单,调用我们开始定义好的loadWebPageWithString方法就行了:

    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
        UIAlertView *alterview = [[UIAlertView alloc] initWithTitle:@"" message:[error localizedDescription]  delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
        [alterview show];
        [alterview release];
    1 UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"Test"    //标题
    2                                               message:@"this is a alert view "   //显示内容
    3                                              delegate:nil          //委托,可以点击事件进行处理
    4                                     cancelButtonTitle:@"取消"
    5                                     otherButtonTitles:@"确定"
    6                                                     //,@"其他",    //添加其他按钮  
    7                                  nil];
    8 [view show];

    2.多个按钮  

    取消上面代码@“其他”的注释后,运行效果如下

    可以以此类推,添加多个

    3.一些系统样式参数

    UIAlertViewStyle这个枚举提供了几个样式

    1 typedef NS_ENUM(NSInteger, UIAlertViewStyle) {
    2     UIAlertViewStyleDefault = 0,            //缺省样式
    3     UIAlertViewStyleSecureTextInput,         //密文输入框
    4     UIAlertViewStylePlainTextInput,          //明文输入框
    5     UIAlertViewStyleLoginAndPasswordInput      //登录用输入框,有明文用户名,和密文密码输入二个输入框
    

    使用代码如下:

    1     UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"请等待"    //标题
    2                                                   message:@"this is a alert view "   //显示内容
    3                                                  delegate:nil                //委托,可以点击事件进行处理
    4                                         cancelButtonTitle:@"取消"
    5                                         otherButtonTitles:@"确定",
    6                                                     //,@"其他",    //添加其他按钮
    7                          nil];
    8 [view setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];   //控制样式

    这是参数为:UIAlertViewStyleLoginAndPasswordInput  效果图,其他的自行查看

    不过这几个类型,我个人觉得太丑了,不能接受,便自定义了个弹出框,用来接受输入

    实现也不难,有需要的朋友可以联系我

    4.判断用户点了哪个按钮

    UIAlertView的委托UIAlertViewDelegate ,实现该委托来实现点击事件,如下:

    1 @interface ViewController : UIViewController<UIAlertViewDelegate> {
    

    在.m实现委托的方法

    1 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    3     NSString* msg = [[NSString alloc] initWithFormat:@"您按下的第%d个按钮!",buttonIndex];
    4     NSLog(@"%@",msg);
    

    在这个方法中的参数 buttonIndex,表示的是按钮的索引,上图的三按键 “取消”,“确定”,“其他”对应的索引分别为“0”,“1”,“2”.

    用Delegate的方式处理点击时候,会带来一个问题比较麻烦,比如在一个页面里,有好几个UIAlertView的时候,处理点击的时候,会增加处理逻辑的复杂度,得做一些判断

    这种情况有一个解决办法,就是用Block,添加Block的回调,代替Delegate,target和selector.(下次展开写这个内容)

    5.添加子视图

    这个用得也是比较多的,贴几个使用实例

    添加 UIActivityIndicatorView

    实现代码:

     1     UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"请等待"
     2                                                   message:nil
     3                                                  delegate:nil                
     4                                         cancelButtonTitle:nil
     5                                         otherButtonTitles:nil,
     6                                                           nil];
     7     [view show];
     8     UIActivityIndicatorView *activeView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
     9     activeView.center = CGPointMake(view.bounds.size.width/2.0f, view.bounds.size.height-40.0f);
    10     [activeView startAnimating];
    11     [view addSubview:activeView];
    13     //[view show];

    添加UITableView

    这个列表的几行代码也说不清楚,就说下思路吧,UIAlertView之所以有这么大的空间显示UITableView,用了比较取巧的一个办法

    1 UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"请选择"
    2                                             message:@"\n\n\n\n\n\n\n\n\n\n"
    3                                                 delegate:nil                
    4                                        cancelButtonTitle:nil      
    5                                                  otherButtonTitles:nil,
    6                                                            nil];          
    7  //其中用了10个换行符来撑大UIAlertView的

    然后再来添加UITableView,可以自行实现,如果有需要,请留言

    基本上这是一些比较常用且实用的东西了,然后还有一个比较重要的东西,就是自定义和美化UIAlertView,相信很多人关心这个,自定义和美化的内容放在下一篇来细说,分析几个个人觉得不错的Demo源码

    1.title

    获取或设置UIAlertView上的标题。

    2.message

    获取或设置UIAlertView上的消息

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    alertView.title = @"T";
    alertView.message = @"M";
    [alertView show];
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    NSLog(@"%d",alertView.numberOfButtons);
    [alertView show];
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示"
                                                   message:@"请选择一个按钮:"
                                                  delegate:nil
                                         cancelButtonTitle:@"取消"
                                         otherButtonTitles:@"按钮一", @"按钮二", @"按钮三",nil];
    [alert show];
    NSLog(@"UIAlertView中取消按钮的角标是%d",alert.cancelButtonIndex);
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"产品信息展示" message:p.name delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
    // 弹出UIAlertView
    [alert show];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"产品信息展示" message:p.name delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    // 弹出UIAlertView
    [alert show];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"产品信息展示" message:p.name delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    alert.alertViewStyle = UIAlertViewStyleSecureTextInput;
    // 弹出UIAlertView
    [alert show];

    6. - (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex

    返回textFieldIndex角标对应的文本框,取出文本框文字。

    7.手动的取消对话框

    9.注意UIAlertView调用show显示出来的时候,系统会自动强引用它,不会被释放。

    10. 为UIAlertView添加子视图

    在为UIAlertView对象太添加子视图的过程中,有点是需要注意的地方,如果删除按钮,也就是取消UIAlerView视图中所有的按钮的时候,可能会导致整个显示结构失衡。按钮占用的空间不会消失,我们也可以理解为这些按钮没有真正的删除,仅仅是他不可见了而已。如果在UIAlertview对象中仅仅用来显示文本,那么,可以在消息的开头添加换行符(@"\n)有助于平衡按钮底部和顶部的空间。

    下面的代码用来演示如何为UIAlertview对象添加子视图的方法。

    UIAlertView*alert = [[UIAlertView alloc]initWithTitle:@"请等待"
                                                                          message:nil
                                                                          delegate:nil
                                                                          cancelButtonTitle:nil
                                                                          otherButtonTitles:nil];
    [alert show];
    UIActivityIndicatorView*activeView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    activeView.center CGPointMake(alert.bounds.size.width / 2.0f, alert.bounds.size.height - 40.0f);
    [activeView startAnimating];
    [alert addSubview:activeView];
    - (void)willPresentAlertView:(UIAlertView *)alertView {
              forUIView view in alertView.subviews ) {
                        if( [view isKindOfClass:[UILabel class]] ) {
                                  UILabel* label = (UILabel*) view;
                                  label.textAlignment=UITextAlignmentLeft;

    如上图中的曲线图和表格便是由ScrollView加载两个控件(UIWebView 和 UITableView)实用其翻页属性实现的页面滚动。而PageControll但当配合角色,页面滚动小白点会跟着变化位置,而点击小白点ScrollView会滚动到指定的页面。

    代码:(只罗列主要代码)

    - (void)viewDidLoad

        [superviewDidLoad];

        self.view.backgroundColor = [UIColorcolorWithPatternImage:[UIImageimageNamed:@"bg_blank.png"]];

      //  self.view.backgroundColor = [UIColor clearColor];

    //定义UIScrollView

        scrollview = [[UIScrollViewalloc] init];

        scrollview.frame = CGRectMake(10, 0, 300, 108);    

        scrollview.contentSize = CGSizeMake(600, 108);  //scrollview的滚动范围

        scrollview.showsVerticalScrollIndicator = NO;

        scrollview.showsHorizontalScrollIndicator = NO;

    //myScrollView.clipsToBounds = YES;

        scrollview.delegate = self;

         scrollview.scrollEnabled = YES;

        scrollview.pagingEnabled = YES; //使用翻页属性 

        scrollview.bounces = NO; 

    //定义WebView加载曲线图

        webview = [[UIWebViewalloc] init];

        webview.frame = CGRectMake(-7, -10, 307, 118);

        webview.delegate = self;

        [webviewsetBackgroundColor:[UIColorclearColor]];

        [webviewsetOpaque:NO];    

        NSString *fullPath = [NSBundlepathForResource:@"sline"ofType:@"htm"inDirectory:[[NSBundlemainBundle] bundlePath]];  

        [self.webviewloadRequest:[NSURLRequestrequestWithURL:[NSURLfileURLWithPath:fullPath]]];   

        //用来制定边框

        view22 = [[UIViewalloc] init];

        //将图层的边框设置为圆脚   

        view22.layer.cornerRadius = 10;

        view22.layer.masksToBounds = YES;

        //给图层添加一个有色边框

        view22.layer.borderWidth = 1;

        //view1.layer.borderColor = [[UIColor colorWithRed:0.52 green:0.09 blue:0.07 alpha:1] CGColor]; 

        view22.layer.borderColor = [[UIColorcolorWithRed:0green:0blue:0alpha:1] CGColor];   

        view22.frame = CGRectMake(0, 0, 300, 108);

        view22.backgroundColor = [UIColorcolorWithRed:0.31green:0.31blue:0.31alpha:1];  

        tableview.frame = CGRectMake(0, 21, 300, 87);

        tableview.allowsSelection = NO;

        tableview.backgroundColor = [UIColorcolorWithRed:0.31green:0.31blue:0.31alpha:1];

    //用来制定边框

        view11 = [[UIViewalloc] init];

        //将图层的边框设置为圆脚   

        view11.layer.cornerRadius = 10;

        view11.layer.masksToBounds = YES;

        //给图层添加一个有色边框

        view11.layer.borderWidth = 1;

        //view1.layer.borderColor = [[UIColor colorWithRed:0.52 green:0.09 blue:0.07 alpha:1] CGColor]; 

        view11.layer.borderColor = [[UIColorcolorWithRed:0green:0blue:0alpha:1] CGColor];   

        view11.frame = CGRectMake(300, 0, 300, 108);

        view11.backgroundColor = [UIColorblackColor];

        [view11addSubview:tableview];

        [scrollviewaddSubview:view11];

        [view22addSubview:webview];

        [scrollviewaddSubview:view22];

    //定义PageControll

        pageControl = [[UIPageControlalloc] init];

        pageControl.frame = CGRectMake(150, 100, 20, 20);//指定位置大小

        pageControl.numberOfPages = 2;//指定页面个数

        pageControl.currentPage = 0;//指定pagecontroll的值,默认选中的小白点(第一个)

        [pageControladdTarget:selfaction:@selector(changePage:)forControlEvents:UIControlEventValueChanged];

        //添加委托方法,当点击小白点就执行此方法

        [self.viewaddSubview:scrollview];

        [self.viewaddSubview:pageControl];    

    //scrollview的委托方法,当滚动时执行

    - (void)scrollViewDidScroll:(UIScrollView *)sender {

        int page = scrollview.contentOffset.x / 290;//通过滚动的偏移量来判断目前页面所对应的小白点

         pageControl.currentPage = page;//pagecontroll响应值的变化

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

    //pagecontroll的委托方法

    - (IBAction)changePage:(id)sender { 

        int page = pageControl.currentPage;//获取当前pagecontroll的值

        [scrollview setContentOffset:CGPointMake(300 * page, 0)];//根据pagecontroll的值来改变scrollview的滚动位置,以此切换到指定的页面

    以上是一种简单的方法来实现pagecontroll的切换页面功能,以后会为大家添加 “无限循环切换页面”和“动态的增加和减少页面”。

     (二)2.UITextView 能滚动的文字显示控件

    1.创建并初始化

    创建UITextView的文件,并在.h文件中写入如下代码:

    #import <UIKit/UIKit.h>



    @interface TextViewController : UIViewController <UITextViewDelegate>

    {

    UITextView *textView;

    }



    @property (nonatomic, retain) UITextView *textView;



    @end

    2. UITextView退出键盘的几种方式

    因为你点击UITextView会出现键盘,如果你退出键盘,有如下几种方式:

    (1)如果你程序是有导航条的,可以在导航条上面加多一个Done的按钮,用来退出键盘,当然要先实UITextViewDelegate。

    代码如下:


    这样无论你是使用电脑键盘上的回车键还是使用弹出键盘里的return键都可以达到退出键盘的效果。

    (3)还有你也可以自定义其他加载键盘上面用来退出,比如在弹出的键盘上面加一个view来放置退出键盘的Done按钮。

    代码如下:

    (4)设置UITextView圆角问题

    做法是在 #import QuartzCore/QuartzCore.h 后,便能調用 [textView.layer setCornerRadius:10]; 來把 UITextView 设定圓角

    (5)UITextView根据文本大小自适应高度

    通过实现文本字数来确定高度,如下:

    (1)创建

       UIActivityIndicatorView *activityView=[[UIActivityIndicatorViewalloc] initWithFrame:CGRectMake(150, 30, 100, 100)];
    (2)设置类型(activityIndicatorViewStyle)
      三种类型:
        UIActivityIndicatorViewStyleWhiteLarge:大的白色的指示器
        UIActivityIndicatorViewStyleWhite: 标准白色的指示器
        UIActivityIndicatorViewStyleGray:为白色背景准备的灰色指示器
    (3)当停止时隐藏
      activityIndicator.hidesWhenStopped = YES;
    (4)开始动画
      [activityView startAnimating];
    (5)结束动画
      [activityView stopAnimating];
    (6)将它添加到UIView中
     [view addSubView:activityView];
    开关(UISwitch)提供了一个简单的开/关UI元素,类似于传统的物理开关,开关的可配置选项很少,应将其用于处理布尔值。我们使用其Value Changed事件来检测开关切换,并通过属性on或实例方法isOn来获取当前值。

    1.UISwitch的初始化

    UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectMake(54.0f, 16.0f, 100.0f, 28.0f)];

    2.设置UISwitch的初始化状态

    switchView.on = YES;//设置初始为ON的一边

     3.UISwitch事件的响应

    [switchView addTarget:self action:@selector(switchAction:) forControlEvents:UIControlEventValueChanged];

    iOS自定义的UISwitch按钮

    因为项目需要在UISwitch按钮上写文字,系统自带的UISwitch是这样的:

    既不能写字,也不能改颜色,于是在网上找到了这么一个自定义的Switch按钮,具体出处找不见了。记录一下,怕以后找不见了。

    先看下效果图:

    按钮的样式很多,可以文字,可以写多行,文字大小和颜色都可以设置。

    看下它的源码:

  • #import <Foundation/Foundation.h>  
  • @interface HMCustomSwitch : UISlider {  
  •     BOOL on;  
  •     UIColor *tintColor;  
  •     UIView *clippingView;  
  •     UILabel *rightLabel;  
  •     UILabel *leftLabel;  
  •     // private member  
  •     BOOL m_touchedSelf;  
  • @property(nonatomic,getter=isOn) BOOL on;  
  • @property (nonatomic,retain) UIColor *tintColor;  
  • @property (nonatomic,retain) UIView *clippingView;  
  • @property (nonatomic,retain) UILabel *rightLabel;  
  • @property (nonatomic,retain) UILabel *leftLabel;  
  • + (HMCustomSwitch *) switchWithLeftText: (NSString *) tag1 andRight: (NSString *) tag2;  
  • - (void)setOn:(BOOL)on animated:(BOOL)animated;  
  • #import "HMCustomSwitch.h"  
  • @implementation HMCustomSwitch  
  • @synthesize on;  
  • @synthesize tintColor, clippingView, leftLabel, rightLabel;  
  • +(HMCustomSwitch *)switchWithLeftText:(NSString *)leftText andRight:(NSString *)rightText  
  •     HMCustomSwitch *switchView = [[HMCustomSwitch alloc] initWithFrame:CGRectZero];  
  •     switchView.leftLabel.text = leftText;  
  •     switchView.rightLabel.text = rightText;  
  •     return [switchView autorelease];  
  • -(id)initWithFrame:(CGRect)rect  
  •     if ((self=[super initWithFrame:CGRectMake(rect.origin.x,rect.origin.y,95,27)]))  
  •         //      self.clipsToBounds = YES;  
  •         [self awakeFromNib];        // do all setup in awakeFromNib so that control can be created manually or in a nib file  
  •     return self;  
  • -(void)awakeFromNib  
  •     [super awakeFromNib];  
  •     self.backgroundColor = [UIColor clearColor];  
  •     [self setThumbImage:[UIImage imageNamed:@"switchThumb.png"] forState:UIControlStateNormal];  
  •     [self setMinimumTrackImage:[UIImage imageNamed:@"switchBlueBg.png"] forState:UIControlStateNormal];  
  •     [self setMaximumTrackImage:[UIImage imageNamed:@"switchOffPlain.png"] forState:UIControlStateNormal];  
  •     self.minimumValue = 0;  
  •     self.maximumValue = 1;  
  •     self.continuous = NO;  
  •     self.on = NO;  
  •     self.value = 0.0;  
  •     self.clippingView = [[UIView alloc] initWithFrame:CGRectMake(4,2,87,23)];  
  •     self.clippingView.clipsToBounds = YES;  
  •     self.clippingView.userInteractionEnabled = NO;  
  •     self.clippingView.backgroundColor = [UIColor clearColor];  
  •     [self addSubview:self.clippingView];  
  •     [self.clippingView release];  
  •     NSString *leftLabelText = NSLocalizedString(@"ON","Custom UISwitch ON label. If localized to empty string then I/O will be used");  
  •     if ([leftLabelText length] == 0)      
  •         leftLabelText = @"l";       // use helvetica lowercase L to be a 1.   
  •     self.leftLabel = [[UILabel alloc] init];  
  •     self.leftLabel.frame = CGRectMake(0, 0, 48, 23);  
  •     self.leftLabel.text = leftLabelText;  
  •     self.leftLabel.textAlignment = NSTextAlignmentCenter;  
  •     self.leftLabel.font = [UIFont boldSystemFontOfSize:17];  
  •     self.leftLabel.textColor = [UIColor whiteColor];  
  •     self.leftLabel.backgroundColor = [UIColor clearColor];  
  •     //      self.leftLabel.shadowColor = [UIColor redColor];  
  •     //      self.leftLabel.shadowOffset = CGSizeMake(0,0);  
  •     [self.clippingView addSubview:self.leftLabel];  
  •     [self.leftLabel release];  
  •     NSString *rightLabelText = NSLocalizedString(@"OFF","Custom UISwitch OFF label. If localized to empty string then I/O will be used");  
  •     if ([rightLabelText length] == 0)     
  •         rightLabelText = @"O";  // use helvetica uppercase o to be a 0.   
  •     self.rightLabel = [[UILabel alloc] init];  
  •     self.rightLabel.frame = CGRectMake(95, 0, 48, 23);  
  •     self.rightLabel.text = rightLabelText;  
  •     self.rightLabel.textAlignment = NSTextAlignmentCenter;  
  •     self.rightLabel.font = [UIFont boldSystemFontOfSize:17];  
  •     self.rightLabel.textColor = [UIColor grayColor];  
  •     self.rightLabel.backgroundColor = [UIColor clearColor];  
  •     //      self.rightLabel.shadowColor = [UIColor redColor];  
  •     //      self.rightLabel.shadowOffset = CGSizeMake(0,0);  
  •     [self.clippingView addSubview:self.rightLabel];  
  •     [self.rightLabel release];  
  • -(void)layoutSubviews  
  •     [super layoutSubviews];  
  •     //  NSLog(@"leftLabel=%@",NSStringFromCGRect(self.leftLabel.frame));  
  •     // move the labels to the front  
  •     [self.clippingView removeFromSuperview];  
  •     [self addSubview:self.clippingView];  
  •     CGFloat thumbWidth = self.currentThumbImage.size.width;  
  •     CGFloat switchWidth = self.bounds.size.width;  
  •     CGFloat labelWidth = switchWidth - thumbWidth;  
  •     CGFloat inset = self.clippingView.frame.origin.x;  
  •     //  NSInteger xPos = self.value * (self.bounds.size.width - thumbWidth) - (self.leftLabel.frame.size.width - thumbWidth/2);   
  •     NSInteger xPos = self.value * labelWidth - labelWidth - inset;  
  •     self.leftLabel.frame = CGRectMake(xPos, 0, labelWidth, 23);  
  •     //  xPos = self.value * (self.bounds.size.width - thumbWidth) + (self.rightLabel.frame.size.width - thumbWidth/2);   
  •     xPos = switchWidth + (self.value * labelWidth - labelWidth) - inset;   
  •     self.rightLabel.frame = CGRectMake(xPos, 0, labelWidth, 23);  
  •     //  NSLog(@"value=%f    xPos=%i",self.value,xPos);  
  •     //  NSLog(@"thumbWidth=%f    self.bounds.size.width=%f",thumbWidth,self.bounds.size.width);  
  • - (UIImage *)image:(UIImage*)image tintedWithColor:(UIColor *)tint   
  •     if (tint != nil)   
  •         UIGraphicsBeginImageContext(image.size);  
  •         //draw mask so the alpha is respected  
  •         CGContextRef currentContext = UIGraphicsGetCurrentContext();  
  •         CGImageRef maskImage = [image CGImage];  
  •         CGContextClipToMask(currentContext, CGRectMake(0, 0, image.size.width, image.size.height), maskImage);  
  •         CGContextDrawImage(currentContext, CGRectMake(0,0, image.size.width, image.size.height), image.CGImage);  
  •         [image drawAtPoint:CGPointMake(0,0)];  
  •         [tint setFill];  
  •         UIRectFillUsingBlendMode(CGRectMake(0,0,image.size.width,image.size.height),kCGBlendModeColor);  
  •         UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
  •         UIGraphicsEndImageContext();  
  •         return newImage;  
  •         return image;  
  • -(void)setTintColor:(UIColor*)color  
  •     if (color != tintColor)  
  •         [tintColor release];  
  •         tintColor = [color retain];  
  •         [self setMinimumTrackImage:[self image:[UIImage imageNamed:@"switchBlueBg.png"] tintedWithColor:tintColor] forState:UIControlStateNormal];  
  • - (void)setOn:(BOOL)turnOn animated:(BOOL)animated;  
  •     on = turnOn;  
  •     if (animated)  
  •         [UIView  beginAnimations:nil context:nil];  
  •         [UIView setAnimationDuration:0.2];  
  •     if (on)  
  •         self.value = 1.0;  
  •         self.value = 0.0;  
  •     if (animated)  
  •         [UIView commitAnimations];    
  • - (void)setOn:(BOOL)turnOn  
  •     [self setOn:turnOn animated:NO];  
  • - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event  
  •     NSLog(@"preendTrackingWithtouch");  
  •     [super endTrackingWithTouch:touch withEvent:event];  
  •     NSLog(@"postendTrackingWithtouch");  
  •     m_touchedSelf = YES;  
  •     [self setOn:on animated:YES];  
  • - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event  
  •     [super touchesBegan:touches withEvent:event];  
  •         NSLog(@"touchesBegan");  
  •     m_touchedSelf = NO;  
  •     on = !on;  
  • - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event  
  •     [super touchesEnded:touches withEvent:event];  
  •     NSLog(@"touchesEnded");  
  •     if (!m_touchedSelf)  
  •         [self setOn:on animated:YES];  
  •         [self sendActionsForControlEvents:UIControlEventValueChanged];  
  • -(void)dealloc  
  •     [tintColor release];  
  •     [clippingView release];  
  •     [rightLabel release];  
  •     [leftLabel release];  
  •     [super dealloc];  

  • 看代码可以知道,其实它是通过继承UISlider控件实现的,UISlider的左右分别是个UILabel,当YES的时候,滑块滑到了最右边,NO的时候滑到了最左边。

    如何在代码中使用它呢?很简单:

    - (void)loadView  

        UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];  

        self.view = contentView;  

  •     contentView.backgroundColor = [UIColor whiteColor];  
  • // Standard ON/OFF  
  •     HMCustomSwitch *switchView = [[HMCustomSwitch alloc] initWithFrame:CGRectZero];  
  •     switchView.center = CGPointMake(160.0f, 20.0f);  
  •     switchView.on = YES;  
  •     [contentView addSubview:switchView];  
  •     [switchView release];  
  • // Custom YES/NO  
  •     switchView = [HMCustomSwitch switchWithLeftText:@"YES" andRight:@"NO"];  
  •     switchView.center = CGPointMake(160.0f, 60.0f);  
  •     switchView.on = YES;  
  •     [contentView addSubview:switchView];  
  • // Custom font and color  
  •     switchView = [HMCustomSwitch switchWithLeftText:@"Hello " andRight:@"ABC "];  
  •     switchView.center = CGPointMake(160.0f, 100.0f);  
  •     switchView.on = YES;  
  •     [switchView.leftLabel setFont:[UIFont boldSystemFontOfSize:13.0f]];  
  •     [switchView.rightLabel setFont:[UIFont italicSystemFontOfSize:15.0f]];  
  •     [switchView.rightLabel setTextColor:[UIColor blueColor]];  
  •     [contentView addSubview:switchView];  
  • // Multiple lines  
  •     switchView = [HMCustomSwitch switchWithLeftText:@"Hello\nWorld" andRight:@"Bye\nWorld"];  
  •     switchView.center = CGPointMake(160.0f, 140.0f);  
  •     switchView.on = YES;  
  •     switchView.tintColor = [UIColor orangeColor];  
  •     switchView.leftLabel.font = [UIFont boldSystemFontOfSize:9.0f];  
  •     switchView.rightLabel.font = [UIFont boldSystemFontOfSize:9.0f];  
  •     switchView.leftLabel.numberOfLines = 2;  
  •     switchView.rightLabel.numberOfLines = 2;  
  •     switchView.leftLabel.lineBreakMode = NSLineBreakByWordWrapping;  
  •     switchView.rightLabel.lineBreakMode = NSLineBreakByWordWrapping;  
  •     [contentView addSubview:switchView];  
  •     switchView = [[HMCustomSwitch alloc] init];  
  •     switchView.center = CGPointMake(160.0f, 180.0f);  
  •     switchView.on = YES;  
  •     switchView.tintColor = [UIColor purpleColor];  
  •     [contentView addSubview:switchView];  
  •     [switchView release];  
  •     switchView = [HMCustomSwitch switchWithLeftText:@"l" andRight:@"O"];  
  •     switchView.center = CGPointMake(160.0f, 220.0f);  
  • //  customSwitch.tintColor = [UIColor colorWithRed:125.f/255.f green:157.f/255.f blue:93.f/255.f alpha:1.0];  
  • //  customSwitch.tintColor = [UIColor colorWithRed:125.f/255.f green:157.f/255.f blue:93.f/255.f alpha:1.0];  
  •     [contentView addSubview:switchView];  
  • // Standard ON/OFF  
  •     switchView = [[HMCustomSwitch alloc] init];  
  •     switchView.center = CGPointMake(160.0f, 260.0f);  
  •     switchView.tintColor = [UIColor colorWithRed:125.f/255.f green:157.f/255.f blue:93.f/255.f alpha:1.0];  
  •     [switchView addTarget:self action:@selector(switchFlipped:) forControlEvents:UIControlEventValueChanged];  
  •     [contentView addSubview:switchView];  
  •     [switchView release];  
  •     UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 420, 320, 40)];  
  •     toolbar.tintColor = [UIColor colorWithRed:125.f/255.f green:157.f/255.f blue:93.f/255.f alpha:1.0];  
  •     [contentView addSubview:toolbar];  
  •     [contentView release];  
  • -(void)switchFlipped:(HMCustomSwitch*)switchView  
  •     NSLog(@"switchFlipped=%f  on:%@",switchView.value, (switchView.on?@"Y":@"N"));  
  • UIActionSheet是在IOS弹出的选择按钮项,可以添加多项,并为每项添加点击事件。

    为了快速完成这例子,我们打开Xcode 4.3.2, 先建立一个single view application。然后再xib文件添加一个button,用来弹出sheet view。

    1、首先在.h文件中实现协议,加代码的地方在@interface那行的最后添加<UIActionSheetDelegate>,协议相当于java里的接口,实现协议里的方法。

    @interface sheetviewViewController : UIViewController<UIActionSheetDelegate>
    

    2、添加button,命名button为showSheetView.

    3、为button建立Action映射,映射到.h文件上,事件类型为Action ,命名为showSheet。

    4、在.m文件上添加点击事件代码

    图的效果是这样的:

    - (IBAction)showSheet:(id)sender {
        UIActionSheet *actionSheet = [[UIActionSheet alloc]
                                      initWithTitle:@"title,nil时不显示"
                                      delegate:self
                                      cancelButtonTitle:@"取消"
                                      destructiveButtonTitle:@"确定"
                                      otherButtonTitles:@"第一项", @"第二项",nil];
        actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
        [actionSheet showInView:self.view];
    

    actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;//设置样式

    参数解释:   

    cancelButtonTitle  destructiveButtonTitle是系统自动的两项。

    otherButtonTitles是自己定义的项,注意,最后一个参数要是nil。

    [actionSheet showInView:self.view];这行语句的意思是在当前view显示Action sheet。当然还可以用其他方法显示Action sheet。

    对应上面的图和代码,一目了然了把

    5、接下来我们怎么相应Action Sheet的选项的事件呢?实现协议里的方法。为了能看出点击Action sheet每一项的效果,我们加入UIAlertView来做信息显示。下面是封装的一个方法,传入对应的信息,在UIAlertView显示对应的信息。

    -(void)showAlert:(NSString *)msg {
        UIAlertView *alert = [[UIAlertView alloc]
                              initWithTitle:@"Action Sheet选择项"
                              message:msg
                              delegate:self
                              cancelButtonTitle:@"确定"
                              otherButtonTitles: nil];
        [alert show];
    

    那相应被Action Sheet选项执行的代码如下:

    (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
        if (buttonIndex == 0) {
            [self showAlert:@"确定"];
        }else if (buttonIndex == 1) {
            [self showAlert:@"第一项"];
        }else if(buttonIndex == 2) {
            [self showAlert:@"第二项"];
        }else if(buttonIndex == 3) {
            [self showAlert:@"取消"];
    - (void)actionSheetCancel:(UIActionSheet *)actionSheet{  
    -(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{  
    -(void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex{  
    

    可以看到 buttonIndex 是对应的项的索引。

    看到那个红色的按钮没?那是ActionSheet支持的一种所谓的销毁按钮,对某户的某个动作起到警示作用,

    比如永久性删除一条消息或图像时。如果你指定了一个销毁按钮他就会以红色高亮显示:

    actionSheet.destructiveButtonIndex=1;  

    与导航栏类似,操作表单也支持三种风格 :

    UIActionSheetStyleDefault              //默认风格:灰色背景上显示白色文字   

    UIActionSheetStyleBlackTranslucent     //透明黑色背景,白色文字   

    UIActionSheetStyleBlackOpaque          //纯黑背景,白色文字  

     actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;//设置样式

    我选sheet 里的第一项,显示如下:

    6、注意事项,在开发过程中,发现有时候UIActionSheet的最后一项点击失效,点最后一项的上半区域时有效,这是在特定情况下才会发生,这个场景就是试用了UITabBar的时候才有。解决办法:

    在showView时这样使用,[actionSheet showInView:[UIApplication sharedApplication].keyWindow];

    或者[sheet showInView:[AppDelegate sharedDelegate].tabBarController.view];这样就不会发生遮挡现象了。

    代码获取:http://download.csdn.net/detail/totogo2010/4343267

    自定义UIActionSheet

    UIActionSheet类系IOS开发中实现警告框的重要的类,而在好多应用中,都对它进行了扩展,今天介绍一下自定义风格的UIActionSheet

    一、自定义CustomActionSheet类

      CustomActionSheet类继承UIActionSheet,具体的实现如下所示:

      1)CustomActionSheet.h头文件

    #import <Foundation/Foundation.h>

    @interface CustomActionSheet : UIActionSheet {

    UIToolbar* toolBar;

    UIView* view;

    @property(nonatomic,retain)UIView* view;

    @property(nonatomic,retain)UIToolbar* toolBar;

    /*因为是通过给ActionSheet 加 Button来改变ActionSheet, 所以大小要与actionsheet的button数有关

     *height = 84, 134, 184, 234, 284, 334, 384, 434, 484

     *如果要用self.view = anotherview.  那么another的大小也必须与view的大小一样

    -(id)initWithHeight:(float)height WithSheetTitle:(NSString*)title;

       2)CustomActionSheet.m实现文件

    #import "CustomActionSheet.h"

    @implementation CustomActionSheet

    @synthesize view;

    @synthesize toolBar;

    -(id)initWithHeight:(float)height WithSheetTitle:(NSString*)title

    self = [super init];

        if (self) 

    int theight = height - 40;

    int btnnum = theight/50;

    for(int i=0; i<btnnum; i++)

    [self addButtonWithTitle:@" "];

    toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];

    toolBar.barStyle = UIBarStyleBlackOpaque;

    UIBarButtonItem *titleButton = [[UIBarButtonItem alloc] initWithTitle:title 

                                                                            style:UIBarButtonItemStylePlain 

                                                                           target:nil 

                                                                           action:nil];

    UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" 

                                                                            style:UIBarButtonItemStyleDone 

                                                                           target:self

                                                                           action:@selector(done)];

    UIBarButtonItem *leftButton  = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" 

                                                                            style:UIBarButtonItemStyleBordered 

                                                                           target:self 

                                                                           action:@selector(docancel)];

    UIBarButtonItem *fixedButton  = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace 

                                                                                          target:nil 

                                                                                          action:nil];

    NSArray *array = [[NSArray alloc] initWithObjects:leftButton,fixedButton,titleButton,fixedButton,rightButton,nil];

    [toolBar setItems: array];

    [titleButton release];

    [leftButton  release];

    [rightButton release];

    [fixedButton release];

    [array       release];

    [self addSubview:toolBar];

    view = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, height-44)];

    view.backgroundColor = [UIColor groupTableViewBackgroundColor];

    [self addSubview:view];

        return self;

    -(void)done

    [self dismissWithClickedButtonIndex:0 animated:YES];

    -(void)docancel

    [self dismissWithClickedButtonIndex:0 animated:YES];

    -(void)dealloc

    [view release];

    [super dealloc];


    二、利用自定义的CustomActionSheet类显示提示框

    #import "TestActionSheetViewController.h"

    #import "CustomActionSheet.h"

    @implementation TestActionSheetViewController

    -(IBAction)btndown

    CustomActionSheet* sheet = [[CustomActionSheet alloc] initWithHeight:284.0f 

                                                              WithSheetTitle:@"自定义ActionSheet"];

    UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0,50, 320, 50)];

    label.text = @"这里是要自定义放的控制";

    label.backgroundColor = [UIColor clearColor];

    label.textAlignment = UITextAlignmentCenter;

    [sheet.view addSubview:label];

    [sheet showInView:self.view];

    [sheet release];

        这里的UILabel是作一个示例,在这个位置你可以换成你自己的内容即可;

    三、效果图

    (二)6.UIDatePicker 日期选择器

    UIDatePicker

  • 1、UIDatePicker使用
  • 2、UIPickerView使用
  • 在点击过文本输入框后弹出日期选中键盘。需要给UITextField控件的inutView属性指定需要显示的界面。

    这里显示的代码如下:

    - (void)setBirthdayFieldKeyboard

        UIDatePicker *datePicker = [[UIDatePicker alloc] init];

        _datePicker = datePicker;

        // 只显示时间

        datePicker.datePickerMode = UIDatePickerModeDate;

        // 显示中文

        datePicker.locale = [NSLocalelocaleWithLocaleIdentifier:@"zh"];

        // 监听值得改变

        [datePicker addTarget:selfaction:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];

        self.birthdayField.inputView = datePicker;

    在程序加载时进行设定

    - (void)viewDidLoad {

        [superviewDidLoad];

        [selfsetBirthdayFieldKeyboard];

    然后对UITextField的一些属性进行设置,比如说不能输入日期,只能选择显示日期。可以在以下代理方法中实现

    #pragma mark - textField代理方法

    // 是否允许修改填充字符串

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

        returnNO;

    当然使用之前要指定代理并遵守协议。

    然后再选择过时间后,同步更新到文本输入框中,这里需要监听控件的valueChanged的方法

        [datePicker addTarget:self action:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];

    - (void)datePickerValueChanged:(UIDatePicker *)datePicker

        NSDateFormatter *formatter = [[NSDateFormatteralloc] init];

        // 格式化日期格式

        formatter.dateFormat = @"yyyy-MM-dd";

        NSString *date = [formatter stringFromDate:datePicker.date];

        // 显示时间

        self.birthdayField.text = date;

    最后要设置以下UITextField控件的默认值,默认显示0行0列的值

    在改变文本输入框状态时进行设置默认值。

    // 是否允许开始编辑(代理方法)

    - (void)textFieldDidBeginEditing:(UITextField *)textField

        // 添加自定义窗口

        [selfdatePickerValueChanged:self.datePicker];

    2、UIPickerView使用

    先将城市选择键盘添加到文本输入框

    // 设置城市键盘

    - (void)setCitiesFieldKeyboard

        UIPickerView *picker = [[UIPickerViewalloc] init];

        _cityPicker = picker;

        picker.dataSource = self;

        picker.delegate = self;

        self.cityField.inputView = picker; 

    设置代理和数据源为控制器,实现响应的方法

    #pragma mark UIPickerView 数据源

    // 列数

    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

        return 2;

    // 某一列行数

    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

        if (component == 0)  // 省会

            return self.provinces.count;

        else  // 其他城市

            SLQProvince *pro = self.provinces[_proIndex];

            return pro.cities.count;

    #pragma mark UIPickerView 代理

    // 每行的标题

    - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

        if (component == 0)  // 省会

            // 获取省会

            SLQProvince *pro = self.provinces[row];

            return pro.name;

        else  // 其他城市

            SLQProvince *pro = self.provinces[_proIndex];

            return pro.cities[row];

    // 是否选中某行

    - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

        // 滚动省会刷新城市

        if(component == 0)

            // 记录当前省会

            _proIndex = [pickerView selectedRowInComponent:0];

            [pickerView reloadComponent:1];

        // 获取选中省会

        SLQProvince *pro = self.provinces[_proIndex];

        NSInteger cityIndex = [pickerView selectedRowInComponent:1];

        NSString *cityName = pro.cities[cityIndex];

        _cityField.text = [NSString stringWithFormat:@"%@-%@",pro.name,cityName];

    然后在文本输入框的代理方法中添加默认显示对象

    // 是否允许开始编辑

    - (void)textFieldDidBeginEditing:(UITextField *)textField

        if (textField == self.birthdayField)

            // 添加自定义窗口

            [selfdatePickerValueChanged:self.datePicker];

            [selfpickerView:self.cityPickerdidSelectRow:0inComponent:0]; // 默认显示0行0列

     主要代码参考

    // 2. 设置日期选择控件的地区
    [datePicker setLocale:[[NSLocale  alloc]initWithLocaleIdentifier:@"zh_Hans_CN"]];
    // 2) 设置日期选择控件的地区
    [datePicker setLocale:[[NSLocale alloc]initWithLocaleIdentifier:@"en_SC"]];
    // 1) 设置日期选择的模
    [self.datePicker setDatePickerMode:UIDatePickerModeCountDownTimer];
    // 2) 设置倒计时的时长
    // 注意:设置倒计时时长需要在确定模式之后指定
    // 倒计时的时长,以秒为单位
    [self.datePicker setCountDownDuration:10 * 60];
    NSDateminDate [[NSDate alloc]initWithString:@"1900-01-01 00:00:00 -0500"];
    NSDatemaxDate [[NSDate alloc]initWithString:@"2099-01-01 00:00:00 -0500"];
    datePicker.minimumDate minDate;
    datePicker.maximumDate maxDate;

    1. 初始化UIDatePicker

    UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 200, 320, 216)];

    注:高度和宽度可以设定为0,比如:

    UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 200, 0, 0)];

    2. 设置时区

    [datePicker setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];

    3. 设置当前显示时间

    [datePicker setDate:tempDate animated:YES];

    4. 设置显示最大时间(此处为当前时间)

    [datePicker setMaximumDate:[NSDate date]];

    datePicker.maximumDate = [NSDate date];

    设置最小时间

    NSDate* minDate = [[NSDate alloc]initWithString:@"1900-01-01 00:00:00 -0500"];
    datePicker.minimumDate = minDate;
    [minDate release];

    5. 设置UIDatePicker的显示模式

    [datePicker setDatePickerMode:UIDatePickerModeDate];

    参数 UIDatePickerMode 有四种:

        UIDatePickerModeTime,           // Displays hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. 6 | 53 | PM)
        UIDatePickerModeDate,           // Displays month, day, and year depending on the locale setting (e.g. November | 15 | 2007)
        UIDatePickerModeDateAndTime,    // Displays date, hour, minute, and optionally AM/PM designation depending on the locale setting (e.g. Wed Nov 15 | 6 | 53 | PM)
        UIDatePickerModeCountDownTimer  // Displays hour and minute (e.g. 1 | 53)

    6. 当值发生改变的时候调用的方法

    [datePicker addTarget:self action:@selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];

    7. 加入到视图

    [self.view addSubview:datePicker];

    甚至还可以加入到 UIActionSheet 中

    [actionSheet addSubview: datePicker];

    8. 释放对象

    [datePicker release];

    9. 获得当前UIPickerDate所在的时间

    NSDate *date = [datePicker date];

    10.设置本地化语言

      NSLocale * locale = [[NSLocalealloc] initWithLocaleIdentifier:@"Chinese"];//设置本地化语言,本地化语言可以通过在xib文件中添加一个日历选取器,然后查看其属性来找到需要的值

      [datePicker setLocale:locale];

    比如可以在 datePickerValueChanged 回调方法中

    - (void)datePickerValueChanged:(id)sender {
        UIDatePicker *datePicker = sender;
        NSDate *date = [datePicker date];
        // TODO:
    |

    可以在toolBar上添加任何View。其实它的原理是把你要添加的View先加到UIBarButtonItem里面,最后再把UIBarButtonItem数组一次性放到toolbar的items里面。

    1.首先,我们看一下UIBbarButtonItem有哪些初始化方法,这也可以看出,它可以被定义为什么东东,然后加到UIToolBar上面去。

    根据SDK的文档,我们可以发现UIBarButtonItem有如下几种初始化的方法:

    -initWithTitle(添加button用这个)

    -initWithImage

    -initWithBarButtonSystemItem(添加系统自定义的button,形状跟大小都已经固定了)下面链接里面有按钮图片样式

    https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIBarButtonItem_Class/Reference/Reference.html

    -initWithCustomView(添加除了button以外的View)

    第4种方法就是我们添加各种作料的接口,所以今天的主角其它也是它。

    2.在UIToolBar上面添加Title

    view plaincopy to clipboardprint?

    UIToolbar *myToolBar = [[UIToolbar alloc] initWithFrame:  

                                                        CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];  

    NSMutableArray *myToolBarItems = [NSMutableArray array];  

    [myToolBarItems addObject:[[[UIBarButtonItem alloc]  

                                                            initWithTitle:@"myTile"   

                                                            style:UIBarButtonItemStylePlain   

                                                            target:self   

                                                            action:@selector(action)] autorelease]];  

    [myToolBar setItems:myToolBarItems animated:YES];  

    [myToolBar release];  

    [myToolBarItems];                                                         

    setItems传入值或者说items是一个对象数组。

    3.在UIToolBar上面添加image

    view plaincopy to clipboardprint?

    [myToolBarItems addObject:[[[UIBarButtonItem alloc]  

                                            initWithImage:[UIImage imageNamed:@"myImage.png"]   

                                            style:UIBarButtonItemStylePlain   

                                            target:self   

                                            action:@selector(action)]];   

    4.在UIToolBar上面添加SystemItem

    [myToolBarItems addObject:[[[UIBarButtonItem alloc]  

                                            initWithBarButtonSystemItem:UIBarButtonSystemItemPlay   

                                            target:self   

                                            action:@selector(action)] autorelease]];   

    Note:

    initWithBarButtonSystemItem初始化:

    - (id)initWithBarButtonSystemItem:(UIBarButtonSystemItem)systemItem target:(id)target action:(SEL)action

    Defines system defaults for commonly used items.

    typedef enum {  

        UIBarButtonSystemItemDone,  

        UIBarButtonSystemItemCancel,  

        UIBarButtonSystemItemEdit,  

        UIBarButtonSystemItemSave,  

        UIBarButtonSystemItemAdd,  

        UIBarButtonSystemItemFlexibleSpace,  

        UIBarButtonSystemItemFixedSpace,  

        UIBarButtonSystemItemCompose,  

        UIBarButtonSystemItemReply,  

        UIBarButtonSystemItemAction,  

        UIBarButtonSystemItemOrganize,  

        UIBarButtonSystemItemBookmarks,  

        UIBarButtonSystemItemSearch,  

        UIBarButtonSystemItemRefresh,  

        UIBarButtonSystemItemStop,  

        UIBarButtonSystemItemCamera,  

        UIBarButtonSystemItemTrash,  

        UIBarButtonSystemItemPlay,  

        UIBarButtonSystemItemPause,  

        UIBarButtonSystemItemRewind,  

        UIBarButtonSystemItemFastForward,  

        UIBarButtonSystemItemUndo,        // iPhoneOS 3.0  

        UIBarButtonSystemItemRedo,        // iPhoneOS 3.0  

    } UIBarButtonSystemItem;  

    5.在UIToolBar上面添加其它各种控件,最自由意义,最有意思的,我把它放在最后来讲。我们使用initWithCustomView来完成,

    这里需要看一下initWithCustomView的定义:

    - (id)initWithCustomView:(UIView *)customView

    可以看出,它的参数是一个VIEW,所以我们给它的配料要正确哦才行哦,否则,你就等着时间DIDADIDA的流失吧.

    A>加一个开关switch:

    [myToolBarItems addObject:[[[UIBarButtonItem alloc]     

                                    initWithCustomView:[[[UISwitch alloc] init] autorelease]]  

                                        autorelease]];  

    B>加一个按钮UIBarButtonItem

    UIBarButtonItem *myButton = [[[UIBarButtonItem alloc]  

                                     initWithTitle:@"myButton"  

                                     style:UIBarButtonItemStyleBordered  

                                     target:self   

                                     action:@selector(action)]autorelease];  

    get1Button.width = 50;  

    [myToolBarItems addObject:myButton];      

    C>加一个文本Label

    view plaincopy to clipboardprint?

    UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(40.0f, 20.0f, 45.0f, 10.0f)];  

    myLabel.font=[UIFont systemFontOfSize:10];  

    //myLabel.backgroundColor = [UIColor clearColor];  

    //myLabel.textAlignment=UITextAlignmentCenter;  

    UIBarButtonItem *myButtonItem = [[UIBarButtonItem alloc]initWithCustomView:myLabel];  

    [myToolBarItems addObject: myButtonItem];     

    [mylabel release];  

    [myButtonItem release];  

    D>加一个进度条UIProgressView

    UIProgressView *myProgress = [[UIProgressView alloc] initWithFrame:CGRectMake(65.0f, 20.0f, 90.0f, 10.0f)];  

    UIBarButtonItem *myButtonItem = [[UIBarButtonItem alloc]initWithCustomView:myProgress];  

    [myToolBarItems addObject: myButtonItem];  

    [myProgress release];                                             

    [myButtonItem release];  

    可以加使用initWithCustomView制作各种button,这里就不在这里一个一个在加了。我想你应该也已经掌握了如何添加各种buttonItem的方法了。

        proValue=0;

         timer = [NSTimerscheduledTimerWithTimeInterval:1target:selfselector:@selector(changeProgress) userInfo:nilrepeats:YES]; //利用计时器,每隔1秒调用一次(changeProgress)

    -(void)changeProgress

        proValue += 1.0; //改变proValue的值

        if(proValue > 5)

            //停用计时器

            [timer invalidate];        

            [proViewsetProgress:(proValue / 5)];//重置进度条

    - (void)viewDidLoad

        proView = [[UIProgressViewalloc] initWithFrame:CGRectMake(100, 100, 150, 20)];

        [proViewsetProgressViewStyle:UIProgressViewStyleDefault]; //设置进度条类型

        [self.viewaddSubview:proView];

        [superviewDidLoad];

     (三)3.UISlider 滑块 

    UIslider是一个方便的控件,让用户能够以可视化的方式设置指定范围内的值。和按钮一样,滑块也能响应事件,还可像文本框一样被读取。如果希望用户对滑块的调整立刻影响应用程序,则需要让他触发操作。

    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 20)]; //初始化 	slider.minimumValue = 0;//指定可变最小值 	slider.maximumValue = 100;//指定可变最大值 	slider.value = 50;//指定初始值 	[slider addTarget:self action:@selector(updateValue:) forControlEvents:UIControlEventValueChanged];//设置响应事件 	[self.view addSubview:slider];


    -(IBAction)updateValue:(id)sender{
      //添加响应事件
      float f = slider.value; //读取滑块的值
    }


    改变UISlider的样式:

    需要资源如下

    (max.png)

      (min.png)          类似图片就可。

     slider.backgroundColor = [UIColorclearColor];  

    [slider setMinimumTrackImage:[UIImageimageNamed:@"max.png"] forState:UIControlStateNormal];

    [slider setMaximumTrackImage:[UIImageimageNamed:@"min.png"] forState:UIControlStateNormal];

    注意:UISlider的长和宽,要和图片匹配。

     (三)4.UISegmentControl 选项卡

    -(void) viewDidLoad{
    /*************分段控件UISegmentdControl*************/ UISegmentedControl *segmentedControl = [[UISegmentedControlalloc] initWithItems:nil]; segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; //控件风格小按钮,适合导航栏: segmentedControl.segmentedControlStyle = UISegmentedControlStyleBezeled; //控件风格 segmentedControl.segmentedControlStyle = UISegmentedControlStyleBordered; //控件风格黑边的大白按钮,适合表格单元 segmentedControl.segmentedControlStyle = UISegmentedControlStylePlain; //控件风格灰边大白按钮,适合偏好设置单元 segmentedControl.tintColor = [UIColor blueColor]; //渲染色彩 //添加片段,从0单元开始 ,可加入标题或图片两种情况 [segmentedControl insertSegmentWithTitle:@"First"atIndex:0animated:NO]; [segmentedControl insertSegmentWithTitle:@"Second"atIndex:1animated:NO]; UIImage *myImage = [UIImage imageNamed:@"1.png"]; [segmentedControl insertSegmentWithImage:myImage atIndex:2animated:NO]; //删除片段 [segmentedControl removeSegmentAtIndex:1 animated:YES]; //删除单个 [segmentedControl removeAllSegments]; //删除所有 //片段标题 [segmentedControl setTitle:@"Third" forSegmentAtIndex:2];//设置标题 NSString *myTitle = [segmentedControl titleForSegmentAtIndex:0];//读取标题 [segmentedControl setImage:[UIImageimageNamed:@"2.png"] forSegmentAtIndex:0];//设置图像 UIImage *myImage = [segmentedControl imageForSegmentAtIndex:3]; //读取图片 //设置片段宽度 [segmentedControl setWidth:64.0 forSegmentAtIndex:0]; //瞬时单击 segmentedControl.momentary = YES; //按钮被按下后很快恢复,默认为选中状态就一直保持 //初始化默认片段 segmentedControl.selectedSegmentIndex = 0; //初始指定第0个选中 //显示控件 [parentView addSubview:segmentedControl]; //添加到父视图 self.navigationItem.titleView = segmentedControl; //添加到导航栏(通过视图控制器) //读取控件 int selectIndex = segmentedControl.selectedSegmentIndex; //对应当前被选总的片段号码 [segmentedControl addTarget:selfaction:@selector(controlPressed:) forControlEvents:UIControlEventValueChanged];

     //SegmentedControl触发的动作    

    -(void)controlPressed:(id)sender{        

            UISegmentedControl *control = (UISegmentedControl *)sender;

            if (control == mySegmentedControl) {            

                int x = control.selectedSegmentIndex;           

                /*添加代码,对片段变化做出响应*/         

     (三)5.UIPickerView 选择器

    1.UIPickerView的初始化

    pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0.0f, 200.0f, 320.0f, 216.0f)];
    pickerView.delegate = self//指定Delegate
    pickerView.showsSelectionIndicator = YES; //显示选中框
    - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView; //返回列数
    - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component; //返回每列的最大行数
    - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; //每一列中每一行的具体内容
    - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component //选中哪一列哪一行