Tag: 布局

建立有效的布局

关于iOS,我们大多数人已经使用AutoLayout在UI中定位内容已有相当长的时间了。 但是我们是否曾经考虑过有效使用它,或者您多么容易使UI变得如此复杂而导致丢失帧。 当我们以编程方式添加约束时,这更适用。 渲染循环 大多数应用的目标帧率为60 FPS,相当于每帧16.67毫秒。 渲染循环是每秒可能运行120次的过程。 这样可以确保所有内容都准备好用于每个帧。 渲染循环分为三个阶段。 1.计算约束 从叶的大多数视图一直到窗口的视图层次结构。 2.布局视图 从窗户向下朝树叶开始,这是相反的方向。 3.显示/绘制 这也从窗口开始朝着叶子的方向相反。 避免约束搅动 当您不必要地更新约束但并非所有子视图都需要重新渲染时,就会发生搅动。 这将为布局引擎增加其他工作,从而导致渲染循环中花费更多时间。 下面的示例演示如何避免使用非常简单的方法重新计算静态约束。 激活约束 激活约束后,将创建一个方程式,布局引擎将对其求解以获取minX,minY,宽度和高度。 在布局阶段,此帧数据将从布局引擎提供给视图,并且将相应调整每个视图的大小和位置。 对于具有静态位置的视图,而不是激活停用一组约束的方法,请尝试查找是否可以使用setHidden和hide / show以避免布局引擎和布局阶段的额外开销。 内在内容大小 具有非视图内容的视图将基于该非视图内容返回其固有内容大小的大小。 这方面的两个示例是UIImageView和UILabel,UIImageView使用其图像的大小来计算其内部内容的大小,UILabel测量其文本并使用其返回其内部内容的大小。 这用于创建大小约束。 文本测量可能很昂贵。 因此,如果您的应用程序是文本密集型应用程序,并且如果您知道文本所需的大小而无需进行所有文本度量,那么您可以返回该大小和固有内容大小,或者如果您打算放置此视图在屏幕上,无论其中的文本大小如何,约束都将完全定义大小。 例如,约束总是会使它大于您所拥有的文本量。 systemLayoutSizeFittingSize 这用于从布局引擎获取尺寸信息。 尝试将其使用量降到最低,尤其是在表格或集合单元格内部,因为这可能会对滚动性能产生不利影响。 调用此方法将创建一个布局引擎,并将约束添加到此引擎,解决布局,然后返回顶视图框架的大小,然后丢弃该引擎。 因此,总的来说,性能影响是线性的,取决于您添加的约束。 约束越复杂,求解这些方程式以及渲染循环中的后续阶段所花费的时间就越多。 布局引擎是一个缓存和一个依赖项跟踪器,因此已经解决的值将存在于缓存中,并且相对于此添加新约束将很快。 设置其他参数(例如约束优先级)将花费更多时间来计算,建议除非您确实需要它们,否则不要过多使用它。

SNAPKit nedirnasılkullanabiliriz吗?

大容量iPhone型号320×480像素布局布局sadece bir cihazagöreoluşturmakyeterli oluyordu。 Sonradan iPhone 5,iPhone6,iPhone6 Plus和iPhone6 Plus型号,包括她的iPhone 5和iPhone6 Plus。 界面生成器ile AutoLayout可以在界面上显示出来。 不可抗拒的法律和约束条件。 Apple iOS SDK可以使用NSLAyoutConstraints来完成对karmaşıklığını的操作。 提示SNAPKityardımımızakoşuyor。 SNAPKit ile“ swifty ” olarakokunabilirliğidaha iyihızlıve kolay birşekilde制约因素artıkoluşturabiliriz🙂 Örneklerilenasılkullanabileceğimizibir inceleyelim。 SNAPKitkütüphanesiniCocoaPods Ent Entegre ettikten sonrabütünview’lerde snp attribute ile SNAPKitkütüphanesineulaşabiliriz。 约束条件可以使约束方法不合规,而参数不能被约束。 Öceçoğunluklakullandığımız填充işleminebirbakalım。 容器view’e 20 pts填充ile bir kutuyerleştirmekistiyorsak bunuaşağıdakişekildekolayca yapabiliriz。 .equalTo methodunda hangi view’egörekonumlandıracağımızıseçiyoruz。 equalTo methodu参数olarak视图,ViewAttribute vebit sabit birsayıdeğerialabiliyor。 […]

