疯狂ios讲义之代码控制UI界面

简介:

通过前面的介绍我们已经了解了iOS开发的基本方法和步骤实际上只要掌握了这些基本的方法和步骤我们就可以对iOS应用进行更多的控制。前面介绍的开发方式是使用xib或Storyboard文件设计iOS应用界面这也是iOS开发的最主要方式在某些极端的情况下我们也有可能不使用任何界面设计文件直接通过代码来开发UI界面。


9.5.1  不使用界面布局文件开发UI界面


如果打算使用纯代码来开发UI界面则不需要设计任何界面布局文件没有界面布局文件也就不再需要使用自定义的视图控制器。这样程序可以直接在应用程序委托对象的application: didFinishLaunchingWithOptions:方法中创建UIWindow和应用程序界面——所有这些对象的创建都使用objective-C代码来完成。


实例无界面布局文件开发iOS应用


首先创建一个iOS的Empty Application应用。在创建iOS应用时选择“Empty Application”项即可如图9.35所示。


1390204145

                        图9.35 创建iOS的EmptyApplication应用


对于“Empty Application”类型的iOS应用Xcode只生成应用程序委托类不会生成任何界面设计文件也不会生成任何控制器类。


对于打算使用纯代码开发UI界面的开发方式来说我们的应用并不需要任何界面设计文件也不需要任何控制器。程序只要修改应用程序委托的application:didFinishLaunchingWithOptions:方法并在该方法中创建UI控件然后利用这些UI控件搭建应用程序界面即可。下面是修改过的application:didFinishLaunchingWithOptions:方法代码。


程序清单codes/09/9.5/CodeUI/ CodeUI/FKAppDelegate.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 应用程序加载完成后将会自动回调该方法
- ( BOOL )application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
     // 创建UIWindow对象并将该UIWindow初始化为与屏幕相同大小
     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
     // 设置UIWindow的背景色
     self.window.backgroundColor = [UIColor whiteColor];
     // 创建一个UIViewController对象
     UIViewController* controller = [[UIViewController alloc] init];
     // 让该程序的窗口加载并显示viewController视图控制器关联的用户界面
     self.window.rootViewController = controller;
     // 创建一个UIView对象
     UIView* rootView = [[UIView alloc] initWithFrame
         :[[UIScreen mainScreen] bounds]];
     // 设置controller显示rootView控件
     controller.view = rootView;
     // 创建一个圆角按钮
     UIButton* button = [UIButton buttonWithType: UIButtonTypeRoundedRect];
     // 设置按钮的大小
     button.frame = CGRectMake(120, 100, 80, 40);
     // 为按钮设置文本
     [button setTitle:@ "确定"  forState:UIControlStateNormal];
     // 将按钮添加到rootView控件中
     [rootView addSubview:button];
     // 创建一个UILabel对象
     self.show = [[UILabel alloc] initWithFrame
         :CGRectMake(60 , 40 , 180 , 30)];
     // 将UILabel添加到rootView控件中
     [rootView addSubview:self.show];
     // 设置UILabel默认显示的文本
     self.show.text = @ "初始文本" ;
     self.show.backgroundColor = [UIColor grayColor];
     // 为圆角按钮的触碰事件绑定事件处理方法
     [button addTarget:self action:@selector(clickHandler:)
         forControlEvents:UIControlEventTouchUpInside];
     // 将该UIWindow对象设为主窗口并显示出来
     [self.window makeKeyAndVisible];
     return  YES;
}

上面的代码中首先创建了一个UIWindow作为应用程序的窗口接下来创建一个UIView作为UIWindow显示的根视图需要借助一个UIViewController对象。


一旦程序中有了UIView作为容器接下来代码归纳起来相当于只有三行此处的三行是一种归纳说法并非实际只有三行。


创建UI控件比如创建UILabel丶创建UIButton等。


调用addSubView:方法将UI控件添加到其他容器中。


多次调用UI控件的setter方法来设置UI控件的外观丶行为。


上面代码中为按钮的触碰事件绑定了clickHandler:事件处理方法因此程序还需要在应用程序委托类中定义该方法。方法代码如下


程序清单codes/09/9.5/CodeUI/ CodeUI/FKAppDelegate.m

1
2
3
4
- ( void ) clickHandler:(id)sender
{
     self.show.text = @ "开始学习iOS吧" ;
}

上面的代码只是简单地修改show控件的文本内容这样即可实现当用户触碰按钮时动态改变show控件的文本内容。


运行该程序单击程序中的按钮即可看到如图9.36所示的效果。


通过上面的开发过程可以发现不管是通过纯代码来创建UI控件再将这些UI控件搭建成程序界面还是使用界面设计文件来搭建程序界面其本质是相同的。它们的本质都是把UI控件当成小的积木块然后将这些“积木块”按自己的意愿组合在一起就可以做成iOS应用的程序界面了。


