占位符介绍
在UITextField
上设置多个占位符并UITextField
设置动画
占位符是一个源远流长的功能强大的概念-易于被用户识别,具有严格,合理的含义,并为开发人员提供了一种提示用户的简便方法。
但是,有时仅拥有一个占位符是不够的。 有时您想向用户展示可以输入的所有内容。 例如,如果您有一个名为“活动标题”的字段,那么您当然可以在其中将“运行”作为占位符。 或者,您可以定义一组占位符,例如“运行中”,“行走”,“行进”,“拳击”,并对它们进行动画处理。 如果认真使用此技术,则可以提供出色的用户体验。 看起来像这样:
占位符库允许您做到这一点。 实际上,它确实非常简单,我鼓励您自己尝试实现类似的东西-它可以很好地介绍迭代器, CATransition
和Timer
(以前称为NSTimer
)。 在本文中,我们将快速浏览API,然后讨论一些体系结构选择和功能。
在开始之前,这里是GitHub上的占位符 :
德雷蒙德/占位符
占位符–🅿️为UITextField定义多个占位符,并对它们的更改进行动画处理 github.com
现在让我们潜入吧!
如何使用
占位符旨在与视图控制器很好地配合使用。 API的核心部分是Placeholders
类。 您可以直接创建它:
let占位符=占位符(占位符:[“正在运行”,“正在行走”,“骑自行车”])
这将创建一组三个占位符。 当然,通常您希望“循环”占位符,以便动画永远运行。 或者您想改组您的集合,以使用户不会每次都以相同的顺序看到相同的占位符。 为此,应分别使用.infinite
和.shuffled
选项,如下所示:
let占位符=占位符(占位符:[“正在运行”,“正在行走”,“骑自行车”],选项:[.infinite,.shuffle])
然后,在viewWillAppear
方法中,应将Placeholder
实例绑定到UITextField
。 您可以通过调用start
方法来做到这一点:
placeholders.start(时间间隔:3.0,
fireInitial:正确,
textField:textField,
动画:.pushTransition(.fromBottom))
( fireInitial
用于立即设置第一个占位符)
基本上就是这样! 现在,您有多个动画占位符。 您可以间隔播放或调整动画以适合您的需求。 如果要创建完全自定义的动画,请查看自述文件。
怎么运行的
总的来说,该解决方案非常简单:它是Timer
,迭代器和CATransition
的组合。 数据源是通过AnyIterator
提供的,占位符的更改是通过Timer
安排的,并使用简单的CATransition
执行。
如果您想知道动画的执行方式,则为:
让过渡= CATransition()
transition.duration = 0.35
transition.timingFunction = CAMediaTimingFunction(名称:kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromBottom
textField.subviews.first(其中:{NSStringFromClass(type(of:$ 0))==“ UITextFieldLabel”})?. layer.add(transition,forKey:nil)
textField.placeholder = nextPlaceholder
(免责声明:这不是直接来自库的代码-实际的代码被拆分为多个函数,但是为了简单起见,我将其全部放在此处。)
怎么做的
在开发Placeholder时 ,需要做出一些有趣的架构决策。 我想在本文中分享其中的一些。
1.组成而不是继承
通常,这种附加功能是通过子类完成的。 当然,可以简单地创建MultiplePlaceholdersTextField
类,并向其添加一些美观的setPlaceholders
方法。 但是,但是,它使您无法使用UITextField
所有自定义子类(或者更有可能的是,您根本不会使用该库)。 这也降低了代码的可重用性,并且总体而言,这是一个可疑的体系结构决策:此逻辑根本不属于View层。
这就是为什么Placeholders
是一个单独的对象的原因,它位于Controller层(据我所相信属于该层)中并且可以与任何UITextField
一起使用,因此即使与现有代码库集成起来也很容易。
2.隔离实施
如果查看Placeholder
类,您会发现它对UITextField
完全一无所知(甚至不导入UIKit
)。 而且所有UITextField
功能都放在一个扩展中,该扩展实现了前所未有的自定义级别。 基本上,您几乎可以在每个步骤上自定义过程。
Placeholder
对象本身只有一个start
方法:
func start(interval:TimeInterval,fireInitial:Bool,action:@escaping(Element)->())
在用法部分描述的UITextField
方法只是一个包装器。 这有效地分离了逻辑,使实际的实现更简单,更易于管理。
您可以在此处阅读有关此方法背后思想的更多信息。
3.迭代器代替数组
在AnyIterator
, Placeholders
使用AnyIterator
而不是简单的数组。 这样做有两个原因:
- 拥有迭代器就足够了。 我们不需要这里配备齐全的阵列。 我们只需要一些可以给我们下一个要素的东西。 迭代器实际上就是那个“东西”。
- 可以以有趣的方式修改迭代器。 例如,“无限”功能可在迭代器级别上使用,而不是嵌入到
Placeholders
。 您可以在此处检查InfiniteIterator
的实现。
4.泛型
您可能没有注意到它,但是Placeholders
实际上是一个泛型类型。 这是为什么? 因为这样您可以使用相同的语法使用String
和NSAttributedString
!