如何使用PureLayout摆脱情节提要和AutoLayout?

Xcode,Swift和Cocoa,这些很棒的东西,在构建iOS应用程序时会让您微笑。 但是,对于情节提要和AutoLayout,我认为这不是事实。 自动布局是我见过的最不可靠的东西。 不用担心,iOS社区已经构建了出色的开源工具来帮助我们继续构建出色的应用程序,而无需关心AutoLayout,Segues和Storyboard管理。 在本文中,我将向您展示如何在不使用任何故事板或定义自动布局约束的情况下构建应用程序。 代替这些,我将向您展示如何使用PureLayout配置视图控制器,并摆脱项目中的所有情节提要。 1.获取PureLayout 这是PureLayout的Github官方页面 PureLayout / PureLayout PureLayout – iOS和OS X Auto Layout的终极API –极其简单,功能强大。 Objective-C和… github.com 我建议您在实现库时始终使用CocoaPods,因为这会使您的生活更轻松🙂 2.删除情节提要 首先删除您的Main.storyboard,使所有内容保持干净。 转到项目目标,然后清除“主界面”字段。 3.编辑您的AppDelegate 打开您的AppDelegate文件,然后在应用程序didFinishLaunchingWithOptions内部配置启动屏幕 func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->布尔{ 让窗口= UIWindow(框架:UIScreen.main.bounds) window.backgroundColor = UIColor.white 让vc = CustomViewController() window.rootViewController = vc window.makeKeyAndVisible() self.window =窗口 返回真 } 在此示例中,我将启动视图控制器配置为CustomViewController,将在下一步中创建它。 4.创建一个新的View Controller并导入PureLayout 创建一个名称为CustomViewController的视图控制器,让我们开始配置PureLayout参数。 首先导入PureLayout,这样您就可以访问它的漂亮功能。 导入PureLayout 5.将UI元素放在视图上。 使用PureLayout时,请确保将“ didSetupConstraints”变量放置在视图控制器中,并将其设置为“ […]

尺寸等级和约束:印刷效果更好

