iOS开发系列课程(02) — 视图交互和事件机制详解手机开发

UIButton详解

UIButton和UILabel的区别和联系

  为什么要讨论这个看似没有营养的问题,因为大家都知道UIButton是按钮而UILabel是标签,这明显是两个不同的东西。事实上,UIButton和UILabel都是UIView的子类型,UIView及其子类型都代表一个矩形区域,UILabel直接继承了UIView,而UIButton的父类UIControl继承了UIView,这有什么区别吗?答案是肯定的,UIView有一个叫做userInteractionEnabled的属性,UIView将其默认值设置为YES,但UILabel的这个属性默认是NO。换句话说,只有UIControl的子类将这个属性设置为YES,因此这些控件在默认的情况下是交互型控件,能够跟用户进行交互,比如UIButton可以接受用户点击的操作,而且UIControl的子类可以通过addTarget方法设置要处理的事件及其处理代码。

这里写图片描述

创建和使用UIButton对象

  • +buttonWithType:类方法,在创建按钮时指定按钮的类型。(iOS 7开始取消了圆角矩形按钮类型,但是仍然可以通过其他方式做出圆角矩形的按钮,因为很多时候按钮都是以图片的形态呈现,有了这个圆角矩形反而不方便定制)

UIButton常用属性和方法

配置按钮标题的属性和方法:

  • titleLabel属性:按钮标题的标签
  • -titleForState:方法:指定状态下的按钮标题
  • -setTitle:forState:方法:设置指定状态下按钮的标题
  • -titleColorForState:方法:指定状态下的按钮标题颜色
  • -setTitleColor:forState:方法:设置指定状态下按钮标题的颜色
  • -setTitleShadowColor:forState:方法:设置指定状态下按钮标题阴影的颜色

配置按钮显示的方法:

  • -backgroundImageForState:方法:获得指定状态下的背景图
  • -setBackgroundImage:forState:方法:设置指定状态下的背景图
  • -imageForState:方法:获得指定状态下的按钮图片
  • -setImage:forState:方法:设置指定状态下的按钮图片

配置边距的属性:

  • contentEdgeInsets属性:内容的边距
  • titleEdgeInsets属性:标题的边距
  • imageEdgeInsets属性:图片的边距

获取按钮当前状态的属性:

  • buttonType属性:可能的取值包括UIButtonTypeCustom、UIButtonTypeSystem、UIButtonTypeDetailDisclosure、UIButtonTypeInfoLight、UIButtonTypeInfoDark、UIButtonTypeContactAdd、UIButtonTypeRounedRect(过时)。
  • currentTitle属性:按钮上当前显示的标题
  • currentTitleColor属性:当前标题颜色
  • currentImage属性:按钮上当前显示的图片
  • currentBackgroundImage属性:按钮上当前显示的背景图片
  • imageView属性:按钮上的图片视图

继承自UIControl的属性和方法:

  • -addTarget:action:forControlEvents:方法:将为事件添加的消息接受者和对应的动作加入事件派发表,简而言之就是为控件绑定事件处理的回调方法
  • -removeTarget:action:forControlEvents:方法:与上面方法的作用相反
  • -enabled属性:控件是启动还是禁用
  • -state属性:控件所处的状态

UIButton的常用事件和状态

  我们先说一下UIControl的所有可能的事件。

事件类型 说明
UIControlEventTouchDown 单点触摸按下事件,用户点触屏幕,或者又有新手指落下的时候
UIControlEventTouchDownRepeat 多点触摸按下事件,点触计数大于1:用户按下第二、三、或第四根手指的时候
UIControlEventTouchDragInside 当一次触摸在控件窗口内拖动时
UIControlEventTouchDragOutside 当一次触摸在控件窗口之外拖动时
UIControlEventTouchDragEnter 当一次触摸从控件窗口之外拖动到内部时
UIControlEventTouchDragExit 当一次触摸从控件窗口内部拖动到外部时
UIControlEventTouchUpInside 所有在控件之内触摸抬起事件
UIControlEventTouchUpOutside 所有在控件之外触摸抬起事件(点触必须开始与控件内部才会发送通知)
UIControlEventTouchCancel 所有触摸取消事件,即一次触摸因为放上了太多手指而被取消,或者被上锁或者电话呼叫打断
UIControlEventValueChanged 当控件的值发生改变时,发送通知。用于滑块、分段控件、以及其他取值的控件。你可以配置滑块控件何时发送通知,在滑块被放下时发送,或者在被拖动时发送
UIControlEventEditingDidBegin 当文本控件中开始编辑时发送通知
UIControlEventEditingChanged 当文本控件中的文本被改变时发送通知
UIControlEventEditingDidEnd 当文本控件中编辑结束时发送通知
UIControlEventEditingDidOnExit 当文本控件内通过按下回车键(或等价行为)结束编辑时,发送通知
UIControlEventAlltouchEvents 通知所有触摸事件
UIControlEventAllEditingEvents 通知所有关于文本编辑的事件
UIControlEventAllEvents 通知所有事件

  对于UIButton来说,可能绝大多数处理的都是UIControlEventTouchUpInside事件,简单的说就是按钮点击的事件。

  下面的例子中我们在窗口上放置一个标签和一个按钮,通过点击按钮修改标签上的文字,效果如下图所示。

