iOS开发——UI篇OC篇&UIStackView详解
UIStackView详解
一、继承关系、遵守协议、隶属框架及可用平台
UIStackView 类提供了一个高效的接口用于平铺一行或一列的视图组合。Stack视图使你依靠自动布局的能力,创建用户接口使得可以动态的调整设备朝向、屏幕尺寸及任何可用范围内的变化。Stack视图管理着所有在它的 arrangedSubviews 属性中的视图的布局。这些视图根据它们在 arrangedSubviews 数组中的顺序沿着 Stack 视图的轴向排列。精确的布局变量根据 Stack 视图的 axis , distribution , alignment , spacing , 和其它属性共同决定。
使用 stack 视图,打开一个你希望编辑的 Storyboard,从对象库中拖拽出一个 Horizontal Stack View 或者一个 Vertical Stack View,并放置到你希望的位置上。下一步,将控件或视图拖拽放置到 stack 中,如果需要你可以继续添加视图或者控件给指定的 stack。Interface Builder 将根据 stack 的内容自动调节尺寸。你也可以通过修改属性面板中 Stack视图的属性调整 stack 内容的外观。
注意:你需要负责指定 stack 视图的位置和尺寸(可选的)。然后 stack 视图将管理其内容的布局和尺寸。
二、Stack 视图与自动布局
Stack 视图使用自动布局来定位和控制其管理的视图的尺寸。stack 视图沿着它的轴向拼凑第一个和最后一个被管理视图,使其边界平齐。对于一个水平 stack 视图,这意味着第一个被管理视图的左边界是与 stack 的左边界平齐的,并且最后一个被管理视图右边界与 stack的右边界平齐。对于垂直 stack,上边界和下边界是各自平齐的。如果你设置了 stack 视图的 layoutMarginsRelativeArrangement 属性为 YES,stack 视图将使用相关的边距与其内容对齐,而不是边界。
对于除去 UIStackViewDistributionFillEqually 分布以外的分布方式,stack 视图使用被管理视图的 intrinsicContentSize 属性来计算沿着 stack 轴向的视图尺寸。 UIStackViewDistributionFillEqually 分布将调节所有被管理视图的在 stack 轴向上拥有相同尺寸,以填充 stack 视图。如果可能,stack 视图将拉伸所有被管理视图,来匹配其在 stack 轴向上最长的原有尺寸(译注:保证长宽比的情况下根据 stack 轴向长度拉伸视图)。
对于除去 UIStackViewAlignmentFill 对齐方式以外的对齐方式,stack 视图使用其管理的视图的 intrinsicContentSize 属性来计算视图垂直于 stack 轴向的尺寸。 UIStackViewAlignmentFill 重新调节了所有其管理的视图,使这些视图填充 stack 视图垂直于其轴向空间。如果可能,stack 视图将拉伸其所有管理的视图来匹配其垂直于 stack 轴向的最大固有尺寸。
三、定位和调整 Stack 视图尺寸
当 Stack 视图允许你布局其内容而不直接使用自动布局,你将仍然需要使用自动布局来定位 stack 视图。通常情况下,这意味着需要拼凑至少两个边界相邻的stack来定义它的位置。没有额外约束的情况下,系统会为 stack 视图计算一个尺寸来适应其内容:
· 沿着 stack 视图轴向,其适应尺寸等于其管理的视图尺寸与间距的和;
· 垂直于 stack 视图轴向,其适应尺寸等于其管理的视图中最大的视图的尺寸;
· 如果 stack 视图的
layoutMarginsRelativeArrangement
属性设置为 YES,stack 视图的适应尺寸会包括边距空间。
你可以提供额外的约束来具体说明 stack 视图的高度、宽度或者两者兼有。在这些情况下,stack 视图调整了其管理的视图的布局和尺寸来填充指定区域。精确的布局变量根据 stack 视图的属性获得。可以通过查看 UIStackViewDistribution 和 UIStackViewAlignment 枚举,以获得一个完整的 stack 视图在其内容空间多余或空间不足情况下的处理描述。
你也可以根据 stack 视图的第一条或最后一条基线定位它,而不是使用顶部、底部或者中心的Y值。类似于 stack 视图的适应尺寸,这些基线都是基于 stack 视图的内容计算得到的。
· 一个水平的 stack 视图调用 viewForFirstBaselineLayout 方法或 viewForLastBaselineLayout 方法时返回它最高的视图。如果最高的视图也是一个 stack 视图,那么其返回的将是在嵌套的 stack 视图上调用 viewForFirstBaselineLayout 方法或 viewForLastBaselineLayout 方法的结果。
· 一个垂直的 stack 视图当调用 viewForFirstBaselineLayout 方法时返回的是其管理的第一个视图,当调用 viewForLastBaselineLayout 方法时返回的是其管理的最后一个视图。如果这两个视图之一也是 stack 视图,那么其返回的将是在嵌套的 stack 视图上对应调用 viewForFirstBaselineLayout 方法或 viewForLastBaselineLayout 方法的结果。
注意:基线对齐方式只作用于那些高度匹配其原本内容高度的视图。如果视图被拉伸或压缩过,那么基线将出现在错误的位置上。
四、通用 Stack 视图布局
这有一些通用方法用于 stack 视图。这个清单是要高亮一些有用的示例来显示 stack 视图的灵活性。目前这还不是一个完整的清单。
· 只是定义位置。 你可以通过固定两个与其父视图相邻的边界来定义 stack 视图的位置。在这里,stack 视图的尺寸将根据其管理的视图在两个维度上自由扩展。当你想要 stack 视图的内容展现其原有内容尺寸,和你想要管理其他与 stack 视图有关联的用户接口元素时是特别有用的。
举个例子,在 Figure 1中,stack 视图的左边界和上边界都已经相对固定于其父视图。这些标签将根据带有8个点的两者之间的空间作为第一基线校准。这对于相对于其本身左对齐的 stack 视图内容是有效的。
Figure 1.定义位置
· 定义沿着 stack 视图轴向的尺寸。 这里,你固定了沿着 stack 视图轴向相对于其父视图的两个边界,定义了 stack 视图沿着其轴向的尺寸。你将需要固定其他边界中的一个来定义 stack 视图的位置。stack 视图将沿着其轴向改变尺寸和位置来填充定义的空间;然而,未固定的边界将根据其管理的最大视图的尺寸自由移动。
举例如 Figure 2,stack 视图的左、上、右边界都已经相对于其父视图固定了。使用 UIStackViewDistributionFill 分布使得其内容重设尺寸来填充它的宽度,并且从文本框有比标签更低的内容紧凑优先级开始,它将在必要的时候被拉伸。
Figure 2.定义沿着 stack 视图轴向的尺寸
· 定义垂直于 stack 视图轴向的尺寸。 这类似于上一个示例,但是你固定了垂直于 stack 视图轴向的两个边界和沿着轴向的一个边界。这使得 stack 视图在你增加或移除其管理的视图时将沿着其轴向扩展或回缩。除非你使用了 UIStackViewDistributionFillEqually 分布,被管理的视图将根据其原有尺寸调节尺寸。垂直于其轴向的视图将根据其 stack 视图的对其模式在其定义的范围内平铺。
举例,Figure 3展示了一个包含了四个标签和一个按钮的垂直 stack 视图。这个 stack 视图使用了8个点的间隙和 UIStackViewAlignmentCenter 对齐方式。stack 视图的高度将根据 stack 内部的元素的增减而增大或回缩。
Figure 3.定义垂直于 stack 视图轴向的尺寸
同时定义 stack 视图的位置和尺寸。 这里你固定了 stack 视图的所有四个边界。stack 视图将在提供的范围之内平铺其内容。举例,Figure 4展示了一个所有四个边界都相对于其父视图固定的垂直 stack 视图。通过使用 UIStackViewAlignmentCenter 对齐方式和 UIStackViewDistributionFill 分布方式,stack 视图确保其内容将水平和垂直居中填充屏幕。然而,获得想要的布局需要两个额外的步骤。默认情况下,stack视图会垂直拉伸标签而不是图片。要缩放图片控 件,就要降低其内容紧凑优先级到低于标签。额外的,为了保持图片缩放时的长宽比,你必须设置图片视图的模式为 Aspect Fit。增加一个图片视图与 stack 视图间宽度相等约束将有助于确保图片将被缩放来填充可用范围。
Figure 4.同时定义 stack 视图的位置和尺寸
五、管理 Stack 视图的展现
UIStackView 是 UIView 的非渲染型子类。它没有提供其自有的任何用户接口。相反的,它只管理被其管理的视图的位置和尺寸。因此,有些属性(如 backgroundColor)在 stack 视图上是无效的。类似的,你无法重写 layerClass,drawRect: 或 drawLayer:inContext: 方法。
这里有一系列的属性来定义 stack 视图如何平铺其内容。
· axis (轴向) 属性决定了 stack 的朝向,只有垂直或水平;
· distribution (分布) 属性决定了其管理的视图在沿着其轴向上的布局;
· alignment (对齐) 属性决定了其管理的视图在垂直于其轴向上的布局;
· spacing (空隙) 属性决定了其管理的视图间的最小间隙;
· baselineRelativeArrangement 属性决定了其视图间的垂直间隙是否根据基线测量得到;
·
layoutMarginsRelativeArrangement
属性决定了 stack 视图平铺其管理的视图时是否要参照它的布局边距
通常情况下,你会使用一个 stack 视图来布局小数量的视图。你可以通过在其他 stack 视图中嵌套多个 stack 视图的方式创建更加复杂的视图层次结构。举例,Figure 5展示了一个包含两个水平 stack 视图的垂直 stack 视图。每一个水平 stack 视图各包含一个标签和一个文本框。
Figure 5.Stack 视图的嵌套
你也可以通过增加被管理的视图的额外约束来完美的调节一个被管理视图的展现。举例说明,你可以使用约束类设置视图的最小或最大的高度或宽度。或者 你可以定义一个长宽比。当平铺其内容时,stack 视图将使用这些约束。举例来说,在Figure 4中,当图片被缩放时,图片视图的一个长宽比约束被强行赋予了一个长宽比常数。
注意:当给一个 stack 视图内的视图增加约束时要特别注意避免传入冲突。作为惯例,如果一个视图的尺寸在一个指定的维度上默认回到其原本内容尺寸,那么你可以安全的在这个维度上增加约束。
六、维护其管理的视图与子视图之间的统一性
Stack 视图确保它的 arrangedSubviews 属性将一直是其 subviews 属性的子集合。明确的说,stack 视图强制实施了以下规定:
· 无论何时 stack 视图增加了一个视图到它的 arrangedSubviews 数组,其也将把这个视图作为子视图增加,如果还未增加的话。
· 无论何时一个子视图从 stack 视图中被移除,那么 stack 视图也将将其从 arrangedSubviews 数组中移除。
· 从 arrangedSubviews 移除一个视图并不会将其作为子视图移除。stack 视图将不再管理该视图的尺寸和位置,但是该视图仍将是视图结构的一部分,并且当其可见的情况下仍会被渲染到屏幕上。
当 arrangedSubviews 数组一直包含着 subviews 数组的子集合,这些数组间的顺序仍然是独立的。
· arrangedSubviews 数组的顺序定义了展现在 stack 中的视图的顺序。对于水平 stack 视图,这些视图将以阅读顺序平铺,即较小索引的视图在较大索引视图的左侧。对于垂直 stack 视图,这些视图是从上到下平铺的,及较小索引的视图在较大索引视图的上方。
· subviews 数组中的顺序定义了子视图在Z轴上是顺序。如果视图重叠,有较小索引的子视图将出现在有较大索引的子视图后方。
七、动态改变 Stack 视图内容
当视图被加入、移出或插入 arrangedSubviews 数组时,或当一个被管理的子视图的 hidden 属性改变时,stack 视图都会自动更新它的布局。
OC代码如下:
// Appears to remove the first arranged view from the stack. // The view is still inside the stack, it's just no longer visible, and no longer contributes to the layout. UIView * firstView = self.stackView.arrangedSubviews[0]; firstView.hidden = YES;
Swift代码如下:
// Appears to remove the first arranged view from the stack. // The view is still inside the stack, it's just no longer visible, and no longer contributes to the layout. let firstView = stackView.arrangedSubviews[0] firstView.hidden = true
stack 视图也会自动响应其任何属性的改变。举例,你可以更新 stack 视图的 axis 属性来动态改变的朝向。
OC代码如下:
// Toggle between a vertical and horizontal stack if (self.stackView.axis == UILayoutConstraintAxisHorizontal) { self.stackView.axis = UILayoutConstraintAxisVertical; } else { self.stackView.axis = UILayoutConstraintAxisHorizontal; }
Swift代码如下:
// Toggle between a vertical and horizontal stack if stackView.axis == .Horizontal { stackView.axis = .Vertical } else { stackView.axis = .Horizontal }
对于被管理的子视图的 hidden 属性的变化和 stack 视图属性的变化,你可以通过将这些改变内置到一个动画块代码的方式以动画方式展现。
OC代码如下:
// Animates removing the first item in the stack. [UIView animateWithDuration:0.25 animations:^{ UIView * firstView = self.stackView.arrangedSubviews[0]; firstView.hidden = YES; }];
Swift代码如下:
// Animates removing the first item in the stack. UIView.animateWithDuration(0.25) { () -> Void in let firstView = stackView.arrangedSubviews[0] firstView.hidden = true }
最后,你可以直接在Interface Builder中给很多 stack 视图属性定义特定的 “尺寸类” 类型值。系统将在 stack 视图的尺寸类改变时动画展现这些改变。
八、常用的方法
创建 Stack 视图
- initWithArrangedSubviews: (New in iOS 9.0)
管理安排的子视图
- addArrangedSubview: (New in iOS 9.0) arrangedSubviews Property (New in iOS 9.0) - insertArrangedSubview:atIndex: (New in iOS 9.0) - removeArrangedSubview: (New in iOS 9.0)
设置布局
alignment Property (New in iOS 9.0) axis Property (New in iOS 9.0) baselineRelativeArrangement Property (New in iOS 9.0) distribution Property (New in iOS 9.0) layoutMarginsRelativeArrangement Property (New in iOS 9.0) spacing Property (New in iOS 9.0)
常量
UIStackViewDistribution UIStackViewAlignment 代码实例
-、建立 UITableView DataTable = [[UITableView alloc] initWithFrame:CGRectMake(, , , )]; [DataTable setDelegate:self]; [DataTable setDataSource:self]; [self.view addSubview:DataTable]; [DataTable release]; 二、UITableView各Method说明 //Section总数 - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ return TitleData; } // Section Titles //每个section显示的标题 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return @""; } //指定有多少个分区(Section),默认为1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { ; } //指定每个分区中有多少行,默认为1 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ } //绘制Cell -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: SimpleTableIdentifier] autorelease]; } cell.imageView.image=image;//未选cell时的图片 cell.imageView.highlightedImage=highlightImage;//选中cell后的图片 cell.text=//..... return cell; } //行缩进 -(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath{ NSUInteger row = [indexPath row]; return row; } //改变行的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ ; } //定位 [TopicsTable setContentOffset:CGPointMake(, promiseNum * + Chapter * )]; //返回当前所选cell NSIndexPath *ip = [NSIndexPath indexPathForRow:row inSection:section]; [TopicsTable selectRowAtIndexPath:ip animated:YES scrollPosition:UITableViewScrollPositionNone]; [tableView setSeparatorStyle:UITableViewCellSelectionStyleNone]; //选中Cell响应事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [tableView deselectRowAtIndexPath:indexPath animated:YES];//选中后的反显颜色即刻消失 } //判断选中的行(阻止选中第一行) -(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger row = [indexPath row]; ) return nil; return indexPath; } //划动cell是否出现del按钮 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { } //编辑状态 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { } [topicsTable setContentSize:CGSizeMake(,controller.promiseNum * )]; //右侧添加一个索引表 - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ } //返回Section标题内容 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ } //自定义划动时del按钮内容 - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath //跳到指的row or section [tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow: inSection:] atScrollPosition:UITableViewScrollPositionBottom animated:NO]; 三、在UITableViewCell上建立UILable多行显示 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; UILabel *Datalabel = [[UILabel alloc] initWithFrame:CGRectMake(, , , )]; [Datalabel setTag:]; Datalabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [cell.contentView addSubview:Datalabel]; [Datalabel release]; } UILabel *Datalabel = (UILabel *)[cell.contentView viewWithTag:]; [Datalabel setFont:[UIFont boldSystemFontOfSize:]]; Datalabel.text = [data.DataArray objectAtIndex:indexPath.row]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; return cell; } //选中cell时的颜色 typedef enum { UITableViewCellSelectionStyleNone, UITableViewCellSelectionStyleBlue, UITableViewCellSelectionStyleGray } UITableViewCellSelectionStyle //cell右边按钮格式 typedef enum { UITableViewCellAccessoryNone, // don't show any accessory view UITableViewCellAccessoryDisclosureIndicator, // regular chevron. doesn't track UITableViewCellAccessoryDetailDisclosureButton, // blue button w/ chevron. tracks UITableViewCellAccessoryCheckmark // checkmark. doesn't track } UITableViewCellAccessoryType //是否加换行线 typedef enum { UITableViewCellSeparatorStyleNone, UITableViewCellSeparatorStyleSingleLine } UITableViewCellSeparatorStyle//改变换行线颜色 tableView.separatorColor = [UIColor blueColor];
iOS开发——UI篇OC篇&UIStackView详解的更多相关文章
- iOS开发——UI精选OC篇&UIApplication,UIWindow,UIViewController,UIView(layer)简单介绍
UIApplication,UIWindow,UIViewController,UIView(layer)简单介绍 一:UIApplication:单例(关于单例后面的文章中会详细介绍,你现在只要知道 ...
- iOS开发——UI高级OC篇&自定义控件之调整按钮中子控件(图片和文字)的位置
自定义控件之调整按钮中子控件(图片和文字)的位置 其实还有一种是在storyBoard中实现的,只需要设置对应空间的左右间距: 这里实现前面两种自定义的方式 一:imageRectForContent ...
- iOS开发——网络实用技术OC篇&网络爬虫-使用青花瓷抓取网络数据
网络爬虫-使用青花瓷抓取网络数据 由于最近在研究网络爬虫相关技术,刚好看到一篇的的搬了过来! 望谅解..... 写本文的契机主要是前段时间有次用青花瓷抓包有一步忘了,在网上查了半天也没找到写的完整的教 ...
- ios开发——实用技术篇OC篇&iOS的主要框架
iOS的主要框架 阅读目录 Foundation框架为所有的应用程序提供基本系统服务 UIKit框架提供创建基于触摸用户界面的类 Core Data框架管着理应用程序数据模型 Core ...
- iOS开发——高级技术OC篇&运行时(Runtime)机制
运行时(Runtime)机制 本文将会以笔者个人的小小研究为例总结一下关于iOS开发中运行时的使用和常用方法的介绍,关于跟多运行时相关技术请查看笔者之前写的运行时高级用法及相关语法或者查看响应官方文档 ...
- iOS开发——运行时OC篇&使用运行时获取系统的属性:使用自己的手势修改系统自带的手势
使用运行时获取系统的属性:使用自己的手势修改系统自带的手势 有的时候我需要实现一个功能,但是没有想到很好的方法或者想到了方法只是那个方法实现起来太麻烦,一或者确实为了装逼,我们就会想到iOS开发中最牛 ...
- iOS开发——网络实用技术OC篇&网络爬虫-使用java语言抓取网络数据
网络爬虫-使用java语言抓取网络数据 前提:熟悉java语法(能看懂就行) 准备阶段:从网页中获取html代码 实战阶段:将对应的html代码使用java语言解析出来,最后保存到plist文件 上一 ...
- iOS 开发之 -- UDID和UUID的详解
老实说,搞了几年的ios开发了,对基础的概念,还是不牢固,整天都是为了赶进度而码代码,这里记录一下这两者的区别: UDID的全名为 Unique Device Identifier :设备唯一标识符. ...
- iOS开发——高级技术&本地化与国际化详解
本地化与国际化详解 效果如下: 英语: 中文: 具体实现如下: ...
- iOS开发——新特性OC篇&IOS9 SDK新特性
iOS9 SDK新特性 WWDC 2015苹果开发者大会是移动开发者一年一度的盛会,InfoQ中文站除了第一时间整理Keynote内容分享给大家之外,还邀请了资深的一线开发者分享他们的收获.本文为王巍 ...
随机推荐
- bzoj3211,bzoj3038
线段树的裸题: 但是操作很奇怪,开方是不能lazy tag的 看来只能暴力修改了 但注意,开放开到1的时候就不用开,立一个flag就可以了 这可以大大的优化: 其实我是来复习线段树的 ..] of i ...
- 常用WEB服务器的特点介绍
经过系统的学习web服务器,现在知道常用的web服务器的优缺点,这对搭建网站架构时选择使用web服务器很有帮助,现在我简单总结一下: 1. Apache:属于重量级web服务器(重量级主要是在软件包的 ...
- 信息学院第九届ACM程序设计竞赛题解
A: 信号与系统 Time Limit: 1000 MS Memory Limit: 65536 KBTotal Submit: 238 Accepted: 44 Page View: 69 Des ...
- Android开发优化宝典
I. 网络相关 http头信息带Cache-Control域 确定缓存过期时间 防止重复请求 直接用IP直连,不用域名,策略性跟新本地IP列表. – DNS解析过程耗时在百毫秒左右,并且还有可能存在D ...
- 常用高度——获取浏览器窗口的高度(jquery和js)
一:针对浏览器的常用高度 jquery的用法: <script type="text/javascript"> $(document).ready(function() ...
- class属性添加多个类
<html> <head> <style type="text/css"> h1.intro { color:blue; text-align: ...
- java jvm学习笔记五(实践自己写的类装载器)
欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和 ...
- tdx api z
调用TdxAPI.dll函数 .DLL命令 TdxInit, 逻辑型, "TdxApi.dll", "TdxInit", , 初始化通达信实例,成功时返回tru ...
- java.lang.ExceptionInInitializerError的原因(转)
这个错误是说变量初始化出现问题,通常出现在静态变量尤其是单例模式.这种问题往往是初始化顺序不对造成的,下面举个简单的例子. import java.util.HashMap; import java. ...
- (二)GameMaker:Studio ——使用等高图生成3D地形
上一篇,我们讲解了GM中导入模型的方法,这节我们来讲地形. 源文件地址:http://pan.baidu.com/share/link?shareid=685772423&uk=2466343 ...