几乎每个认真进行iOS开发的人都经历了为一个人处理约束的痛苦,这对于大多数人和两个人来说似乎都是不可思议的,您永远无法真正摆脱它们的需求。 我们需要告诉OS将UI元素放置在屏幕上的位置。 这考虑了对内部变化(如动态内容)或外部变化(如形状因数,屏幕方向和旋转)的响应。 根据官方文档,有三种方法可以执行此操作: 布局用户界面的主要方法有三种。 您可以以编程方式对用户界面进行布局,可以使用自动调整大小的蒙版来自动化对外部更改的某些响应,或者可以使用“ 自动布局” 。 在这三者中,我们将讨论“自动布局”。 自动布局是在iOS 6中引入的,它是一个系统,可让我们通过创建元素之间关系的数学描述来布局用户界面。 我们根据对单个元素或元素集之间的约束来定义这些关系。 如果我们的用户界面是建筑物,则将约束视为将所有东西都放在定义的位置的脚手架。 通过自动布局使事情进展最快的方法是堆栈,固定,对齐和解析工具。 堆栈是使用自动布局而不使用约束的工具。 这就像选择各种元素并将它们放到堆栈中一样容易,因此在屏幕旋转时,它将保持内部元素之间的对齐。 堆栈视图可能是最快且无混乱的UI布局方式,但是请记住,它们是iOS 9中引入的,因此不能用于以前的版本。 好吧,裸体谈话! 让这些手变脏,在自动布局中通过引脚对齐和固定。 假设您有一个UI要求,即在potrait模式下必须有两个等号的按钮在一个按钮的下方显示,而在横向模式下,它们应彼此并排显示。 而且,我们将完成所有这些工作,而无需触及任何一行代码,保证! 我们将学习如何通过尺寸类来做到这一点。 这是一个非常酷的3×3矩阵,可以说是构建UI的最快,最有效的方法。 wAny hAny表示所有方向上的所有形状因子。 这也意味着我们在其中设置的任何元素或约束在所有设备和所有方向上都是可见的。 您的应用程序可能同时处理iPad和iPhone,因此最好放置UI中常见的元素。 当设计要求发生变化时,这可以帮助您节省时间并易于使用。 转到视图并将按钮放入其中,将它们分别命名为绿色和红色,并更改其背景颜色。 我们将从设置绿色在屏幕上的位置开始。 这将是风景和肖像之间的唯一共同约束。 按下“固定”工具,然后取消选中“到边距的约束”复选框,然后固定2个边缘(前导和顶部),如下图所示: 我们将更改Size类,因为我们希望iPhone处于纵向模式,我们将鼠标悬停在矩阵上,并将宽度Compact和height设置为Any(3×1),它将覆盖纵向模式下的所有iPhone。 接下来,如图所示,将后缘以50px固定在绿色上: 自动布局附带三个方程式,它们定义了绿色按钮与父视图的关系。 在这一点上,必须了解自动布局如何看到这些约束,等号表示项目在左侧和右侧的相等性,而不是赋值。 自动布局会努力使=符号两侧的两个实体相等,同时这样做肯定会有错误,请参阅官方文档,以了解它引发的各种错误及其原因。 现在我们已经设置了绿色按钮的位置,我们要做的就是使红色按钮完全相同,并将其放置在比绿色按钮低20px的位置。 在继续之前,请从“解决”菜单中执行更新框架。 现在,我们将使用“对齐”工具,同时选择两个按钮,然后检查“前缘”和“后缘”按钮。 自动布局足够聪明,可以解密哪个按钮的边缘与谁对齐。 更新框架,您会在绿色的顶部看到红色,并且高度和宽度相等,但是自动布局仍然会抱怨您尚未将红色绑定到Y轴。 将红色拖动到绿色下面,不用担心您不需要准确,我们可以自动布局! 完成后,将红色顶部固定为20px。 切记取消选中“边距约束”。 另外请记住,我们需要绿色按钮中的20px,下拉菜单将为您提供您要固定其位置的选项,请选择绿色。 添加约束并更新框架。 瞧! 您已经创建了无冲突的用户界面!! 在我们高兴之前,这项工作尚未完成。 我们必须在横向模式下并排显示按钮。 在文档概述中完成此操作后,您将注意到一些约束方程式变为灰色。 这是因为,我们告诉自动布局如何在iPhone纵向模式下而不是横向模式下将这些按钮保持在原位,这就是我们现在要完成的工作。 跳至文档大纲,然后选择红色和绿色。 […]

学习以编程方式创建iOS视图

在上一篇文章的结尾,我答应展示如何编写“自动布局”约束并以编程方式创建视图。 这篇文章是涵盖Swift和iOS开发许多方面的一系列文章中的第一篇。 从iOS 9开始,编码约束变得容易得多。 Auto Layout NSLayoutAnchor类在以非常流畅的方式创建约束方面提供了巨大的帮助。 但是,在达到这种流利程度之前,您需要了解和学习两个非常重要的知识: 了解视图,子视图以及两个视图,两个子视图或视图与子视图之间的关系。 学习并了解用于创建自动布局约束的语法。 因此,让我们开始吧。 参考上图,有两个全角和等高的视图,它们垂直居中放置。 视图1和视图2都是其父视图的子视图-在这种情况下,控制器的主视图位于视图1和视图2的顶部。 还需要注意的是,视图1的底部边缘正在触摸视图2的顶部边缘。 View 1的顶部,左侧和右侧边缘与Superview的顶部,左侧和右侧边缘对齐。 View 2的左,右和底边与Superview的左,右和底边对齐。 添加标签只是为了创建引用。 我们不会在这篇文章中介绍UILabel类。 让我们开始编码。 1.为了开始,我们必须首先在UIViewController类(或View类,如果愿意)中声明变量-view1和view 2。 2.我们必须添加视图1和视图2作为控制器主视图的子视图。 3.这行代码非常重要。 在这里,我们必须设置view1和view2的translationsAutoresizingMaskIntoConstraints属性。 此属性的含义是,如果将其设置为true,则会将其自动调整大小的蒙版转换为Auto Layout约束。 我们不希望那样,因为我们要定义自己的约束。 因此,我们需要将property设置为false。 4.现在我们必须为view1设置约束。 上面的代码的前三行将view1的顶部,左侧和右侧锚点设置为与superview的顶部,左侧和右侧锚点相同。 这是因为view1的顶部,左侧和右侧边缘与其superview的顶部,左侧和右侧边缘对齐。 为了激活这些约束,您必须将isActive设置为true。 这非常重要,因为默认情况下isActive设置为false。 在第4行中,view1的高度锚点设置为超级视图高度的1/2。 这是因为view1的高度是超级视图的高度的1/2。 注意:类似于在这种情况下使用的“乘数”公式,您也可以使用可以加或减的“常数”。 第5行设置背景色。 5.现在我们必须为视图2设置约束。 上面代码的前两行将view2的左锚和右锚设置为与superview的左锚和右锚相同。 这是因为view2的左右边缘与Superview的左右锚点对齐。 您也可以添加bottomAnchor约束,但是由于我想向您展示两个视图之间的关系,因此我们将其留待以后使用。 第三行将view2的高度设置为超级视图的高度的1/2。 第4行强调了自动版式的一个非常重要的方面。 它定义了view1和view2之间的关系。 这行代码将view2的顶部锚点设置为等于view1的底部锚点。 这是因为view2的顶部边缘与view1的底部边缘对齐。 这是完整的代码: 这是您应该尝试创建自己的另一个示例: 参考上图,“视图”是控制器的主视图。 您将需要为其添加背景色。 子视图1和子视图2具有相同的大小,并且是View的子视图。 子视图1和子视图2水平居中,两者之间有50个点的间隙。 子视图1的左边缘与视图的左边缘相距100个点。 […]

