测试已测试 | ✓ |
语言语言 | Obj-CObjective C |
许可证 | MIT |
发布最新发布 | 2017年11月 |
由 Ignacio Romero、Ignacio 维护。
重要声明:请更新到 >= 1.9
避免应用被拒绝的风险。更多详细信息请参阅 #361
一个包含增长文本视图和其他有用消息功能的 UIViewController 子类。旨在替代 UITableViewController 和 UICollectionViewController。
此库用于 Slack 的 iOS 应用。它是为了满足我们的需求而构建的,但足够灵活,可以由其他希望为 iOS 建立出色的消息应用的人重用。
YES
/true
,因此请注意,您的整个单元格可能会翻转!有两种方法可以实现
Source/
文件夹复制并拖到您的项目中。Builder/SlackTextViewController.xcodeproj
的项目以创建一个 SlackTextViewController.framework
包。您也可以将库链接到您的项目中。SLKTextViewController
设计用于子类化,就像您通常对 UITableViewController
、UICollectionViewController
或 UIScrollView
所做的那样。这种模式是扩展 UIViewController
的方便方式。SlackTextViewController 在幕后管理很多事情,同时仍然能够添加自定义功能。您可以覆盖方法,并决定调用 super 并执行附加逻辑,或者不调用 super 并覆盖默认逻辑。
首先创建一个 SLKTextViewController
的新子类。
在重写 init 方法时,如果您希望使用 UITableView
版本,则调用
[super initWithTableViewStyle:UITableViewStylePlain]
super.init(tableViewStyle: .Plain)
或 UICollectionView
版本
[super initWithCollectionViewLayout:[UICollectionViewFlowLayout new]]
super.init(collectionViewLayout: UICollectionViewFlowLayout())
或 UIScrollView
版本
[super initWithScrollView:self.myStrongScrollView]
super.init(scrollView: self.myStrongScrollView)
例如 UITableViewDelegate
和 UITableViewDataSource
已经为您设置好了。您将能够调用所有需要的代理和数据源方法来自定义您的控件。
调用 [super init]
将默认调用 [super initWithTableViewStyle:UITableViewStylePlain]
。
当在 Storyboard 中使用 SlackTextViewController 时,您需要重写以下两种自定义方法之一,而不是重写传统的 initWithCoder:
。这种方法有助于保留与程序性方法完全相同的功能,但也限制了您的 SLKTextViewController
子类的 nib 编辑,因为子视图不是从 nib 布局(子视图仍然初始化并程序化布局)。
如果您希望使用 UITableView
版本,则调用
+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder
{
return UITableViewStylePlain;
}
override class func tableViewStyleForCoder(decoder: NSCoder) -> UITableViewStyle {
return .Plain
}
或 UICollectionView
版本
+ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder
{
return [UICollectionViewFlowLayout new];
}
override class func collectionViewLayoutForCoder(decoder: NSCoder) -> UICollectionViewLayout {
return UICollectionViewFlowLayout()
}
查看示例项目,那里演示了一切。有 2 个主要示例(不同的目标)用于测试程序性和 storyboard 方法,还有一个 Swift 示例。大多数功能都为您实现了,您可以快速使用它们。
请随时贡献!
当需要新行时,文本视图会自动扩展,直到达到它的maxNumberOfLines
值。您可以在文本视图中更改此属性的值。
默认情况下,行数设置为最佳适配每个设备的尺寸
在iPhone设备上,横屏模式下,最大行数会根据可用空间进行更改。
某些布局可能需要从下至上显示,并且新子视图将从底部插入。为了启用此功能,您必须使用inverted
标志属性(默认值为YES
/true
)。这实际上会反转整个滚动视图对象。请确保将相同的转换应用于每一个子视图。在UITableView的情况下,调整转换的最佳位置在其数据源方法中,例如
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
cell.transform = self.tableView.transform;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier(kAutoCompletionCellIdentifier) {
cell.textLabel!.text = self.searchResult[indexPath.row]
return cell
}
}
我们使用自动完成来处理很多事情:姓名、频道、表情符号等等。
要设置应用中的自动完成,请按照以下简单步骤操作
您必须首先注册所有想要支持的自动完成检测前缀
[self registerPrefixesForAutoCompletion:@[@"#"]];
self.registerPrefixesForAutoCompletion(["@", "#"])
每次在文本视图中插入新字符时,都会处理光标附近的最接近的单词,并验证它是否包含任何已注册的前缀。
一旦检测到前缀,将调用didChangeAutoCompletionPrefix:andWord:
。这是填充你的数据源和显示/隐藏自动完成视图的理想位置。因此,您必须在您的子类中重写它,以便能够执行其他任务。默认返回NO。
- (void)didChangeAutoCompletionPrefix:(NSString *)prefix andWord:(NSString *)word
{
NSArray *array = [NSArray arrayWithArray:self.channels];
if ([prefix isEqualToString:@"#"] && word.length > 0) {
self.searchResult = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self BEGINSWITH[c]", word]];
}
BOOL show = (self.searchResult.count > 0);
[self showAutoCompletionView:show];
}
override func didChangeAutoCompletionPrefix(prefix: String, andWord word: String) {
let array: NSArray = self.channels
if prefix == "#" && word.characters.count > 0 {
self.searchResult = array.filteredArrayUsingPredicate(NSPredicate(format: "self BEGINSWITH[c] %@", word))
}
let show = (self.searchResult.count > 0)
self.showAutoCompletionView(show)
}
自动完成视图是一个UITableView
实例,因此您需要使用UITableViewDataSource
来填充其单元格。您可以自由地定制单元格。
您不需要自己调用.reloadData
,因为它会在调用showAutoCompletionView
方法后自动触发。
自动完成视图的最大高度默认设置为140 pts。您可以随时更新此值,因此视图将自动根据显示的单元格数量进行调整。
- (CGFloat)heightForAutoCompletionView
{
CGFloat cellHeight = 34.0;
return cellHeight*self.searchResult.count;
}
override func heightForAutoCompletionView() -> CGFloat {
let cellHeight:CGFloat = 34
return cellHeight * CGFloat(self.searchResult.count)
}
如果用户在tableView:didSelectRowAtIndexPath:
中选中了任何自动完成视图单元格,您必须调用acceptAutoCompletionWithString:
来提交自动完成。该方法期望一个与选中项匹配的字符串,您希望将其插入文本视图。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView isEqual:self.autoCompletionView]) {
NSMutableString *item = [self.searchResult[indexPath.row] mutableCopy];
[item appendString:@" "]; // Adding a space helps dismissing the auto-completion view
[self acceptAutoCompletionWithString:item keepPrefix:YES];
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView.isEqual(tableView) {
var item = self.searchResult[indexPath.row]
item += " " // Adding a space helps dismissing the auto-completion view
self.acceptAutoCompletionWithString(item)
}
}
自动完成视图将自动消失,所选字符串将被插入文本视图,替换检测到的前缀和单词。
您可以始终调用cancelAutoCompletion
以退出自动完成模式并刷新UI。
要启用编辑模式,您只需调用editText:
,文本输入将切换到编辑模式,移除左右两个按钮,并将输入栏向上扩展一些,添加“接受”和“取消”按钮。这两个按钮都可在SLKTextInputbar
实例中进行自定义。
要捕获“接受”或“取消”事件,您必须重写以下方法。
- (void)didCommitTextEditing:(id)sender
{
NSString *message = [self.textView.text copy];
[self.messages removeObjectAtIndex:0];
[self.messages insertObject:message atIndex:0];
[self.tableView reloadData];
[super didCommitTextEditing:sender];
}
- (void)didCancelTextEditing:(id)sender
{
[super didCancelTextEditing:sender];
}
override func didCommitTextEditing(sender: AnyObject) {
let message:String = self.textView.text
self.messages.removeAtIndex(0)
self.messages.insert(message, atIndex: 0)
self.tableView!.reloadData()
super.didCommitTextEditing(sender)
}
override func didCancelTextEditing(sender: AnyObject) {
super.didCancelTextEditing(sender)
}
请注意,您必须在某个时刻调用super
,以便文本输入退出编辑模式,重新调整布局并清除文本视图。使用editing
属性来了解是否启用了编辑模式。
您可以将Markdown格式化符号注册,以便可以通过原生上下文菜单(即UIMenuController
)轻松使用它们来包装文本选择。这个功能不处理Markdown的渲染:它的唯一目的是使用户更容易使用格式化工具。可选地,您可以选择启用autoCompleteFormatting
,以便在键盘空格键上双击后,可以自动添加任何挂起的Markdown闭包符号,就像原生手势添加句点一样。句点仍然作为后备被添加。
您首先必须注册格式化符号并分配用于菜单控制器项的标题字符串。
[self.textView registerMarkdownFormattingSymbol:@"*" withTitle:@"Bold"];
self.textView.registerMarkdownFormattingSymbol("*", withTitle: "Bold")
此外,您可以使用UITextViewDelegate
方法中的某些行为来自定义特殊格式化情况。在下面的示例中,当文本选择不是段落时,我们不在上下文菜单中显示引用格式化。
- (BOOL)textView:(SLKTextView *)textView shouldOfferFormattingForSymbol:(NSString *)symbol
{
if ([symbol isEqualToString:@">"]) {
NSRange selection = textView.selectedRange;
// The Quote formatting only applies new paragraphs
if (selection.location == 0 && selection.length > 0) {
return YES;
}
// or older paragraphs too
NSString *prevString = [textView.text substringWithRange:NSMakeRange(selection.location-1, 1)];
if ([[NSCharacterSet newlineCharacterSet] characterIsMember:[prevString characterAtIndex:0]]) {
return YES;
}
return NO;
}
return [super textView:textView shouldOfferFormattingForSymbol:symbol];
}
在以下方法实现中,我们不想允许可以为引用格式化自动完成,因为它不需要闭包。
- (BOOL)textView:(SLKTextView *)textView shouldInsertSuffixForFormattingWithSymbol:(NSString *)symbol prefixRange:(NSRange)prefixRange
{
if ([symbol isEqualToString:@">"]) {
return NO;
}
return [super textView:textView shouldInsertSuffixForFormattingWithSymbol:symbol prefixRange:prefixRange];
}
可选地,您可以启用一个简单的打字指示器,它将在文本输入上方显示。它显示正在键入的人的名字,如果有超过2个人,它将显示“多人在键入”的消息。
要启用打字指示器,只需调用
[self.typingIndicatorView insertUsername:@"John"];
self.typingIndicatorView?.insertUsername("John")
视图将自动附加到文本输入框之上进行动画。默认间隔为6秒后,如果未重新分配相同的名称,视图将以动画方式关闭。
您可以通过以下方式从列表中移除名称:
[self.typingIndicatorView removeUsername:@"John"];
self.typingIndicatorView?.removeUsername("John")
您还可以通过以下方式关闭它:
[self.typingIndicatorView dismissIndicator];
self.typingIndicatorView?.dismissIndicator()
默认情况下,通过拖动手势以取消键盘的功能由 keyboardPanningEnabled
属性启用的。如果您想禁用它,您总是可以做到。您可以使用 UIGestureRecognizerDelegate
方法扩展 verticalPanGesture
的行为。
有时您可能需要隐藏文本输入栏。非常类似于 UINavigationViewController
的API,只需执行以下操作:
[self setTextInputbarHidden:YES animated:YES];
self.setTextInputbarHidden(true, animated: true)
清除文本的摇动手势默认通过 undoShakingEnabled
属性启用。
您可以覆盖 willRequestUndo
来实现您的UI,询问用户是否想要清除文本视图的文本。如果没有输入文本,则不会调用该方法。
如果您没有覆盖 willRequestUndo
,并且 undoShakingEnabled
被设置为 YES
/true
,则会显示系统提示框。
默认情况下启用了一些基本的键控制命令。
didPressRightButton:
,如果处于编辑模式,则调用 didCommitTextEditing:
要添加额外的键控制命令,只需通过覆盖 keyCommands
并追加 super
的数组。
- (NSArray *)keyCommands
{
NSMutableArray *commands = [NSMutableArray arrayWithArray:[super keyCommands]];
// Edit last message
[commands addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow
modifierFlags:0
action:@selector(editLastMessage:)]];
return commands;
}
override var keyCommands: [UIKeyCommand]? {
var commands = super.keyCommands
// Edit last message
let command = UIKeyCommand(input: UIKeyInputUpArrow, modifierFlags: .Command, action: "editLastMessage:")
commands?.append(command)
return commands
}
对于诸如 isExternalKeyboardDetected
、isKeyboardUndocked
、typingSuggestionEnabled
和 isTrackpadEnabled
(仅限iOS 9)之类的键盘特殊检测,有一系列有用的标志。
自适应字体大小默认由 dynamicTypeEnabled
属性启用。如果您愿意,您可以始终禁用它,但文本输入栏仍然会调整以最佳适应文本视图的字体大小。
我们准备了一套有用的 Xcode 模板,这样您就可以快速开始使用 SlackTextViewController。
要安装它们,请打开您的终端并输入
sh ./SlackTextViewController/File\ Templates/install.sh
这些模板也可在Alcatraz中使用。