这里写图片描述

AppDelegate类的实现代码

#import "AppDelegate.h" 
 
@interface AppDelegate () { 
    NSArray *infos; 
} 
 
@end 
 
@implementation AppDelegate 
 
 
- (instancetype)init { 
    if(self = [super init]) { 
        infos = @[@"Hello, world!", @"How are you?", @"Nice to meet you!", @"See you!", @"Good night!"]; 
    } 
    return self; 
} 
 
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
 
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; 
    self.window.backgroundColor = [UIColor whiteColor]; 
 
    CGRect screenRect = [[UIScreen mainScreen] bounds]; 
    CGPoint centerPoint = CGPointMake(screenRect.size.width / 2.0, screenRect.size.height / 2.0); 
 
    UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)]; 
    centerPoint.y -= 50; 
    infoLabel.center = centerPoint; 
    infoLabel.textAlignment = NSTextAlignmentCenter; 
    infoLabel.font = [UIFont systemFontOfSize:36]; 
    infoLabel.text = infos[0]; 
    infoLabel.textColor = [UIColor redColor]; 
    infoLabel.tag = 101; 
    infoLabel.adjustsFontSizeToFitWidth = YES; 
 
    UIButton *okButton = [UIButton buttonWithType:UIButtonTypeSystem]; 
    okButton.frame = CGRectMake(0, 0, 80, 40); 
    centerPoint.y += 100; 
    okButton.center = centerPoint; 
    [okButton setTitle:@"OK" forState:UIControlStateNormal]; 
    okButton.layer.borderColor = [UIColor blackColor].CGColor; 
    okButton.layer.borderWidth = 1; 
    okButton.layer.cornerRadius = 5; 
 
    [okButton addTarget:self action:@selector(okButtonClicked) forControlEvents:UIControlEventTouchUpInside]; 
 
    [self.window addSubview:infoLabel]; 
    [self.window addSubview:okButton]; 
 
    [self.window makeKeyAndVisible]; 
 
    return YES; 
} 
 
- (void) okButtonClicked { 
    UILabel *infoLabel = (id)[self.window viewWithTag:101]; 
    int randomIndex = arc4random() % [infos count]; 
    infoLabel.text = infos[randomIndex]; 
} 
 
@end

自定义UIButton

  为什么需要定制按钮呢,如果大家用过酷狗音乐就知道,它的播放按键是带进度提示功能的,这样的按钮肯定需要我们自行定制,看看下面的例子。

这里写图片描述

#import <UIKit/UIKit.h> 
 
/**带进度的按钮*/ 
@interface CDMyPlayButton : UIButton 
 
/**完成进度(0.0-1.0)*/ 
@property (nonatomic, assign) double value; 
 
@end
#import "CDMyPlayButton.h" 
 
@implementation CDMyPlayButton 
 
// Only override drawRect: if you perform custom drawing. 
// An empty implementation adversely affects performance during animation. 
- (void)drawRect:(CGRect)rect { 
    // Drawing code 
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init]; 
    CGFloat centerX = rect.size.width / 2.0; 
    CGFloat centerY = rect.size.height / 2.0; 
    CGFloat radius = centerX; 
    [bezierPath addArcWithCenter:CGPointMake(centerX, centerY) radius:radius * 0.8 startAngle:-M_PI_2 endAngle:M_PI * 2 * self.value - M_PI_2 clockwise:YES]; 
 
    [[UIColor cyanColor] setStroke]; 
    bezierPath.lineWidth = 2; 
    [bezierPath stroke]; 
} 
 
@end

UIImage简介

  UIImage是用来显示图像的对象。我们可以通过文件、接收到原始的数据或者Quartz图像对象来创建UIImage对象。

创建UIImage对象的方式

  • +imageNamed:类方法:根据指定的文件名返回UIImage对象
  • +imageWithData:类方法:根据指定的NSData对象创建UIImage对象
  • -imageWithContentOfFile:方法:通过文件加载指定路径下的内容获得UIImage对象
  • -imageWithCGImage:方法:通过Quartz 2D对象创建UIImage对象
  • -imageWithCIImage:方法:通过Core Image对象创建UIImage对象
    // 此种方式会对加载的图片进行单例处理,不适合动态加载大量图片,因为单例对象会一直存在于内存中 
    UIImage *image1 = [UIImage imageNamed:@"abc"]; 
 
    NSString * strPath = [[NSBundle mainBundle]  pathForResource:@"abc" ofType:@"png"]; 
    // 此方式适合本地动态加载大量图片,而且即使加载很大的图片也不会使程序崩溃,前一种方式加载大图片可能会出现问题 
    UIImage *image2 = [UIImage imageWithContentsOfFile:strPath]; 
 
    // 通过制定URL得到的数据创建图片对象 
    UIImage *image3 =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://www.baidu.com/img/bdlogo.png"]]];

  此外,还可以通过一组图片和一个持续时间来创建一个动态UIImage对象。