需要指出的是使用纯代码方式来开发iOS应用并不是最好的开发方式这种方式不仅开发步骤异常烦琐而且所有创建程序界面的代码都由应用程序委托对象的方法负责完成这并不符合MVC设计原则因此不利于程序组件的解耦。通过学习这种开发方式我们可以更好地理解iOS应用中应用程序委托的作用同时也能更好地理解iOS程序界面的底层实现原理。


下面介绍一种更实用的代码方式开发UI界面。


9.5.2  使用代码创建UI界面


更实际的情况是在程序运行开始时程序已经具有一个初始的程序界面初始界面可能只包含一个UIView在程序运行过程中程序需要根据用户交互来动态添加丶删除UI控件。


在这种需求下我们可以通过Interface Builder来设计程序的初始界面接下来在程序运行过程中可以通过代码创建UI控件再将UI控件添加到相应的父控件中即可。


实例动态添加丶删除标签


首先创建一个iOS的Single View Application应用创建完成后该应用将自带一个Main.storyboard界面设计文件但我们并不打算修改该界面设计文件而是直接在程序代码中创建整个UI界面程序只使用该界面文件中的UIView作为容器即可。


接下来修改控制器类在控制器类的实现部分创建整个程序界面绑定事件处理方法。下面是控制类的实现部分代码。


程序清单codes/09/9.5/DynaLabel/DynaLabel/FKViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#import "FKViewController.h"
// 定义FKViewController的扩展
@interface FKViewController ()
// 定义一个属性来记录所有动态添加的UILabel控件
@property (nonatomic, strong) NSMutableArray* labels;
@end
@implementation FKViewController
// 定义一个变量来记录下一个将要添加的UILabel的位置
int  nextY = 80;
- ( void )viewDidLoad
{
     [super viewDidLoad];
     // 设置该view的背景色
     self.view.backgroundColor = [UIColor grayColor];
     // 初始化labels数组
     self.labels = [NSMutableArray array];
     // 创建UIButtonTypeRoundedRect类型的UIButton对象
     UIButton* addBn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     // 设置addBn的大小和位置
     addBn.frame = CGRectMake(30, 30, 60, 40);
     // 为UIButton设置按钮文本
     [addBn setTitle:@ "添加"
         forState:UIControlStateNormal];
     // 为addBn的Touch Up Inside事件绑定事件处理方法
     [addBn addTarget:self action:@selector(add:)
         forControlEvents:UIControlEventTouchUpInside];
     // 创建UIButtonTypeRoundedRect类型的UIButton对象
     UIButton* removeBn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     // 设置removeBn的大小和位置
     removeBn.frame = CGRectMake(230, 30, 60, 40);
     // 为UIButton设置按钮文本
     [removeBn setTitle:@ "删除"
         forState:UIControlStateNormal];
     // 为removeBn的Touch Up Inside事件绑定事件处理方法
     [removeBn addTarget:self action:@selector( remove :)
         forControlEvents:UIControlEventTouchUpInside];
     [self.view addSubview:addBn];
     [self.view addSubview:removeBn];
}
- ( void )add:(id)sender {
     // 创建一个UILabel控件
     UILabel* label = [[UILabel alloc] initWithFrame:
         CGRectMake(80, nextY, 160, 30)];
     label.text = @ "疯狂iOS讲义" ;   // 设置该UILabel显示的文本
     [self.labels addObject: label];   // 将该UILabel添加到labels数组中
     [self.view addSubview:label];   // 将UILabel控件添加到view父控件内
     nextY += 50;   // 控制nextY的值加50
}
- ( void ) remove :(id)sender {
     // 如果labels数组中元素个数大于0表明有UILabel可删除
     if ([self.labels count] > 0)
     {
         // 将最后一个UILabel从界面上删除
         [[self.labels lastObject] removeFromSuperview];
         [self.labels removeLastObject];   // 从labels数组中删除最后一个元素
         nextY -= 50;   // 控制nextY的值减50
     }
}
@end

上面的代码中第一段粗体字代码创建了应用的初始界面该初始界面只包含两个按钮并且程序还为这两个按钮绑定了事件处理方法。


该应用的关键就是实现add:和remove:两个方法其中add:方法中粗体字代码负责创建一个UILabel控件每次创建的UILabel的Y坐标并不相同并将这个UILabel控件添加到该控制器关联的UIView内。这样即可实现每次用户触碰该按钮程序界面就会添加一个UILabel控件而remove:方法中粗体字代码则负责把labels数组的最后一个元素UILabel控件从父控件中删除并从该数组中删除该元素。


通过上面的程序即可实现通过用户交互来动态添加丶删除程序界面控件。编译丶运行该程序并多次触碰添加丶删除按钮后可能看到如图9.37所示的动态界面。

