Description
Proton is a simple library that allows you to extend the behavior of a textview to add rich content that you always wanted. It provides simple API that allows you to extend the textView to include complex content like nested textViews or for that matter, any other UIView or change the text as it is typed as in Markup syntax. The possibilities are endless.
In the simplest terms - It's what you always wanted UITextView to be.
Proton alternatives and similar libraries
Based on the "UI" category.
Alternatively, view Proton alternatives based on common mentions on social networks and blogs.
-
Lottie
An iOS library to natively render After Effects vector animations -
iCarousel
A simple, highly customisable, data-driven 3D carousel for iOS and Mac OS -
IQKeyboardManager
Codeless drop-in universal library allows to prevent issues of keyboard sliding up and cover UITextField/UITextView. Neither need to write any code nor any setup required and much more. -
SVProgressHUD
A clean and lightweight progress HUD for your iOS and tvOS app. -
AsyncDisplayKit
Smooth asynchronous user interfaces for iOS apps. -
DZNEmptyDataSet
A drop-in UITableView/UICollectionView superclass category for showing empty datasets whenever the view has no content to display -
IGListKit
A data-driven UICollectionView framework for building fast and flexible lists. -
FSCalendar
A fully customizable iOS calendar library, compatible with Objective-C and Swift -
TTTAttributedLabel
A drop-in replacement for UILabel that supports attributes, data detectors, links, and more -
animated-tab-bar
:octocat: RAMAnimatedTabBarController is a Swift UI module library for adding animation to iOS tabbar items and icons. iOS library made by @Ramotion -
folding-cell
:octocat: 📃 FoldingCell is an expanding content cell with animation made by @Ramotion -
NVActivityIndicatorView
A collection of awesome loading animations -
SkeletonView
☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting -
LTMorphingLabel
[EXPERIMENTAL] Graceful morphing effects for UILabel written in Swift. -
MGSwipeTableCell
An easy to use UITableViewCell subclass that allows to display swippable buttons with a variety of transitions. -
SWTableViewCell
An easy-to-use UITableViewCell subclass that implements a swippable content view which exposes utility buttons (similar to iOS 7 Mail Application) -
SwiftMessages
A very flexible message bar for iOS written in Swift. -
JTAppleCalendar
The Unofficial Apple iOS Swift Calendar View. Swift calendar Library. iOS calendar Control. 100% Customizable -
XLForm
XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. Fully compatible with Swift & Obj-C. -
JVFloatLabeledTextField
UITextField subclass with floating labels - inspired by Matt D. Smith's design: http://dribbble.com/shots/1254439--GIF-Mobile-Form-Interaction?list=users -
TPKeyboardAvoiding
A drop-in universal solution for moving text fields out of the way of the keyboard in iOS -
FSPagerView
FSPagerView is an elegant Screen Slide Library. It is extremely helpful for making Banner View、Product Show、Welcome/Guide Pages、Screen/ViewController Sliders. -
SVPullToRefresh
Give pull-to-refresh & infinite scrolling to any UIScrollView with 1 line of code. -
AMScrollingNavbar
Scrollable UINavigationBar that follows the scrolling of a UIScrollView -
Koloda
KolodaView is a class designed to simplify the implementation of Tinder like cards on iOS. -
SwipeCellKit
Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift. -
Alerts & Pickers
Advanced usage of UIAlertController and pickers based on it: Telegram, Contacts, Location, PhotoLibrary, Country, Phone Code, Currency, Date... -
SCLAlertView-Swift
Beautiful animated Alert View. Written in Swift -
Macaw
Powerful and easy-to-use vector graphics Swift library with SVG support -
TextFieldEffects
Custom UITextFields effects inspired by Codrops, built using Swift -
ViewDeck
An implementation of the sliding menu found in various iOS apps. -
SwiftEntryKit
SwiftEntryKit is a presentation library for iOS. It can be used to easily display overlays within your iOS apps. -
PageMenu
A paging menu controller built from other view controllers placed inside a scroll view (like Spotify, Windows Phone, Instagram) -
Material Components
[In maintenance mode] Modular and customizable Material Design UI components for iOS -
SideMenu
Simple side/slide menu control for iOS, no code necessary! Lots of customization. Add it to your project in 5 minutes or less. -
SWRevealViewController
A UIViewController subclass for presenting side view controllers inspired on the FaceBook and Wunderlist apps, done right ! -
expanding-collection
:octocat: ExpandingCollection is an animated material design UI card peek/pop controller. iOS library made by @Ramotion -
CSStickyHeaderFlowLayout
UICollectionView replacement of UITableView. Do even more like Parallax Header, Sticky Section Header. Made for iOS 7.
Appwrite - The Open Source Firebase alternative introduces iOS support
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Proton or a related project?
Popular Comparisons
README
Note: While Proton is already a very powerful and flexible framework, it is still in early stages of development. The APIs and public interfaces are still undergoing revisions and may introduce breaking changes with every version bump before reaching stable version 1.0.0.
Proton is a simple library that allows you to extend the behavior of a textview to add rich content that you always wanted. It provides simple API that allows you to extend the textView to include complex content like nested textViews or for that matter, any other UIView. In the simplest terms - It's what you always wanted UITextView
to be.
Proton is designed keeping the following requirements in mind:
- Be a standalone component with nothing that is specific to anything that is required in complex Text Editor. At it's most basic form, it should be able to be used as a UITextView and in most complex form, it should be able to provide rich text editing capabilities which are beyond just text formatting.
- Should be extensible to support adding any view as content in the Editor such that it flows with the text.
- Resizing of content views should automatically resize the containing Editor and support this to nth nesting level.
- Should support extending the appearance of text as the content is typed - for e.g. changing text as it is typed using mark-up syntax and yet, not be aware of any of these requirements directly.
- Should allow for working on multiple editors through the same toolbar based on where the focus is, and yet not be aware of the toolbar itself.
- Respect the bounds of the container i.e. resize to change bounds when the device orientation changes.
- Support a default font and styling like alignment and head indentation.
- And of course, support all this on macOS Catalyst as well with almost no additional effort.
Core Concepts
At it's core, Proton constitutes of following key components:
- EditorView: A substitute for
UITextView
that can be extended to add custom views including other EditorViews. - TextProcessor: Allows you to inject a behavior that is invoked as you type text in the EditorView. This can be used to change text, add/remove attributes like color or replace the added text with an entirely different text/view. For e.g. as you type markup syntax, you can convert the markup text into a formatted text by adding corresponding behavior to the
TextProcessor
. - EditorCommand: Allows you to add a behavior that can be invoked on demand on the given EditorView. For e.g. selecting some text and making it bold.
- Attachment: A container capable of hosting a custom view including another
EditorView
. Attachment is a superchargedNSTextAttachment
that can have automatic constraints applied on it to size it in various configurations like matching content, range of width, fixed width and so on. It also has helper functions to get it's range in it's container as well as to remove itself from the container.
A practical use case
The power of EditorView
to host rich content is made possible by the use of Attachment
which allows hosting any UIView
in the EditorView
. This is further enhanced by use of TextProcessor
and EditorCommand
to add interactive behavior to the editing experience.
Let's take an example of a Panel
and see how that can be created in the EditorView
. Following are the key requirements for a Panel
:
- A text block that is indented and has a custom UI besides the
Editor
. - Change height based on the content being typed.
- Have a different font color than the main text.
- Able to be inserted using a button.
- Able to be inserted by selecting text and clicking a button.
- Able to be inserted in a given Editor by use of
>>
char. - Nice to have: delete using
backspace
key when empty similar to aBlockquote
.
Panel view
The first thing that is required is to create a view that represents the
Panel
. Once we have created this view, we can add it to an attachment and insert it in theEditorView
.extension EditorContent.Name { static let panel = EditorContent.Name("panel") } class PanelView: UIView, BlockContent, EditorContentView { let container = UIView() let editor: EditorView let iconView = UIImageView() var name: EditorContent.Name { return .panel } override init(frame: CGRect) { self.editor = EditorView(frame: frame) super.init(frame: frame) setup() } var textColor: UIColor { get { editor.textColor } set { editor.textColor = newValue } } override var backgroundColor: UIColor? { get { container.backgroundColor } set { container.backgroundColor = newValue editor.backgroundColor = newValue } } private func setup() { // setup view by creating required constraints } }
As the
Panel
contains anEditor
inside itself, the height will automatically change based on the content as it is typed in. To restrict the height to a given maximum value, an absolute size or autolayout constraint may be used.Using the
textColor
property, the default font color may be changed.For the ability to add
Panel
to theEditor
using a button, we can make use ofEditorCommand
. ACommand
can be executed on a givenEditorView
or viaCommandExecutor
that automatically takes care of executing the command on the focussedEditorView
. To insert anEditorView
inside another, we need to first create anAttachment
and then used aCommand
to add to the desired position:class PanelAttachment: Attachment { var view: PanelView init(frame: CGRect) { view = PanelView(frame: frame) super.init(view, size: .fullWidth) view.delegate = self view.boundsObserver = self } var attributedText: NSAttributedString { get { view.attributedText } set { view.attributedText = newValue } } } class PanelCommand: EditorCommand { func execute(on editor: EditorView) { let selectedText = editor.selectedText let attachment = PanelAttachment(frame: .zero) attachment.selectBeforeDelete = true editor.insertAttachment(in: editor.selectedRange, attachment: attachment) let panel = attachment.view panel.editor.maxHeight = 300 panel.editor.replaceCharacters(in: .zero, with: selectedText) panel.editor.selectedRange = panel.editor.textEndRange } }
The code in
PanelCommand.execute
reads theselectedText
fromeditor
and sets it back inpanel.editor
. This makes it possible to take the selected text from main editor, wrap it in a panel and then insert the panel in the main editor replacing the selected text.To allow insertion of a
Panel
using a shortcut text input instead of clicking a button, you can use aTextProcessor
:class PanelTextProcessor: TextProcessing { private let trigger = ">> " var name: String { return "PanelTextProcessor" } var priority: TextProcessingPriority { return .medium } func process(editor: EditorView, range editedRange: NSRange, changeInLength delta: Int, processed: inout Bool) { let line = editor.currentLine guard line.text.string == trigger else { return } let attachment = PanelAttachment(frame: .zero) attachment.selectBeforeDelete = true editor.insertAttachment(in: line.range, attachment: attachment) }
For a requirement like deleting the
Panel
when backspace is tapped at index 0 on an empty Panel,EdtiorViewDelegate
may be utilized:extension PanelAttachment: PanelViewDelegate { func panel(_ panel: PanelView, didReceiveKey key: EditorKey, at range: NSRange, handled: inout Bool) { if key == .backspace, range == .zero, panel.editor.attributedText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { removeFromContainer() handled = true } } }
In the code above,
PanelViewDelegate
is acting as a passthrough forEditorViewDelegate
for theEditor
inside thePanelView
.Checkout the complete code in the ExamplesApp.
Example usages
Changing text as it is typed using custom
TextProcessor
:Adding attributes as it is typed using custom
TextProcessor
:Nested editors
Panel from existing text:
Relaying attributes to editor contained in an attachment:
Highlighting using custom command in Editor:
Find text and scroll in Editor:
Learn more
- Proton API reference is available here.
- For sample code, including the ones for examples shown above, please refer to the Example app.
Questions and feature requests
Feel free to create issues in github should you have any questions or feature requests. While Proton is created as a side project, I'll endeavour to respond to your issues at earliest possible.
License
Proton is released under the Apache 2.0 license. Please see [LICENSE](LICENSE) for details.
*Note that all licence references and agreements mentioned in the Proton README section above
are relevant to that project's source code only.