AppleWatch___学习笔记(二)UI布局和UI控件
1.UI布局
直接开发,你会发现Apple Watch并不支持AutoLayout,WatchKit里有个类叫做WKInterfaceGroup,乍一看像是UIView,但是这货其实是用来布局的。从 Storyboard中拉一个WKInterfaceGroup出来,在属性检查器(Attributes Inspector)中有个Layout属性,通过设置成Horizontal或Vertical,就可以让这个group下所有的子视图水平排列或竖直排列。再结合AutoLayout的知识,就可以轻松满足要求啦。
首先,watch的屏幕不大,目前只有38mm和42mm两个尺寸,我们不可能在 这个有限的空间里做非常复杂的界面效果,因此,在界面开发中,应该遵循便于使用和一目了然的原则。watch上的布局方式采用的是一种平面堆放的方式,不再有frame,也不再有约束,控件的布局方式只是一个挨着一个的平面堆放,也不可重叠。但在watch中,提供了group这样一种布局方式,可以让我 们在布局中体现自由与个性的方面。具体如何使用呢?
(1)首先简单布局介绍
就是我们在不使用group的时候,watch的布局采用的是最基础的堆放方式,从上到下依次排开,例如,我们添加四个label,效果如下:

通过改变label的添加顺序,可以改变其上下位置:

这种方式的布局高度并没有限制,我们可以一直往下排列,在watch上,会出现滑动的效果:

(2)使用Group进行复杂的界面布局
通过上面的布局方式,我们只能进行纵向的排列布局,这并不能达到我们的需求,WatchKit中提供那一套布局的模型:Group。
可以这样理解,group就是将屏幕分成了几各分区,我们可以设置各个分区的排列方式,例如水平或者垂直,通过这样的思路,完成复杂的watch界面布局,例如下面的效果:

这样效果的一个界面,就是将在屏幕中添加了三个Group,最上面的Gorup设置为水平排列模式,在其中添加了两个按钮和一个分割线,中间一个Group是垂直排列模式,放入了一个选择器和一个按钮,最下面一个Group也是水平排列模式,放入了一个按钮和一个时间栏。 Group在界面布局上,不仅可以起到分区屏幕的作用,其还可以设置一些属性来使布局更加漂亮。在storyBoard右侧的设置菜单中,我们可以对这些属性进行操作:
Layout:设置布局模式,分为水平布局和垂直布局两种
insert:可以设置内容区域偏移量,通过这个属性,我们可以使其中填充的控件四周留白
Spacing:其中填充的控件的间距
BackGround:设置Group的背景图案
Mode:设置背景图案的填充方式
Animate:出现时带动画
color:设置Group的背景颜色
Radius:设置Group的圆角度
(3)布局中控件的位置和尺寸设置
在iphone中,我们使用frame或者约束来控制控件的位置和尺寸,在watch中则简单很多,尺寸和位置都是固定的模式,我们只需要做一些设置即可。
1、控件尺寸的控制
对于控件的尺寸,有三种模式,控件的width和Height都是通过这三个模式设置的:
Relative to Container:自身的尺寸是按照容器的尺寸比例设置的。例如设置为0.5的话,当前控件的尺寸就是容纳其Group的一半。
Size To Fit Content:自身的尺寸与自身内容相关,例如,label中字数的多少决定了label的尺寸。
Fixed:手动设置一个固定的值。
2、控件位置的控制
因为watch的界面十分简洁,对于控件的位置设置,是通过水平和垂直两个维度来设置的,通过设置每个维度的属性来控制其在容纳它的Group中的位置:
Horizontal:left(左),center(中心),right(右)
Vertical:top(上),center(中心),bottom(下)
注意:
关于图片素材,你可以发现,在Extension和App文件夹中各有一个Assets.xcasssets组,只有将素材放入APP文件夹下的这个组watch才能使用。