UIImage对象的属性

  • size属性:图像的大小,得到一个CGSize结构体,其中包括了宽度(width)和高度(height)。

绘制图像

  • -drawAtPoint:方法:从指定的左上角坐标处绘制图像。
  • -drawInRect:方法:在指定的矩形区域内绘制整个图像。

UIViewController入门

概念和作用

  UIViewController可以管理一屏的内容,如果说UIWindow是一副画的画框,那么UIViewController就是画框中植入的一张画布。我们并不建议将所有的视图对象或子视图都直接置于UIWindow对象中,因为UIWindow对象是唯一的,如果要想改变用户界面就会非常的麻烦。如果使用UIViewController来管理用户界面的话,在切换用户界面时只需要更换一个视图控制器就可以了。

  它定义了一系列和生命周期相关的方法。下面的图展示了UIViewController的生命周期,详细的内容我们在后续的课程中跟大家分享。

  视图控制器加载:
iOS开发系列课程(02) --- 视图交互和事件机制详解手机开发

  视图控制器收到内存警告:
iOS开发系列课程(02) --- 视图交互和事件机制详解手机开发

如何将UIViewController和UIWindow关联

  我们可以创建一个视图控制器并将第一个例子中在UIWindow上放置的按钮和标签放到视图控制器中,再通过UIWindow对象的rootViewController属性将视图控制器设置为窗体对象的根视图控制器,代码如下所示:

  自定义视图控制器的代码如下所示。

#import "CDRootViewController.h" 
 
@interface CDRootViewController () { 
    NSArray *infos; 
} 
 
@end 
 
@implementation CDRootViewController 
 
- (instancetype)init { 
    if(self = [super init]) { 
        infos = @[@"Hello, world!", @"How are you?", @"Nice to meet you!", @"See you!", @"Good night!"]; 
    } 
    return self; 
} 
 
- (void)viewDidLoad { 
    [super viewDidLoad]; 
 
    // 将直接放在AppDelegate中的代码转移到视图控制器中 
    // 将原来直接放到UIWindow上的视图添加到视图控制器的视图中 
    CGRect screenRect = [[UIScreen mainScreen] bounds]; 
    CGPoint centerPoint = CGPointMake(screenRect.size.width / 2.0, screenRect.size.height / 2.0); 
 
    UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)]; 
    centerPoint.y -= 50; 
    infoLabel.center = centerPoint; 
    infoLabel.textAlignment = NSTextAlignmentCenter; 
    infoLabel.font = [UIFont systemFontOfSize:36]; 
    infoLabel.text = infos[0]; 
    infoLabel.textColor = [UIColor redColor]; 
    infoLabel.tag = 101; 
    infoLabel.adjustsFontSizeToFitWidth = YES; 
 
    UIButton *okButton = [UIButton buttonWithType:UIButtonTypeSystem]; 
    okButton.frame = CGRectMake(0, 0, 80, 40); 
    centerPoint.y += 100; 
    okButton.center = centerPoint; 
    [okButton setTitle:@"OK" forState:UIControlStateNormal]; 
    okButton.layer.borderColor = [UIColor blackColor].CGColor; 
    okButton.layer.borderWidth = 1; 
    okButton.layer.cornerRadius = 5; 
    okButton.layer.shadowColor = [UIColor yellowColor].CGColor; 
    okButton.layer.shadowRadius = 10; 
 
    [okButton addTarget:self action:@selector(okButtonClicked) forControlEvents:UIControlEventTouchUpInside]; 
 
    [self.view addSubview:infoLabel]; 
    [self.view addSubview:okButton]; 
} 
 
- (void) okButtonClicked { 
    UILabel *infoLabel = (id)[self.view viewWithTag:101]; 
    int randomIndex = arc4random() % [infos count]; 
    infoLabel.text = infos[randomIndex]; 
 
    [UIView beginAnimations:nil context:nil]; 
    [UIView setAnimationDuration:0.5]; 
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view cache:YES]; 
    [UIView commitAnimations]; 
} 
 
@end

  AppDelegate的代码如下所示。

#import "AppDelegate.h" 
#import "CDRootViewController.h" 
 
@interface AppDelegate () 
 
@end 
 
@implementation AppDelegate 
 
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
 
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; 
    self.window.backgroundColor = [UIColor whiteColor]; 
 
    // 创建视图控制器对象 
    CDRootViewController *rvc = [[CDRootViewController alloc] init]; 
    // 将视图控制器设置为窗口的根视图控制器 
    self.window.rootViewController = rvc; 
 
    [self.window makeKeyAndVisible]; 
 
 
    return YES; 
} 
@end

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/app/5330.html

(0)
上一篇 2021年7月16日 23:42
下一篇 2021年7月16日 23:42

相关推荐

发表回复

登录后才能评论