iOS(Swift):具有可变高度的TableView节标题-适合内容

由于要求,必须根据“设置”更改动态更改TableView的Header部分的内容。 问题 :随着节标题内容的动态变化,节标题的高度必须改变以适应变化的内容。 解决方案 : 以下是实现解决方案的步骤 步骤1 : 设置TableView以支持自动调整大小 覆盖func viewDidLoad(){ super.viewDidLoad() self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension; self.tableView.estimatedSectionHeaderHeight = 38 } 步骤2 : 区段标题 使用自动布局创建节标题视图,这里我们使用NSLayoutConstraint动态创建自动布局UIView func tableView(_ tableView:UITableView,viewForHeaderInSection部分:Int)-> UIView? { 让headerView = UIView() 变量约束= [NSLayoutConstraint]() 如果section == 0 { 让flightStatsNoticeLabel = UILabel() flightStatsNoticeLabel.text =“ Lorem Ipsum只是印刷和排版行业的虚拟文本。 自1500年代以来,Lorem Ipsum一直是业界标准的伪文本,当时一位不知名的打印机拿起一个厨房,然后将其打乱成一本样本书。” flightStatsNoticeLabel.numberOfLines = 0 flightStatsNoticeLabel.sizeToFit() 让goToSettingsButton = UIButton() goToSettingsButton.setTitle(“ GoToSettings”,用于:.normal) […]

使用基于框架的布局桥接自动布局

您是否曾经遇到过将新的基于“自动布局”的视图放置在一些较旧的基于框架的代码中的问题? 您将遇到的一个问题是,您需要一种方法使基于框架的布局知道其“自动布局”子视图的大小何时更改。 事实证明,这可以很简单地解决! 在本文中,我将介绍一个示例以及解决方案。 让我们从一个示例开始:我们的父UIViewController创建一个AutoViewController其大小由“自动布局”约束定义。 在内部,我们的AutoViewController将UILabel绑定到其边缘。 随着文本行数的更改, AutoViewController将扩展以适应这种情况。 私人让autoVC = AutoViewController() 覆盖func viewDidLoad(){ super.viewDidLoad() addChildViewController(autoVC) view.addSubview(autoVC.view) } 我们需要一种找到AutoViewController大小的方法,以便我们可以设置其框架。 使用UIView上的systemLayoutSizeFitting(targetSize:)方法,我们可以获得由自动布局定义的子视图的高度。 在我们的例子中,我们希望视图在父级中显示为固定宽度的行,因此我们定义了一种获取尺寸的方法。 我们提供了可用的宽度,但要求压缩的高度-否则,我们的“自动版式”视图可以自由地垂直拉伸超过其所需的水平,以填满父级。 私人功能rowSize(forView视图:UIView)-> CGSize { 返回view.systemLayoutSizeFitting( CGSize(width:view.bounds.width, 高度:UILayoutFittingCompressedSize.height) ) } 然后,我们可以使用此方法设置基于“自动布局”视图的框架。 尽管不是严格要求,但是我们在父级布置其子视图时执行此操作。 最终,该视图将成为更复杂的基于框架的布局的一部分,因此,如果更改,其兄弟视图也可能需要调整。 viewWillLayoutSubviews()是一个很好的安排。 覆盖func viewWillLayoutSubviews(){ 让childFrame = CGRect( 原点:.zero, 大小:rowSize(forView:autoVC.view) ) autoVC.view.frame = childFrame } 我们仍然有问题。 我们基于自动布局的子UIViewController可能会更改其大小。 看起来像这样: 值得庆幸的是,Apple为我们提供了一种了解何时发生这种情况的方法。 通过处理systemLayoutFittingSizeDidChange(forChild:)我们可以对此做出响应。 在这里,我们将父视图标记为需要进行布局的布局,因为我们的子框架是在viewWillLayoutSubviews中设置的,因此可以完成此操作。 覆盖func systemLayoutFittingSizeDidChange(forChildContentContainer:UIContentContainer){ view.setNeedsLayout() } […]

自动版面

自动版式会根据对这些视图施加的约束来动态计算视图层次结构中所有视图的大小和位置。 例如,您可以限制按钮的位置,使其在“图像”视图中水平居中,并且按钮的顶部边缘始终保持在图像底部下方8个点。 如果图像视图的大小或位置发生更改,则按钮的位置会自动调整以匹配。 这种基于约束的设计方法使您可以构建可动态响应内部和外部更改的用户界面。 当超级视图的大小或形状发生更改时,将发生外部更改。 每次更改后,您都必须更新视图层次结构的布局,以最佳利用可用空间。 以下是一些外部变化的常见来源: 用户调整窗口大小(OS X)。 用户进入或离开iPad(iOS)上的拆分视图。 设备旋转(iOS)。 活动的呼叫和录音栏会出现或消失(iOS)。 您要支持不同的尺寸等级。 您要支持不同的屏幕尺寸。 这些更改大多数可以在运行时发生,并且需要您的应用程序动态响应。 其他功能,例如对不同屏幕尺寸的支持,则表示该应用程序可以适应不同的环境。 即使屏幕大小通常在运行时不会改变,创建自适应界面也可以使您的应用在iPhone 4S,iPhone 6 Plus甚至iPad上同样良好地运行。 自动布局也是支持iPad上的“滑行视图”和“拆分视图”的关键组件。 当用户界面中的视图或控件的大小更改时,就会发生内部更改。 以下是内部变更的一些常见来源: 应用程序显示的内容发生更改。 该应用程序支持国际化。 该应用程序支持动态类型(iOS)。 当您的应用程序的内容更改时,新内容可能需要与旧内容不同的布局。 这通常发生在显示文本或图像的应用程序中。 例如,新闻应用程序需要根据各个新闻文章的大小来调整其布局。 同样,照片拼贴必须处理各种图像尺寸和宽高比。 国际化是使您的应用程序能够适应不同语言,地区和文化的过程。 国际化应用程序的布局必须考虑到这些差异,并在应用程序支持的所有语言和区域中正确显示。 国际化对布局有三个主要影响。 首先,当您将用户界面翻译成其他语言时,标签需要占用不同的空间。 例如,德语通常比英语需要更多的空间。 日语经常需要更少的东西。 其次,即使语言不变,用于表示日期和数字的格式也可能因地区而异。 尽管这些更改通常比语言更改更微妙,但用户界面仍然需要适应大小上的细微变化。 第三,更改语言不仅会影响文本的大小,还会影响布局的组织。 不同的语言使用不同的布局方向。 例如,英语使用从左到右的布局方向,阿拉伯语和希伯来语使用从右到左的布局方向。 通常,用户界面元素的顺序应与布局方向匹配。 如果按钮在英语视图的右下角,则应该在阿拉伯语的左下角。 最后,如果您的iOS应用支持动态类型,则用户可以更改应用中使用的字体大小。 这可以更改用户界面中任何文本元素的高度和宽度。 如果用户在应用程序运行时更改字体大小,则字体和布局都必须适应。 布局用户界面的主要方法有三种。 您可以以编程方式对用户界面进行布局,可以使用自动调整大小的遮罩来自动执行对外部更改的某些响应,或者可以使用“自动布局”。 传统上,应用通过以编程方式为视图层次结构中的每个视图设置框架来布局用户界面。 该框架在超级视图的坐标系中定义了视图的原点,高度和宽度。 要布置用户界面,必须计算视图层次结构中每个视图的大小和位置。 然后,如果发生更改,则必须为所有受影响的视图重新计算框架。 在许多方面,以编程方式定义视图的框架提供了最大的灵活性和功能。 发生更改时,您可以按需进行任何更改。 但是,由于还必须自己管理所有更改,因此,设计一个简单的用户界面需要花费大量的精力进行设计,调试和维护。 […]

使用Swift在iOS中实现登录/注册功能

本文适用于刚刚开始快速开发ios应用程序的用户。 最大程度的初学者友好内容使用情节提要用于此类事情,因此我决定创建一些没有情节提要的内容。 让我们开始吧。 打开Xcode,选择File-> New-> Project。 构建并运行后,您应该看到模拟器以白色视图启动。 现在选择情节提要,您将看到一个白色的场景/视图,选择它并单击删除。 另外,删除ViewController.swift文件。 我们将从头开始。 现在,如果您运行该项目,您将看到一个空白屏幕。 如果您看到该日志,则会发现以下消息: 无法实例化UIMainStoryboardFile’Main’的默认视图控制器-可能未设置指定的入口点? 这是说该项目当前没有任何入口点。 很快,我们将提供一个控制器类作为该应用程序的入口点。 选择文件->新建->文件。 您将看到一个可用模板的窗口。 选择“快速文件”。 它将询问您文件的名称。 给SignUpController,最后按Enter。 选择SignUpController.swift文件,删除所有内容并复制粘贴以下代码。 我们要添加一个橙色视图作为200点的顶视图。 我们如何实现这一目标? 让我们为此创建一个橙色视图。 将以下代码放在viewDidLoad方法上方。 在这里,我们看到表单已经准备好了。 至此,视图部分已完成。 不幸的是,它不响应任何用户操作。 为了启用该功能,我们将以下代码添加到signUpButton: 我们以两种不同的方式为我们的注册表单提供了空文本字段验证。 现在,您可以随意进行一些复杂的验证。

使用自动布局和自动尺寸为UITableViewCell动画大小和文本更改

在我最近的iOS项目中,我有一个视图,其中内容显示为垂直可滚动的卡,并且每个卡都可以扩展以显示更多详细信息。 我已经将整个解决方案建模为UITableView ,其中每个单元格包含垂直堆叠的子视图(由于iOS 8的支持,我无法使用UIStackView ),并且每个子视图都使用其自己的视图模型进行了初始化(但这只是实现细节)。 在最终视图中,层次结构看起来类似于下图。 通过单击“ 更多和更少”按钮,“ 描述”字段在短文本和长文本之间切换。 从iOS 8开始,UITableView提供了一种自动管理UITableViewCell高度的简便方法,而无需手动计算并为每个单元格提供高度。 通过将行高设置为自动并提供估计的行高来完成 tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 124 您只需要确保设置正确的约束即可,这意味着,例如,如果UILabel正确计算了其大小,便可以将其超级视图推到所需的大小。 这意味着您不能例如设置高度限制,最终应该从上到下固定标签。 我的情况非常简单,我只是将UILabel固定在每一侧。 当涉及到动画时,无需考虑高度就非常简单。 您只需更新文本并设置动画大小即可。 因此,代码如下所示: //细胞 @IBAction功能按钮MoreTouched(_发送方:UIButton){ labelDescription.text = longText 委托?.contentDidChange(cell:self) } //代表 扩展TableViewController:CellDelegate { func contentDidChange(cell:Cell){ UIView.animate(withDuration:1){ self.tableView.beginUpdates() self.tableView.endUpdates() } } } 结果是有效的,但存在一些缺陷。 文本立即更改,整个表格都具有动画效果。 但是,文本在垂直方向居中,在我看来,这不是故意的。 我想实现“更多显示”行为。