1390204222


9.5.3  自定义UI控件


UIView控件只是一个矩形的空白区域并没有任何内容。iOS应用的其他UI控件都继承了UIView这些UI控件都是在UIView提供的空白区域上绘制外观。


基于UI控件的实现原理开发者完全可以开发出项目定制的控件——当iOS系统提供的UI控件不足以满足项目需要时开发者可以通过继承UIView来派生自定义控件。


当开发者打算派生自己的UI控件时首先定义一个继承View基类的子类然后重写View类的一个或多个方法通常可以被用户重写的方法如下。


initWithFrame:前面已经见到程序创建UI控件时常常会调用该方法执行初始化因此如果你需要对UI控件执行一些额外的初始化即可通过重写该方法来实现。


initWithCoder:程序通过在nib文件中加载完该控件后会自动调用该方法。因此如果程序需要在nib文件中加载该控件后执行自定义初始化则可通过重写该方法来实现。


drawRect:如果程序需要自行绘制该控件的内容则可通过重写该方法来实现。


layoutSubviews如果程序需要对该控件所包含的子控件布局进行更精确的控制可通过重写该方法来实现。


didAddSubview:当该控件添加子控件完成时将会激发该方法。


willRemoveSubview:当该控件将要删除子控件时将会激发该方法。


willMoveToSuperview:当该控件将要添加到其父控件中时将会激发该方法。


didMoveToSuperview当把该控件添加到父控件完成时将会激发该方法。


willMoveToWindow: 当该控件将要添加到窗口中时将会激发该方法。


didMoveToWindow当把该控件添加到窗口完成时将会激发该方法。


touchesBegan:withEvent:当用户手指开始触碰该控件时将会激发该方法。


touchesMoved:withEvent:当用户手指在该控件上移动时将会激发该方法。


touchesEnded:withEvent:当用户手指结束触碰该控件时将会激发该方法。


touchesCancelled:withEvent:用户取消触碰该控件时将会激发该方法。


当需要开发自定义View时开发者并不需要重写上面列出的所有方法而是根据业务需要重写上面的部分方法。例如下面的跟随手指运动的小球示例程序就只重写drawRect:方法。


实例跟随手指运动的小球


为了实现一个跟随手指运动的小球示例我们考虑开发自定义的UI控件这个UI控件将会在指定位置绘制一个小球这个位置可以动态改变。当用户通过手指在屏幕上拖动时程序监听到这个手指动作并把手指动作的位置传入自定义UI控件然后通知该控件重绘即可。


首先创建一个Single View Application然后通过该应用的项目导航面板打开Main.storyboard文件选中Dock区内唯一场景内的View Controller节点或选中界面布局文件中的根UI控件UIView也就是界面中大块的丶右上角有个电池图标的白色矩形区域然后按下键盘上的command+option+3快捷键打开Xcode的身份检查器通过身份检查器可以看到该界面布局文件的根UI控件的实现类是UIView如图9.38所示。


该应用并不打算使用默认的UIView作为根控件因此将图9.38所示对话框中Class文本框内的实现类改为FKCustomView这表明程序将使用FKCustomView作为界面设计的根控件。


接下来程序需要开发自定义的FKCustomView类其步骤如下。


①用鼠标右键单击项目文件夹然后单击“New File”菜单项Xcode弹出如图9.39所示的对话框。

《疯狂ios讲义》疯狂连载之代码控制UI界面22

图9.38 通过身份检查器面板管理UI控件的实现类



1390204287

 图9.39 创建objective-C类

                    


②在图9.39所示对话框的左边选中iOS分类下的Cocoa Touch然后在对话框右边选中“objective-Cclass”列表项后单击“Next”按钮系统显示如图9.40所示的对话框。

1390204300

图9.40  确定类名和父类


③在图9.40所示的对话框中输入类名选择父类之后单击“Next”按钮Xcode将会显示一个保存文件夹用于确定新创建文件的存储路径。选择合适的路径后单击“Create”按钮即可创建一个新的objective-C类。

下面是自定义控件类实现部分的代码接口部分仅仅只是继承UIView即可。


程序清单codes/09/9.5/CustomView/CustomView/FKCustomView.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#import "FKCustomView.h"
@implementation FKCustomView
// 定义两个变量记录当前触碰点的坐标
int  curX;
int  curY;
- ( void ) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     // 获取触碰事件的UITouch事件
     UITouch *touch = [touches anyObject];
     // 得到触碰事件在当前组件上的触碰点
     CGPoint lastTouch = [touch locationInView:self];
     // 获取触碰点的坐标
     curX = lastTouch.x;
     curY = lastTouch.y;
     // 通知该组件重绘
     [self setNeedsDisplay];
}
// 重写该方法来绘制该UI控件
- ( void )drawRect:(CGRect)rect
{
     // 获取绘图上下文
     CGContextRef ctx = UIGraphicsGetCurrentContext();
     // 设置填充颜色
     CGContextSetFillColorWithColor(ctx, [[UIColor redColor] CGColor]);
     // 以触碰点为圆心绘制一个圆形
     CGContextFillEllipseInRect(ctx, CGRectMake(curX - 10, curY - 10, 20, 20));
}
@end

上面的程序自定义了UIView的子类FKCustomView该子类重写了drawRect:方法该方法的逻辑很简单它仅仅只是以触碰点为圆心绘制一个圆形。除此之外该自定义UIView子类还重写了touchesMoved方法每当用户触碰该组件时程序就会将触碰点的坐标赋给curX丶curY两个变量并通知该控件调用drawRect:方法来重绘自身。这样即可保证每当用户触碰该控件时该控件总会在触碰点绘制一个红色圆形。


编译丶运行该程序即可看到如图9.41所示的效果。

1390204380




——本文节选自《疯狂ios讲义上》



 

本文转自 fkJava李刚 51CTO博客,原文链接:http://blog.51cto.com/javaligang/1353339 ,如需转载请自行联系原作者

相关文章
|
2月前
|
计算机视觉 Python
基于Dlib的人脸识别客户端(UI界面)
基于Dlib的人脸识别客户端(UI界面)
63 2
|
1月前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
97 8
|
2月前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
2月前
|
机器学习/深度学习 数据可视化 计算机视觉
基于opencv的车牌识别系统(UI界面采用tkinter设计)
基于opencv的车牌识别系统(UI界面采用tkinter设计)
43 0
|
4月前
|
编解码 前端开发 vr&ar
从零开始的PICO教程(4)--- UI界面绘制与响应事件
这篇文章是PICO开发系列教程的第四部分,主要介绍了如何在PICO 4 VR环境中创建UI界面,包括Canvas和Panel的配置、UI元素的绘制、以及Button和Slider的事件响应绑定,并通过示例展示了数字增减和滑块功能的具体实现。
从零开始的PICO教程(4)--- UI界面绘制与响应事件
|
3月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
随着移动应用市场的蓬勃发展,用户对界面设计的要求日益提高。为此,掌握由Google推出的Material Design设计语言成为提升应用颜值和用户体验的关键。本文将带你深入了解Material Design的核心原则,如真实感、统一性和创新性,并通过丰富的组件库及示例代码,助你轻松打造美观且一致的应用界面。无论是色彩搭配还是动画效果,Material Design都能为你的Android应用增添无限魅力。
73 1
|
4月前
|
C# 开发者 设计模式
WPF开发者必读:命令模式应用秘籍,轻松简化UI与业务逻辑交互,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,命令模式是简化UI与业务逻辑交互的关键技术,通过将请求封装为对象,实现UI操作与业务逻辑分离,便于代码维护与扩展。本文介绍命令模式的概念及实现方法,包括使用`ICommand`接口、`RelayCommand`类及自定义命令等方式,并提供示例代码展示如何在项目中应用命令模式。
53 0
|
4月前
|
容器 iOS开发 Linux
震惊!Uno Platform 响应式 UI 构建秘籍大公开!从布局容器到自适应设计,带你轻松打造跨平台完美界面
【8月更文挑战第31天】Uno Platform 是一款强大的跨平台应用开发框架,支持 Web、桌面(Windows、macOS、Linux)及移动(iOS、Android)等平台,仅需单一代码库。本文分享了四个构建响应式用户界面的最佳实践:利用布局容器(如 Grid)适配不同屏幕尺寸;采用自适应布局调整 UI;使用媒体查询定制样式;遵循响应式设计原则确保 UI 元素自适应调整。通过这些方法,开发者可以为用户提供一致且优秀的多设备体验。
173 0
|
4月前
|
测试技术 Swift iOS开发
探索iOS自动化测试:使用Swift编写UI测试
【8月更文挑战第31天】在软件开发的海洋中,自动化测试是保证船只不偏离航线的灯塔。本文将带领读者启航,深入探索iOS应用的自动化UI测试。我们将通过Swift语言,点亮代码的灯塔,照亮测试的道路。文章不仅会展示如何搭建测试环境,还会提供实用的代码示例,让理论知识在实践中生根发芽。无论你是新手还是有经验的开发者,这篇文章都将是你技能提升之旅的宝贵指南。
|
5月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
【7月更文挑战第28天】随着移动应用市场的发展,用户对界面设计的要求不断提高。Material Design是由Google推出的设计语言,强调真实感、统一性和创新性,通过模拟纸张和墨水的物理属性创造沉浸式体验。它注重色彩、排版、图标和布局的一致性,确保跨设备的统一视觉风格。Android Studio提供了丰富的Material Design组件库,如按钮、卡片等,易于使用且美观。
159 1