2.UI控件
(1)Table
WatchKit中的 WKInterfaceTable不同于UITableView,没有dataSource和delegate,只能通过主动方式填充并展现数据。对应每 一种不同类型的cell,都需要为它构造一个rowController(继承自NSObject),这个rowController负责往这种类型的 row中填充需要展现的内容。
方法如下:
- -(id)rowControllerAtIndex:(NSInteger)index;
通过调用这个方法得到指定行的rowController,再调用这个rowController的自定义方法来进行渲染。例如:
- - (void)configureRowWithDataModel:(id)dataModel;
另外,如果要插入行和删除行,则要在上述操作之前先调用:
- -(void)insertRowsAtIndexes:(NSIndexSet *)rows withRowType:(NSString *)rowType;
- -(void)deleteRowsAtIndexes:(NSIndexSet *)rows;
注意:在iOS开发中如果要刷新UITableView,只要更新数据源后再调用reloadData方法就可以。但是就像之前说 的,WKInterfaceTable并没有主动刷新数据的方法,只能通过调用 [table setRowTypes:nil] 方法先清除所有数据,再用新数据源重新填充一遍。仅仅是这样就算了,假设你现在视图控制器A中,然后被push到了视图控制 器B,那么如果你在B中刷新A中的WKInterfaceTable是没有用的。但是不是完全没用,经过多次测试,我发现,数据源确实是被更新了,但是界 面上的内容并没有刷新。也就是说,数据源和界面没有保持一致。暂时的解决方法是,在需要刷新的时候记录一个标记位,然后在willActivate的时候根据这个标记位进行延时刷新。一个很明显的副作用就是刷新时会产生跳动,相信之后的版本Apple应该会修复这个问题。
WatchOS中的TableView和iOS中的TableView还是有很大的区别,在开发之前,首先我们应该明白WatchOS中的Table有哪些局限性和特点。下面几点是我总结WatchOS中Table的特殊之处:
1、Table只有行的概念,没有分区的概念,没有头尾视图的概念。
2、可以通过创建多个Table,来实现分区的效果。
3、因为Watch上是通过Gruop进行布局适应的,所以没有行高等设置。
4、Table没有代理,所有行的数据都是采用静态配置的方式。
5、点击Table中的行触发的方法,是通过重写Interface中的方法来实现的。
(2)创建一个Table
在storyBoard中拖入你的Table(想要纯代码就不行了),如下:

在Table上拉两个label:

每一个Table中包含一个TableRowController,实际上我们Table上的控件都是通过这个TableRowController进行管理的,因此如果我们需要在代码中控制TableRow上的内容,我们需要创建一个文件作为Table的TableRowController:

将storyBoard中TableRowController的类修改为我们创建的类并指定一个identifier:


然后,我们将两个label关联到TableRowController中:
|
1
2
3
4
5
6
|
import WatchKitclass TableRowController: NSObject { @IBOutlet var numberLabel: WKInterfaceLabel! @IBOutlet var titleLabel: WKInterfaceLabel!} |
将Table关联到interfaceController中:
|
1
2
3
4
5
|
class InterfaceControllerMain: WKInterfaceController { @IBOutlet var Table: WKInterfaceTable!} |
下面,我们开始在interface中对Table做相关配置,首先我们可以先观察一下WKInterfaceTable中有哪些方法和属性:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class WKInterfaceTable : WKInterfaceObject { //设置行的类型,数组中对应存放行的类型,数组元素的个数,就是行数 /* 通过这个方法,我们可以创建每一行样式都不同的table,行的类型 实际上就是我们刚才用到的TableRowController,我们可以进行自定义 */ public func setRowTypes(rowTypes: [String]) //设置行数和类型 用于创建单一行类型的table public func setNumberOfRows(numberOfRows: Int, withRowType rowType: String) // repeating row name //这个get方法获取行数,用于我们遍历table中的行,进行内容设置 public var numberOfRows: Int { get } //这个方法会返回某一行,我们可以获取到后进行内容设置 public func rowControllerAtIndex(index: Int) -> AnyObject? //插入一行 public func insertRowsAtIndexes(rows: NSIndexSet, withRowType rowType: String) //删除一行 public func removeRowsAtIndexes(rows: NSIndexSet) //滑动到某一行 public func scrollToRowAtIndex(index: Int)} |
了解了上面的方法,可以看出,WatchOS的Table配置非常简单易用,例如我们如下配置:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@IBOutlet var Table: WKInterfaceTable! override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) let dic:Dictionary<String,String> = ["中国建设银行":"¥1000","中国农业银行":"¥5000","中国银行":"20000","招商银行":"¥401","中国邮政储蓄":"1100"] //设置行数与类型 Table.setNumberOfRows(dic.count, withRowType: "TableRowController") //遍历进行设置 let titleArray:Array<String> = Array(dic.keys) for var i=0 ; i < dic.count ; i++ { let row:TableRowController = Table.rowControllerAtIndex(i) as! TableRowController row.titleLabel.setText(titleArray[i]) row.numberLabel.setText(dic[titleArray[i]]) row.numberLabel.setTextColor(UIColor.grayColor()) } // Configure interface objects here. } |
这样一个展示银行卡余额的界面我们就创建完成了,效果如下:

