SlackTextViewController
⛔️**DEPRECATED** ⛔️ A drop-in UIViewController subclass with a growing text input view and other useful messaging features
Top Related Projects
A React-inspired view framework for iOS.
A data-driven UICollectionView framework for building fast and flexible lists.
Smooth asynchronous user interfaces for iOS apps.
Epoxy is an Android library for building complex screens in a RecyclerView
:octocat: 📃 FoldingCell is an expanding content cell with animation made by @Ramotion
Smooth asynchronous user interfaces for iOS apps.
Quick Overview
SlackTextViewController is a drop-in UIViewController subclass with a growing text input view and other useful messaging features. It's designed to be a replacement for UITableViewController & UICollectionViewController, providing a messaging interface similar to the one in the Slack iOS app.
Pros
- Highly customizable text input view with growing and shrinking capabilities
- Autocompletion support for @mentions and custom commands
- Seamless integration with UITableView and UICollectionView
- Optimized for performance, even with large amounts of content
Cons
- Primarily designed for iOS, limiting cross-platform compatibility
- May require additional customization for non-messaging applications
- Learning curve for developers unfamiliar with its architecture
- Last updated in 2018, potentially lacking support for newer iOS features
Code Examples
- Creating a SlackTextViewController:
class MyViewController: SLKTextViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.dataSource = self
self.tableView?.delegate = self
}
}
- Customizing the text input view:
override func viewDidLoad() {
super.viewDidLoad()
self.textView.placeholder = "Type a message"
self.textView.layer.borderColor = UIColor.lightGray.cgColor
self.textView.layer.borderWidth = 1.0
self.textView.layer.cornerRadius = 5.0
}
- Handling text input:
override func didPressRightButton(_ sender: Any?) {
let message = self.textView.text
// Process the message
self.textView.text = ""
super.didPressRightButton(sender)
}
Getting Started
-
Install via CocoaPods by adding to your Podfile:
pod 'SlackTextViewController'
-
Import the library in your Swift file:
import SlackTextViewController
-
Subclass SLKTextViewController in your view controller:
class MyViewController: SLKTextViewController { // Your implementation here }
-
Customize the text input view and implement necessary delegate methods as shown in the code examples above.
Competitor Comparisons
A React-inspired view framework for iOS.
Pros of ComponentKit
- Declarative UI programming model, making it easier to manage complex UI states
- Efficient rendering through intelligent diffing and batching of UI updates
- Strong focus on performance, particularly for large, scrolling lists
Cons of ComponentKit
- Steeper learning curve due to its unique architecture and concepts
- Limited to Objective-C, while SlackTextViewController supports both Objective-C and Swift
- Less flexibility for custom UI components compared to SlackTextViewController
Code Comparison
SlackTextViewController:
SLKTextViewController *textViewController = [SLKTextViewController new];
textViewController.textView.placeholder = @"Message";
textViewController.bounces = YES;
textViewController.keyboardPanningEnabled = YES;
[self.navigationController pushViewController:textViewController animated:YES];
ComponentKit:
CKComponentScope scope(self, @"messageInput");
CKComponent *component = [CKComponent
newWithView:{[UIView class], {{@selector(setBackgroundColor:), [UIColor whiteColor]}}}
size:{}
children:{
{messageInputComponent, .position = {.type = CKComponentPositionTypeRelative}}
}
];
Summary
ComponentKit offers a more declarative and performance-focused approach to UI development, while SlackTextViewController provides a simpler, more traditional UIKit-based solution. ComponentKit excels in complex, data-driven UIs, whereas SlackTextViewController is better suited for quick implementation of chat-like interfaces with built-in text input functionality.
A data-driven UICollectionView framework for building fast and flexible lists.
Pros of IGListKit
- Designed for building complex and performant list-based UIs
- Supports diffing for efficient updates and animations
- Provides a more flexible and modular architecture for list management
Cons of IGListKit
- Steeper learning curve due to its more complex architecture
- May be overkill for simpler list-based interfaces
- Requires more setup and configuration compared to SlackTextViewController
Code Comparison
SlackTextViewController:
SLKTextViewController *textViewController = [SLKTextViewController new];
textViewController.textView.placeholder = @"Message";
textViewController.bounces = YES;
textViewController.keyboardPanningEnabled = YES;
IGListKit:
let adapter = ListAdapter(updater: ListAdapterUpdater(), viewController: self)
adapter.collectionView = collectionView
adapter.dataSource = self
Summary
IGListKit offers more advanced features for complex list-based UIs, while SlackTextViewController focuses on providing a customizable text input interface. IGListKit's diffing and modular architecture make it suitable for high-performance list management, but it may be more complex to implement. SlackTextViewController is simpler to set up and use, particularly for chat-like interfaces, but may not be as flexible for diverse list-based UIs.
Smooth asynchronous user interfaces for iOS apps.
Pros of Texture
- Offers a more comprehensive UI framework with advanced layout and asynchronous rendering capabilities
- Provides better performance for complex, scrolling UIs with large datasets
- Supports a wider range of UI components and customization options
Cons of Texture
- Steeper learning curve due to its more complex architecture
- Requires more setup and configuration compared to SlackTextViewController
- May be overkill for simpler UI implementations
Code Comparison
SlackTextViewController:
SLKTextViewController *textViewController = [SLKTextViewController new];
textViewController.textView.placeholder = @"Message";
textViewController.bounces = YES;
textViewController.keyboardPanningEnabled = YES;
Texture:
let node = ASDisplayNode()
node.automaticallyManagesSubnodes = true
node.layoutSpecBlock = { _, _ in
ASInsetLayoutSpec(insets: .zero, child: ASTextNode())
}
Summary
Texture offers more advanced features and better performance for complex UIs, while SlackTextViewController provides a simpler solution focused on text input. Texture's broader scope comes with a steeper learning curve, making it potentially excessive for basic implementations. The choice between the two depends on the project's complexity and performance requirements.
Epoxy is an Android library for building complex screens in a RecyclerView
Pros of Epoxy
- More flexible and powerful for building complex, heterogeneous RecyclerViews
- Better performance optimization for large lists with many view types
- Supports data binding and view binding out of the box
Cons of Epoxy
- Steeper learning curve due to its more complex architecture
- Requires more boilerplate code for simple use cases
- Limited to Android development, while SlackTextViewController is for iOS
Code Comparison
SlackTextViewController (Objective-C):
SLKTextViewController *textViewController = [SLKTextViewController new];
textViewController.textView.placeholder = @"Message";
textViewController.bounces = YES;
textViewController.keyboardPanningEnabled = YES;
Epoxy (Kotlin):
class MyEpoxyController : EpoxyController() {
override fun buildModels() {
header {
id("header")
title("My List")
}
items.forEach { item ->
itemView {
id(item.id)
title(item.title)
}
}
}
}
Summary
Epoxy is a more powerful and flexible solution for building complex RecyclerViews in Android, offering better performance optimization and support for data binding. However, it comes with a steeper learning curve and more boilerplate code. SlackTextViewController, on the other hand, is specifically designed for iOS and focuses on providing a customizable text input component with additional features like autocomplete and media attachments.
:octocat: 📃 FoldingCell is an expanding content cell with animation made by @Ramotion
Pros of folding-cell
- Unique and visually appealing animation for expanding/collapsing cells
- Lightweight and focused on a specific UI component
- Easy to implement in various UITableView or UICollectionView scenarios
Cons of folding-cell
- Limited to a specific UI pattern, less versatile than SlackTextViewController
- May require additional customization for complex use cases
- Less actively maintained compared to SlackTextViewController
Code Comparison
SlackTextViewController:
let textView = SLKTextView()
textView.placeholder = "Enter message"
textView.delegate = self
folding-cell:
let cell = FoldingCell()
cell.itemCount = 2
cell.delegate = self
Summary
While folding-cell offers a unique and visually appealing animation for expanding and collapsing cells, it is more focused on a specific UI component. SlackTextViewController, on the other hand, provides a more comprehensive solution for messaging interfaces with features like autocomplete and media attachments. The choice between the two depends on the specific requirements of your project and the desired user experience.
Smooth asynchronous user interfaces for iOS apps.
Pros of AsyncDisplayKit
- Offers advanced asynchronous rendering and layout capabilities, improving performance for complex UIs
- Provides a more comprehensive set of UI components and tools for building responsive interfaces
- Better suited for large-scale applications with intricate UI requirements
Cons of AsyncDisplayKit
- Steeper learning curve due to its more complex architecture and concepts
- May be overkill for simpler applications or those with less demanding UI needs
- Requires more setup and configuration compared to SlackTextViewController
Code Comparison
SlackTextViewController:
SLKTextViewController *textViewController = [SLKTextViewController new];
textViewController.textView.placeholder = @"Message";
textViewController.bounces = YES;
textViewController.shakeToClearEnabled = YES;
AsyncDisplayKit:
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.backgroundColor = [UIColor redColor];
node.bounds = CGRectMake(0, 0, 100, 100);
[self.view addSubnode:node];
Summary
AsyncDisplayKit offers more advanced features and better performance for complex UIs, making it suitable for large-scale applications. However, it comes with a steeper learning curve and may be excessive for simpler projects. SlackTextViewController is more focused on text input functionality and is easier to implement, but lacks the comprehensive UI toolkit provided by AsyncDisplayKit.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Deprecation
We are no longer providing support for SlackTextViewController
. This project satisfied all of our iOS messaging needs in the past and we are proud to have contributed it to the open-source community. Today, in order to delight our users with a solution that is highly tailored and rapidly iterated-upon, we have shifted focus to our internal projects. Unfortunately, this renders us lacking the capacity to support our past projects in addition to our newer, internal projects. This project has been deprecated as a result.
SlackTextViewController
IMPORTANT NOTICE: Please update to >= 1.9
to avoid any risk of app rejection.
More details in #361
A drop-in UIViewController subclass with a growing text input view and other useful messaging features. Meant to be a replacement for UITableViewController & UICollectionViewController.
This library was historically used in our iOS app. At its inception, the library satisfied our product needs and was flexible enough to be reused by others wanting to build great messaging apps for iOS.
Feature List
Core
- Works out of the box with UITableView or UICollectionView or UIScrollView
- Growing Text View, with line count limit support
- Flexible UI built with Auto Layout
- Customizable: provides left and right button, and toolbar outlets
- Tap Gesture for dismissing the keyboard
- External keyboard commands support
- Undo/Redo (with keyboard commands and UIMenuController)
- Text Appending APIs
Additional
- Autocomplete Mode by registering any prefix key (
@
,#
,/
) - Edit Mode
- Markdown Formatting
- Typing Indicator display
- Shake Gesture for clearing text view
- Multimedia Pasting (png, gif, mov, etc.)
- Inverted Mode for displaying cells upside-down (using CATransform) -- a necessary hack for some messaging apps.
YES
/true
by default, so beware, your entire cells might be flipped! - Tap Gesture for dismissing the keyboard
- Panning Gesture for sliding down/up the keyboard
- Hideable TextInputbar
- Dynamic Type for adjusting automatically the text input bar height based on the font size.
- Bouncy Animations
Compatibility
- Carthage & CocoaPods
- Objective-C & Swift
- iOS 7, 8 & 9
- iPhone & iPad
- Storyboard
- UIPopOverController & UITabBarController
- Container View Controller
- Auto-Rotation
- iPad Multitasking (iOS 9 only)
- Localization
Installation
With CocoaPods:
pod "SlackTextViewController"
With Carthage:
github "slackhq/SlackTextViewController"
Manually:
There are two ways to do this:
- Copy and drag the
Source/
folder to your project. - or compile the project located in
Builder/SlackTextViewController.xcodeproj
to create aSlackTextViewController.framework
package. You could also link the library into your project.
How to use
Subclassing
SLKTextViewController
is meant to be subclassed, like you would normally do with UITableViewController or UICollectionViewController or UIScrollView. This pattern is a convenient way of extending UIViewController. SlackTextViewController manages a lot behind the scenes while still providing the ability to add custom behaviours. You may override methods, and decide to call super and perform additional logic, or not to call super and override default logic.
Start by creating a new subclass of SLKTextViewController
.
In the init overriding method, if you wish to use the UITableView
version, call:
Obj-C
[super initWithTableViewStyle:UITableViewStylePlain]
Swift
super.init(tableViewStyle: .Plain)
or the UICollectionView
version:
Obj-C
[super initWithCollectionViewLayout:[UICollectionViewFlowLayout new]]
Swift
super.init(collectionViewLayout: UICollectionViewFlowLayout())
or the UIScrollView
version:
Obj-C
[super initWithScrollView:self.myStrongScrollView]
Swift
super.init(scrollView: self.myStrongScrollView)
Protocols like UITableViewDelegate
and UITableViewDataSource
are already setup for you. You will be able to call whatever delegate and data source methods you need for customising your control.
Calling [super init]
will call [super initWithTableViewStyle:UITableViewStylePlain]
by default.
Storyboard
When using SlackTextViewController with storyboards, instead of overriding the traditional initWithCoder:
you will need to override any of the two custom methods below. This approach helps preserving the exact same features from the programatic approach, but also limits the edition of the nib of your SLKTextViewController
subclass since it doesn't layout subviews from the nib (subviews are still initialized and layed out programatically).
if you wish to use the UITableView
version, call:
Obj-C
+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder
{
return UITableViewStylePlain;
}
Swift
override class func tableViewStyleForCoder(decoder: NSCoder) -> UITableViewStyle {
return .Plain
}
or the UICollectionView
version:
Obj-C
+ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder
{
return [UICollectionViewFlowLayout new];
}
Swift
override class func collectionViewLayoutForCoder(decoder: NSCoder) -> UICollectionViewLayout {
return UICollectionViewFlowLayout()
}
Sample Project
Check out the sample project, everything is demo'd there. There are 2 main examples (different targets) for testing the programatic and storyboard approaches, and a Swift example. Most of the features are implemented for you to quickly start using them.
Feel free to contribute!
Features
Growing Text View
The text view expands automatically when a new line is required, until it reaches its maxNumberOfLines
value. You may change this property's value in the textView.
By default, the number of lines is set to best fit each device dimensions:
- iPhone 4 (<=480pts): 4 lines
- iPhone 5/6 (>=568pts): 6 lines
- iPad (>=768pts): 8 lines
On iPhone devices, in landscape orientation, the maximum number of lines is changed to fit the available space.
Inverted Mode
Some layouts may require to show from bottom to top and new subviews are inserted from the bottom. To enable this, you must use the inverted
flag property (default is YES
/true
). This will actually invert the entire ScrollView object. Make sure to apply the same transformation to every subview. In the case of UITableView, the best place for adjusting the transformation is in its data source methods like:
Obj-C
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
cell.transform = self.tableView.transform;
}
Swift
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) {
cell.transform = self.tableView.transform
}
}
Autocompletion
We use autocompletion for many things: names, channels, emoji, and more.
To set up autocompletion in your app, follow these simple steps:
1. Registration
You must first register all the prefixes you'd like to support for autocompletion detection:
Obj-C
[self registerPrefixesForAutoCompletion:@[@"#"]];
Swift
self.registerPrefixesForAutoCompletion(["@", "#"])
2. Processing
Every time a new character is inserted in the text view, the nearest word to the caret will be processed and verified if it contains any of the registered prefixes.
Once the prefix has been detected, didChangeAutoCompletionPrefix:andWord:
will be called. This is the perfect place to populate your data source and show/hide the autocompletion view. So you must override it in your subclass, to be able to perform additional tasks. Default returns NO.
Obj-C
- (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];
}
Swift
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)
}
The autocompletion view is a UITableView
instance, so you will need to use UITableViewDataSource
to populate its cells. You have complete freedom for customizing the cells.
You don't need to call reloadData
yourself, since it will be invoked automatically right after calling the showAutoCompletionView
method.
3. Layout
The maximum height of the autocompletion view is set to 140 pts by default. You can update this value anytime, so the view automatically adjusts based on the amount of displayed cells.
Obj-C
- (CGFloat)heightForAutoCompletionView
{
CGFloat cellHeight = 34.0;
return cellHeight*self.searchResult.count;
}
Swift
override func heightForAutoCompletionView() -> CGFloat {
let cellHeight:CGFloat = 34
return cellHeight * CGFloat(self.searchResult.count)
}
4. Confirmation
If the user selects any autocompletion view cell on tableView:didSelectRowAtIndexPath:
, you must call acceptAutoCompletionWithString:
to commit autocompletion. That method expects a string matching the selected item, that you would like to be inserted in the text view.
Obj-C
- (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];
}
}
Swift
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView.isEqual(self.autoCompletionView) {
var item = self.searchResult[indexPath.row]
item += " " // Adding a space helps dismissing the auto-completion view
self.acceptAutoCompletionWithString(item)
}
}
The autocompletion view will automatically be dismissed and the chosen string will be inserted in the text view, replacing the detected prefix and word.
You can always call cancelAutoCompletion
to exit the autocompletion mode and refresh the UI.
Edit Mode
To enable edit mode, you simply need to call editText:
, and the text input will switch to edit mode, removing both left and right buttons, extending the input bar a bit higher with "Accept" and "Cancel" buttons. Both of this buttons are accessible in the SLKTextInputbar
instance for customisation.
To capture the "Accept" or "Cancel" events, you must override the following methods.
Obj-C
- (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];
}
Swift
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)
}
Notice that you must call super
at some point, so the text input exits the edit mode, re-adjusting the layout and clearing the text view.
Use the editing
property to know if the editing mode is on.
Markdown Formatting
You can register markdown formatting symbols so they can easily be used to wrap a text selection, with the help of the native contextual menu, aka UIMenuController
. This feature doesn't take care of the rendering of the markdown: it's sole purpose is to ease the formatting tools to the user.
Optionally, you can enable autoCompleteFormatting
so any pending markdown closure symbol can be added automatically after double tapping on the keyboard spacebar, just like the native gesture to add a sentence period. The sentence period is still being added as a fallback.
1. Registration
You must first register the formatting symbol and assign a title string to be used in the menu controller item.
Obj-C
[self.textView registerMarkdownFormattingSymbol:@"*" withTitle:@"Bold"];
Swift
self.textView.registerMarkdownFormattingSymbol("*", withTitle: "Bold")
2. Customisation
Futher more, you can customise some of the behavior for special formatting cases, using the UITextViewDelegate
methods.
In the following example, we don't present the Quote formatting in the contextual menu when the text selection isn't a paragraph.
Obj-C
- (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];
}
In this other method implementation, we don't want to allow auto-completion for the Quote formatting since it doesn't require a closure.
Obj-C
- (BOOL)textView:(SLKTextView *)textView shouldInsertSuffixForFormattingWithSymbol:(NSString *)symbol prefixRange:(NSRange)prefixRange
{
if ([symbol isEqualToString:@">"]) {
return NO;
}
return [super textView:textView shouldInsertSuffixForFormattingWithSymbol:symbol prefixRange:prefixRange];
}
Typing Indicator
Optionally, you can enable a simple typing indicator, which will be displayed right above the text input. It shows the name of the people that are typing, and if more than 2, it will display "Several are typing" message.
To enable the typing indicator, just call:
Obj-C
[self.typingIndicatorView insertUsername:@"John"];
Swift
self.typingIndicatorView?.insertUsername("John")
and the view will automatically be animated on top of the text input. After a default interval of 6 seconds, if the same name hasn't been assigned once more, the view will be dismissed with animation.
You can remove names from the list by calling:
Obj-C
[self.typingIndicatorView removeUsername:@"John"];
Swift
self.typingIndicatorView?.removeUsername("John")
You can also dismiss it by calling:
Obj-C
[self.typingIndicatorView dismissIndicator];
Swift
self.typingIndicatorView?.dismissIndicator()
Panning Gesture
Dismissing the keyboard with a panning gesture is enabled by default with the keyboardPanningEnabled
property. You can always disable it if you'd like. You can extend the verticalPanGesture
behaviors with the UIGestureRecognizerDelegate
methods.
Hideable TextInputbar
Sometimes you may need to hide the text input bar.
Very similar to UINavigationViewController
's API, simply do:
Obj-C
[self setTextInputbarHidden:YES animated:YES];
Swift
self.setTextInputbarHidden(true, animated: true)
Shake Gesture
A shake gesture to clear text is enabled by default with the undoShakingEnabled
property.
You can optionally override willRequestUndo
, to implement your UI to ask the users if he would like to clean the text view's text. If there is not text entered, the method will not be called.
If you don't override willRequestUndo
and undoShakingEnabled
is set to YES
/true
, a system alert will be shown.
External Keyboard
There a few basic key commands enabled by default:
- cmd + z -> undo
- shift + cmd + z -> redo
- return key -> calls
didPressRightButton:
, ordidCommitTextEditing:
if in edit mode - shift/cmd + return key -> line break
- escape key -> exits edit mode, or auto-completion mode, or dismisses the keyboard
- up & down arrows -> vertical cursor movement
To add additional key commands, simply override keyCommands
and append super
's array.
Obj-C
- (NSArray *)keyCommands
{
NSMutableArray *commands = [NSMutableArray arrayWithArray:[super keyCommands]];
// Edit last message
[commands addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow
modifierFlags:0
action:@selector(editLastMessage:)]];
return commands;
}
Swift
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
}
There are also a set of useful flags for keyboard special detections such as isExternalKeyboardDetected
, isKeyboardUndocked
, typingSuggestionEnabled
and isTrackpadEnabled
(iOS 9 only)
Dynamic Type
Dynamic Type is enabled by default with the dynamicTypeEnabled
property. You can always disable it if you'd like, but the text input bar would still adjust to best fit the font size of the text view.
Xcode Templates
We have prepared a set of useful Xcode templates so you can quickly start using SlackTextViewController.
To install them, open up your terminal and type:
sh ./SlackTextViewController/File\ Templates/install.sh
These templates are also available in Alcatraz.
Top Related Projects
A React-inspired view framework for iOS.
A data-driven UICollectionView framework for building fast and flexible lists.
Smooth asynchronous user interfaces for iOS apps.
Epoxy is an Android library for building complex screens in a RecyclerView
:octocat: 📃 FoldingCell is an expanding content cell with animation made by @Ramotion
Smooth asynchronous user interfaces for iOS apps.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot