框架中建立浮动框架_建立关注框架

框架中建立浮动框架

At-mentions are an easy way to draw someone’s attention to a high-priority event like a comment or message. The standard way to mention someone is to type “@” followed by the recipient’s name in the message and then select the recipient from a list of results. At-mentions are ubiquitous in apps that have a social element because they facilitate communication and increase user engagement. Last year we released at-mentions in both our iOS and macOS apps.

注意是一种使某人关注诸如评论或消息之类的高优先级事件的简便方法。 提及某人的标准方法是在邮件中键入“ @”,然后输入收件人的姓名,然后从结果列表中选择收件人。 注意在具有社交元素的应用程序中无处不在,因为它们可以促进交流并提高用户参与度。 去年,我们在iOS和macOS应用中发布了提及的内容。

While there are many third-party libraries that enable the feature, we decided to implement our own at-mentions framework. We needed our framework to be compatible with both UIKit and AppKit so we could have either created two custom text fields or extended the existing functionality of the UIText fieldDelegate and NSTextFieldDelegate. We chose the second strategy because it centralized the at-mentions logic for both platforms while maintaining the existing text field delegation flow. This article highlights the key components and lessons learned.

尽管有许多启用该功能的第三方库,但我们决定实现自己的提要框架。 我们需要我们的框架与UIKit和AppKit兼容,因此我们可以创建两个自定义文本字段或扩展UIText fieldDelegate和NSTextFieldDelegate的现有功能。 我们选择第二种策略是因为它集中了两个平台的注意逻辑,同时保留了现有的文本字段委派流程。 本文重点介绍了关键组成部分和经验教训。

This article will cover the main components of the framework:

本文将介绍框架的主要组件:

  1. A trigger reporter that processes the current string in the text view

    触发报告程序,在文本视图中处理当前字符串
  2. Intercepting UITextViewDelegate and NSTextViewDelegate

    拦截UITextViewDelegate和NSTextViewDelegate
  3. A mentions manager that processes tokenized mentions

    处理令牌化提及的提及管理器
  4. A coordinator that ties together the components and reports updates to the client

    协调器,将组件联系在一起并向客户端报告更新

Creating a trigger reporter

创建触发报告器

We called the object used for processing the current string a trigger reporter. A trigger can be any string symbol — in our case, it is the “@” symbol. When a user types “@” in the app the trigger reporter will notify its delegate. The trigger reporter checks for trigger matches in the text input and reports the result to its delegate.

我们将用于处理当前字符串的对象称为触发报告器。 触发器可以是任何字符串符号-在我们的例子中,它是“ @”符号。 当用户在应用程序中键入“ @”时,触发报告程序将通知其委托人。 触发器报告器检查文本输入中的触发器匹配项,并将结果报告给其委托人。

The interface for the trigger reporter is shown below. An in-depth discussion on the regex pattern matching used by the reporter will be covered in a separate article — stay tuned.

触发报告器的界面如下所示。 关于报告者使用的正则表达式模式匹配的深入讨论将在另一篇文章中介绍-请继续关注。

Intercepting the delegate of the text view

拦截文本视图的委托

We know how to check for the at-mention trigger but also need to figure out when to check for the trigger in real-time. Leveraging the system text view delegates seems fitting since they are designed to report text view events; however, we cannot just conform to the text view delegate because the clients are already using it to handle other comment functionalities. What we need then is a way to keep the existing delegate but also respond to text field events for the new at-mentions feature.

我们知道如何检查触发触发器,但是还需要弄清楚何时实时检查触发触发器。 利用系统文本视图委托似乎很合适,因为它们旨在报告文本视图事件。 但是,我们不能仅仅遵循文本视图委托,因为客户端已经在使用它来处理其他注释功能。 然后,我们需要的是一种既保留现有委托人,又响应新的提及功能的文本字段事件的方法。

There is an established way of solving this type of problem: the interceptor pattern. The pattern is used to augment a part of a framework without altering current functionality. In our case, we want to expand the functionality of the text view delegate callbacks while keeping the client side’s use of the text view delegate unchanged. The diagram below illustrates the concept.

有一种解决此类问题的成熟方法:拦截器模式。 该模式用于在不更改当前功能的情况下扩展框架的一部分。 在我们的例子中,我们想扩展文本视图委托回调的功能,同时保持客户端对文本视图委托的使用不变。 下图说明了该概念。

Image for post

Figure 1.0 The Interceptor Pattern

图1.0 拦截器模式

To use the interceptor pattern, we first define what the interceptable interface is.

要使用拦截器模式,我们首先定义什么是可拦截接口。

  1. We define an Interceptable protocol that exposes an interceptableDelegate.

    我们定义了一个Interceptable协议,该协议公开了InterceptableDelegate。
  2. Next, we define a MentionTextInput protocol that provides two callbacks to update the display text with attributed text after a mention is selected (see the video example below).

    接下来,我们定义一个MentionTextInput协议,该协议提供两个回调,以在选择提及后用属性文本更新显示文本(请参见下面的视频示例)。
  3. Because we have both iOS and macOS clients, NSTextField and UITextField conform to MentionTextInput. For brevity purposes, we only show the iOS extensions.

    因为我们同时拥有iOS和macOS客户端,所以NSTextField和UITextField符合MentionTextInput。 为了简洁起见,我们仅显示iOS扩展程序。

Notice that the interceptableDelegate still conforms to UITextViewDelegate. The idea is that when the client creates a text view and sets the delegate of the text view (the delegate is called passThroughDelegate and the text view is called input), it only needs to conform to the UITextViewDelegate while allowing our framework to also respond to the delegate methods.

请注意,interceptableDelegate仍然符合UITextViewDelegate。 这个想法是,当客户端创建文本视图并设置文本视图的委托时(委托称为passThroughDelegate,文本视图称为input),它只需要符合UITextViewDelegate,同时允许我们的框架也响应委托方法。

Our interceptor class is called MentionInterceptor and is responsible for forwarding the text view’s events to the existing text view delegate (set in the client and called passThroughDelegate here) and intercepting those same events.

我们的拦截器类称为MentionInterceptor,负责将文本视图的事件转发到现有的文本视图委托(在客户端中设置,在此处称为passThroughDelegate),并拦截相同的事件。

  1. The mention interceptor is instantiated with an interceptable input, which is either an NSTextView or UITextView object. It then holds on to the original delegate or passThroughDelegate and text view or currentInterceptedInput.

    提及拦截器使用可拦截输入实例化,该输入可以是NSTextView或UITextView对象。 然后,它保留原始委托或passThroughDelegate和文本视图或currentInterceptedInput。
  2. We only care about delegate callbacks that either the passthrough delegate or mention interceptor responds to so we override responds(to:)

    我们只关心传递的委托或提及拦截器响应的委托回调,因此我们覆盖了responds(to:)

  3. Any events not handled by the mention interceptor are forwarded to the text view delegate.

    没有由提及拦截器处理的任何事件都将转发到文本视图委托。

Finally, the mention interceptor implements text view callbacks that it cares about and conforms to the text view delegate. As mentioned earlier, we need our framework to work with both macOS and iOS targets so the MentionInterceptor needs to conform to both NSTextViewDelegate and UITextViewDelegate.

最后,提及拦截器实现了它关心并符合文本视图委托的文本视图回调。 如前所述,我们需要我们的框架可与macOS和iOS目标一起使用,因此MentionInterceptor需要同时符合NSTextViewDelegate和UITextViewDelegate。

  1. The interceptor defers to the passThroughDelegate to see if the text should be replaced.

    拦截器将推迟到passThroughDelegate来查看是否应替换文本。
  2. The text view did change event is first passed to the passThroughDelegate to be handled before the interceptor passes it to its own delegate.’

    文本视图的更改事件首先被传递给passThroughDelegate,然后在拦截器将其传递给自己的委托之前进行处理。

It is interesting to note that in both of the callbacks that the mention interceptor intercepts, it also chooses to forward the events to the passThroughDelegate. We could just have easily blocked the event from reaching the passThroughDelegate. The interceptor pattern is a powerful tool that allows us to augment functionality, in this case, the text view delegation, in a transparent manner without requiring actual changes to the design or existing implementation.

有趣的是,在提到拦截器拦截的两个回调中,它还选择将事件转发到passThroughDelegate。 我们可以很容易地阻止事件到达passThroughDelegate。 拦截器模式是一种强大的工具,它使我们能够以透明的方式扩展功能(在这种情况下为文本视图委派),而无需对设计或现有实现进行实际更改。

Implementing storage for mentions

实现提及存储

The video below illustrates the user at-mentions flow in our iOS app. When the user types in “@”, the interceptor in the mentions framework receives the trigger, processes the text, and delegates back to the app with the search text. The app then uses the search text and presents a table of mentionable results for the user to choose from.

以下视频说明了我们iOS应用中的用户注意流程。 当用户键入“ @”时,提及框架中的拦截器将接收触发器,处理文本并使用搜索文本将其委派回应用。 然后,该应用使用搜索文本并显示可提及结果的表格供用户选择。

Image for post

We need a way to temporarily store the mentions selected by the user so we create a mentions maintainer that is responsible for keeping track of added and removed mentions. It is also in charge of updating the mentions’ indices as the user edits the comment: if a user updates the text upstream of the existing mentions, the indices of the mentions are shifted accordingly while downstream changes are ignored. Below we define the interface for the mentions maintainer.

我们需要一种方法来临时存储用户选择的提及,因此我们创建了提及维护者,负责跟踪添加和删除的提及。 当用户编辑注释时,它还负责更新提及的索引:如果用户在现有提及的上游更新文本,则提及的索引会相应移动,而忽略下游更改。 下面,我们为提及维护者定义接口。

A mention is required to have an itemID, start and end indices, and the corresponding text. The itemID is specific to our needs but there needs to be something that indicates where the mention is located in the text — we use start and end indices.

必须进行提及,以具有itemID,开始和结束索引以及相应的文本。 itemID特定于我们的需求,但是需要有一些内容来指示提及内容在文本中的位置-我们使用开始索引和结束索引。

  1. In the mention maintainer, we keep a private reference to a mentions map that has the start index of each mention as the key. This makes it easy for us to find the mentions that need to be shifted when the text is updated.

    在提及维护者中,我们保留对提及地图的私有引用,该提及地图以每个提及的开始索引为键。 这使我们很容易找到更新文本时需要转移的提及。
  2. We create an extension on Mention to return an updated mention shifted by the offset. We use this new start index and update the mentions, which are structs, map accordingly.

    我们在Mention上创建一个扩展名,以返回通过偏移量偏移的更新提及。 我们使用这个新的开始索引并更新对应的提及(结构)。

Putting it together

把它放在一起

The final component is the mention coordinator which facilitates communication among the mention text input, the trigger reporter, and the mention maintainer. The mention coordinator is injected with the three components and sets itself as their delegates. It reports events to its own delegate, which is the Swift client.

最后一个组件是提及协调器,它促进提及文本输入,触发报告程序和提及维护者之间的通信。 提及协调员被注入了三个组成部分,并将其自身设置为其代表。 它向自己的委托(即Swift客户端)报告事件。

  1. We define the mention coordinator delegate that exposes two methods: both the iOS and macOS clients need to know when to make API requests using the parsed search string. The second method triggers keystroke events for macOS.

    我们定义了提及协调器委托,它公开了两种方法:iOS和macOS客户端都需要知道何时使用已解析的搜索字符串发出API请求。 第二种方法触发macOS的按键事件。
  2. When the trigger reporter detects an @-mention search, the mention coordinator is notified and it, in turn, notifies its delegate, our Swift client, of the search string. Our client then makes a backend request for users matching the search string and displays the results. When the user ends a mention search, the mention coordinator similarly notifies the client.

    当触发器报告程序检测到@提及的搜索时,将通知提及协调者,然后将其通知字符串通知其委托我们的Swift客户端。 然后,我们的客户向与搜索字符串匹配的用户发出后端请求,并显示结果。 当用户结束提及搜索时,提及协调器会类似地通知客户端。

The diagram below illustrates the flow.

下图说明了流程。

Image for post

Implementing at-mentions required multiple independent components each with its own responsibility. Investing in planning and designing the components paid off for us and enabled us to release the feature with minimal maintenance and stability. Because the at-mentions business logic is contained in a separate framework, it was easy to write unit tests — we are very proud to have 100 percent code coverage in the framework!

实施时需要多个独立的组件,每个组件都有自己的责任。 投资于计划和设计组件可以为我们带来回报,并使我们能够以最少的维护和稳定性来发布该功能。 由于关注的业务逻辑包含在一个单独的框架中,因此编写单元测试很容易-我们为拥有100%的代码覆盖率而感到自豪!

Our standalone at-mentions framework is also flexible enough to accommodate future iterations that require additional trigger events like hashtags. Finally, it was a great learning experience using the interceptor pattern in our framework.

我们独立的提要框架也足够灵活,可以容纳需要其他触发事件(如井号)的未来迭代。 最后,在我们的框架中使用拦截器模式是一次很棒的学习经验。

翻译自: https://medium.com/frame-io-engineering/building-an-at-mentions-framework-33ca79bc4740

框架中建立浮动框架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值