(3)关于Table的点击事件
上面我们提到,Table没有所谓代理方法,点击row的时候,我们也是通过两种方式进行逻辑跳转的,一种是在storyBoard中,我们通过拉线跳转,这时如需传值,我们需在interface中实现如下方法:
|
1
|
public func contextForSegueWithIdentifier(segueIdentifier: String, inTable table: WKInterfaceTable, rowIndex: Int) -> AnyObject? |
另一种方式,我们可以重写实现InterfaceController中的如下方法,来处理Table的点击事件:
|
1
|
public func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) |
无论哪种方式,我们都可以通过参数table和rowIndex来确认点击的具体是那个table和哪一行,进行传值和处理我们的逻辑。
AppleWatch___学习笔记(二)UI布局和UI控件的更多相关文章
- IOS学习笔记(四)之UITextField和UITextView控件学习
IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...
- .NET MVC 学习笔记(七)— 控制input控件
.NET MVC 学习笔记(七)— 控制input控件 画面中有时候需要输入数字,这时就需要控制input的输入.以下为保留两位有效数字. /* * 初始化数字输入 */ function initD ...
- Winform控件学习笔记【第二天】——常用控件
背景:期末考试刚过就感冒了,嗓子火辣辣的,好难受.但是一想起要学习总结就打起精神来了,Winform控件网上也没有多少使用教程,大部分都是自己在网上零零散散的学的,大部分用的熟了,不总结会很容易忘得. ...
- Android Studio 学习笔记(二):布局简介和xmlns说明
初学Android Studio,是在b站看的教程视频,这里的笔记也是以其为基础的,个人强烈安利: [天哥]Android开发视频教程最新版 Android Studio开发 Android 布局简介 ...
- Dynamic CRM 2013学习笔记(八)过滤查找控件 (类似省市联动)
我们经常要实现类似省市联动一样的功能,常见的就是二个查找控件,一个选择了省后,另一个市的查找控件就自动过滤了,只显示当前省下的市,而不是所有的市.当然这是最简单的,实际工作中还有更复杂的功能要通过过滤 ...
- 【AngularJS学习笔记】封装一些简单的控件(封装成Html标签)
bootstrap有强大的指令系统,可以自定义一些属性,基本知识请移步:http://angularjs.cn/A00r http://www.cnblogs.com/lvdabao/p/33916 ...
- 张高兴的 Xamarin.Android 学习笔记:(四)常用控件
示例地址 GitHub : https://github.com/ZhangGaoxing/xamarin-android-demo/tree/master/ControlsDemo
- Windows程序设计学习笔记(四)自绘控件与贴图的实现
Windows系统提供大量的控件供我们使用,但是系统提供的控件样式都是统一的,不管什么东西看久了自然会厌烦,为了使界面更加美观,添加一些新的东西我们需要自己绘制控件. 控件在默认情况下并不进行自绘,如 ...
- Win32+API学习笔记:创建基本的窗口控件
创建一个标签 CreateWindowEx(0, "static", "姓名:", ...
- Vue.js学习笔记 第七篇 表单控件绑定
本篇主要说明表单控件的数据绑定,这次没有新的知识点 文本框 1.普通文本框 <div id="app-1"> <p><input v-model=&q ...
随机推荐
- HTML静态网页 Window.document对象
一.找到元素: docunment.getElementById("id"):根据id找,最多找一个: var a =docunment.getElementById(&qu ...
- c# 结构体、枚举类型及函数调用
一.结构体 结构体:就是一个自定义的集合,里面可以放各种类型的元素,用法大体跟集合一样. 枚举类型和结构体都属于值类型. 二.枚举类型 1.枚举类型之针对字符串,对于索引,无意义2.常量的集合,这些常 ...
- wampserver的php.ini文件
在修改php.ini文件时,找到了php文件夹下的php.ini文件,但是重启所有服务后就是不起作用.查看前辈的博客后,明白了是在apache目录下的php.ini才是起作用的. .
- .net下Ueditor配置(主要讲解上传功能配置)
Ueditor上传功能配置——.net 今天项目中用到Ueditor就自己配置了下,但上传功能和图片显示功能不能正确使用,就自己琢磨了下.已实现上传功能,并能显示正确的图片和文件,在线编辑功能也能使用 ...
- Struts和SpringMVC两种MVC框架比较
基于Web的MVC framework在J2EE的世界内已是空前繁荣.TTS网站上几乎每隔一两个星期就会有新的MVC框架发布.目前比较好的MVC,老牌的有Struts.Webwork.新兴的MVC框架 ...
- 一篇很全面的freemarker教程
以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:1,文本:直接输出的部分2,注释:<#-- ... --& ...
- 在win7下安装unbuntu系统
1.分盘 准备EasyBCD,ubuntu操作系统 配置EasyBCD,安装ubuntu http://www.linuxidc.com/Linux/2014-04/100369.htm http:/ ...
- Android课程---关于对话框的学习
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- 手机端开发icon的问题
一般来说,手机端的图片能用字体(字体小的情况下)的话,效果更好,因为不受图片缩放的失真影响. 但是有时,用位图的话,图片材料要高清晰,用jpg的高质量. 另外,有彩图与灰度图的情况下,考虑使用css3 ...
- Tomcat负载均衡配置-未完成
集群技术是目前非常流行的提高系统服务能力与高可靠性( HA- High Availability )的手段,通过把多个独立的服务器组成一个集群可以实现失效无缝转移.也就是说当有某一台集群中的服务器当机 ...