All Projects → jhurray → Selectabletextview

jhurray / Selectabletextview

Licence: mit
A text view that supports selection and expansion

Programming Languages

swift
15916 projects
swift4
162 projects

Projects that are alternatives of or similar to Selectabletextview

Mycoretextlabel
图文混排 , 实现图片文字混排 , 可显示常规链接比如网址,@,#话题#,手机号 , 邮箱号等 , 可以自定义链接字,设置关键字高亮等功能 . 适用于微博,微信,IM聊天对话等场景 . 实现这些功能仅用了几百行代码,耦合性也较低
Stars: ✭ 192 (-69.33%)
Mutual labels:  ios-sdk, ios-ui
Taniwhatextfield
My first cocoapod framework
Stars: ✭ 26 (-95.85%)
Mutual labels:  ios-sdk, ios-ui
extensions-kit
📦 Collection of Swift+Apple Frameworks extensions for speeding up software development [iOS & iPadOS].
Stars: ✭ 71 (-88.66%)
Mutual labels:  ios-ui, ios-sdk
Swiftcocoadsl
An easy way to write iOS UI
Stars: ✭ 103 (-83.55%)
Mutual labels:  ios-sdk, ios-ui
STTextView
📝 STTextView is a light-weight library that adds a placeholder to the UITextView.
Stars: ✭ 36 (-94.25%)
Mutual labels:  interface-builder, textview
Iblocalizable
Localize your views directly in Interface Builder with IBLocalizable
Stars: ✭ 463 (-26.04%)
Mutual labels:  interface-builder
Simplifyspan
A easy-to-use and powerful Spannable library
Stars: ✭ 522 (-16.61%)
Mutual labels:  textview
Dsgradientprogressview
A simple animated progress bar in Swift
Stars: ✭ 437 (-30.19%)
Mutual labels:  ios-ui
Tweetextfield
Lightweight set of text fields with nice animation and functionality. 🚀 Inspired by https://uimovement.com/ui/2524/input-field-help/
Stars: ✭ 421 (-32.75%)
Mutual labels:  interface-builder
Iosproject
iOS project of collected some demos for iOS App, use Objective-C
Stars: ✭ 5,357 (+755.75%)
Mutual labels:  ios-ui
Htextview
Animation effects to text, not really textview
Stars: ✭ 5,309 (+748.08%)
Mutual labels:  textview
Htmlbuilder
Build valid HTML for Android TextView
Stars: ✭ 506 (-19.17%)
Mutual labels:  textview
Stacklabel
🔥空祖家的堆叠标签(以下碎念:一开始起名字“StackLabel”没想太多结果被人吐槽Stack是整齐堆叠的意思...........好吧这是我的锅不过现在要改也来不及了,好用就行了...吧?
Stars: ✭ 471 (-24.76%)
Mutual labels:  textview
Mkdropdownmenu
🔻 Dropdown Menu for iOS with many customizable parameters to suit any needs
Stars: ✭ 523 (-16.45%)
Mutual labels:  ios-ui
Example Ios Apps
 A curated list of Open Source example iOS apps developed in Swift. An amazing list for people who are beginners and learning ios development and for ios developers who need any example app or feature.
Stars: ✭ 461 (-26.36%)
Mutual labels:  ios-ui
Swiftlanguageweather
Swift Language Weather is an iOS weather app developed in Swift 4.
Stars: ✭ 5,190 (+729.07%)
Mutual labels:  interface-builder
Uitextfield Navigation
🏄‍♂️ UITextField-Navigation makes it easier to navigate between UITextFields and UITextViews
Stars: ✭ 436 (-30.35%)
Mutual labels:  interface-builder
Instantsearch Ios
⚡️ A library of widgets and helpers to build instant-search applications on iOS.
Stars: ✭ 498 (-20.45%)
Mutual labels:  interface-builder
My flutter challenges
Flutter project containing all my flutter UI challenges
Stars: ✭ 563 (-10.06%)
Mutual labels:  ios-ui
Flipview
Flipping views like Gmail & beyond
Stars: ✭ 477 (-23.8%)
Mutual labels:  textview

The Problem

UILabel and UITextView offer unsatisfying support for text selection.

Existing solutions like TTTAttributedLabel are great but offer a somewhat limited API for text selection.

Features

Installation

CocoaPods

Add the following to your Podfile

pod 'SelectableTextView', '~> 1.0.2'

Carthage

Add the following to your Cartfile

github "jhurray/SelectableTextView" ~> 1.0.2

Add to project Manually

Clone the repo and manually add the Files in /SelectableTextView

Usage

import SelectableTextView

let textView = SelectableTextView()
textView.text = "Hello World!"
textView.truncationMode = .truncateTail
textView.alignment = .center
textView.numberOfLines = 1

let greetingValidator = MatchesTextValidator(text: "hello")
textView.registerValidator(_ validator: greetingValidator) { (validText, validator) in
	// Handle selection of "Hello"
}

let exclamationValidator = SuffixValidator(suffix: "!")
textView.registerValidator(_ validator: exclamationValidator) { (validText, validator) in
	// Handle selection of "World!"
}

Text Selection

To create selectable text, you have to create and register a validator. The validator must conform to the TextSelectionValidator protocol.

let hashtagValidator = PrefixValidator(prefix: "#")
textView.registerValidator(validator: hashtagValidator) { (validText, validator) in
	// Handle selection of hashtag
}

You can unregister a validator at any time.

textView.removeValidator(validator: hashtagValidator)

Custom Validators

Here is a resource for creating custom validators using the TextSelectionValidator protocol.

There are other more specific protocols that make customization easier like ContainerTextSelectionValidator and CompositeTextSelectionValidator.

Prewritten Validators

There are a few prewritten validators supplied. These can be used as they are, as building blocks for other more complex validators, and as examples on how to build custom validators.

Text Validators
MatchesTextValidator(text: String, caseSensitive: Bool = false)

ContainsTextValidator(text: String, caseSensitive: Bool = false)

PrefixValidator(text: String, caseSensitive: Bool = false)

SuffixValidator(text: String, caseSensitive: Bool = false)

HashtagTextValidator()

AtSymbolTagTextValidator()

QuotationsTextValidator()

HandlebarsValidator(searchableText: String, replacementText: String)
Abstract Validators
ReverseValidator(validator: TextSelectionValidator)

ContainerValidator(validator: TextSelectionValidator, selectionAttributes: [String: Any]? = nil)

CompositeValidator(validators: [TextSelectionValidator], selectionAttributes: [String: Any]? = nil)
Link Validators
LinkValidator() // Validates any link (HTTP, HTTPS, file, etc...)

HTTPLinkValidator() // Validates HTTP and HTTPS links

UnsafeLinkValidator() // Validates HTTP links

HTTPSLinkValidator()

CustomLinkValidator(urlString: String!, replacementText: String? = nil) 

Customization is possible using the LinkValidatorAttributes protocol. Example here.

Regex Validators
RegexValidator(pattern: String, options: NSRegularExpression.Options = .caseInsensitive)

EmailValidator()

PhoneNumberValidator()

Text Expansion

You can add a text expansion button with the following method:


public func addExpansionButton(collapsedState: (text: String, lines: Int), expandedState: (text: String, lines: Int), attributes: [String: Any]? = nil)

You can remove the expansion button using the following method:

public func removeExpansionButton(numberOfLines: Int = 1)

Example:

let attributes = [NSForegroundColorAttributeName: purple]
textView.addExpansionButton(collapsedState: ("More...", 2),
                             expandedState: ("Less", 0),
                                attributes: attributes)
                                
...

textView.removeExpansionButton(numberOfLines: 2)

You can customize the background color of the expansion button using the SelectedBackgroundColorAttribute property HighlightedTextSelectionAttributes struct as an attribute key.

let attributes: [String: Any] = [HighlightedTextSelectionAttributes.SelectedBackgroundColorAttribute : UIColor.purple]

Customization

text

  • Sets the content of the text view
  • Type: String?

font

  • Sets the font of the text view
  • Type: UIFont
  • Defaults to UIFont.systemFont(ofSize: 17)

textColor

  • Sets the default text color
  • Type: UIColor
  • Defaults to UIColor.darkText

attributedText

  • Overrides the text and textColor with the attributed text
  • Type: NSAttributedString?
  • Defaults to nil

textAlignment

  • Alignment of text in the text view
  • Type: TextAlignment
  • Supports 3 types: .left, .right, .center
  • Defaults to .left

lineBreakMode

  • Determines how the text view handles new lines
  • Type: LineBreakMode
  • Supports 1 type: .wordWrap
    • Defaults to . wordWrap
  • See Goals

truncationMode

  • Determines the bahavior of the last word in the last line of the text view
  • Type: TruncationMode
  • Supports 2 types: .clipping, .truncateTail
  • Defaults to .clipping
  • See Goals

numberOfLines

  • Determines the number of lines in the text view
  • Type: Int
  • Defaults to 0
  • 0 lines means unbounded, similar to UILabel

lineSpacing

  • Determines the spacing between lines
  • Type: CGFloat
  • Defaults to 0
  • Supports negative values

textContainerInsets

  • Sets the content inset of the text view
  • Type: UIEdgeInsets
  • Defaults to UIEdgeInsets.zero

selectionAttributes

  • Sets the default selection attributes for selectable text
  • Type: [String : AnyObject]?
  • Defaults: color = tintColor, font = boldSystemFont(ofSize: font.pointSize + 2)

isExpanded

  • Tracks the state of the expansion button
  • Type: Bool?
  • Defaults to nil. Will only return a value if the expansion button is added
  • If the expansion button is added, this property will toggle the state

textContentSize

  • Readonly, returns the size of the text content
  • Type: CGSize

isSelectionEnabled

  • Determines if selection is enabled for the text view
  • Type: Bool
  • Defaults to true

isScrollEnabled

  • Determines if scrolling is enabled for the text view
  • Type: Bool
  • Defaults to false

scrollDelegate

  • Forwards scrolling events fron the text view
  • Type: SelectableTextViewDelegate?

delegate

  • Delegates work for the text view
  • Type: SelectableTextViewScrollDelegate?

Supported Escape Characters

  • New Line \n
  • Tab \t
  • Null Terminator \0

If you want to have text next to to a selectabe portion of text but still validate the text correctly, use the null terminator.

let text = "The period next to the #Hashtag\0. Will not be highlighted if I use a hashtag validator."

Miscelaneous

framesOfWordsMatchingValidator

You can get the relative frames of words within the text view with the method below. This is how I set up the stars effect in the first example gif.

public func framesOfWordsMatchingValidator(_ validator: TextSelectionValidator) -> [CGRect]
Tab Length

You can adjust the number of spaces a tab character creates using TabTextModelConfig.numberOfSpaces. The default value is 4.

TabTextModelConfig.numberOfSpaces = 2

Interface Builder

You can set most customization properties via interface builder. SelectableTextView is marked as @IBDesignable.

  • numberOfLines: Int
  • text: String
  • textColor: UIColor
  • lineSpacing: Float
  • isSelectionEnabled: Bool
  • isScrollEnabled: Bool
  • fontSize: Float
  • truncateTail: Bool
  • topTextInsets: Float
  • bottomTextInsets: Float
  • leftTextInsets: Float
  • rightTextInsets: Float

Delegate

Default implementations are provided for all SelectableTextViewDelegate methods.

public protocol SelectableTextViewDelegate: class {
    
    /// Resolves conflict between multiple validates that return `true` from their `validate:` method
    //
    // i.e. PrefixTextValidator for `#` and `#my` will both return true for `#myCoolHashtag`,
    // but the actions they are registered for may differ
    //
    /// Default behavior is to choose the first validator in the composite validator's `validators` array
    func resolveValidationConflictsForSelectableTextView(textView: SelectableTextView, conflictingValidators: [TextSelectionValidator]) -> TextSelectionValidator
    
    /// Defaults to `false`
    func animateExpansionButtonForSelectableTextView(textView: SelectableTextView) -> Bool
    
    /// Defaults to `.truncateTail`
    func truncationModeForWordsThatDontFitForSelectableTextView(textView: SelectableTextView) -> TruncationMode
    
    /// Optional, Default empty implementation provideed
    func selectableTextViewContentHeightDidChange(textView: SelectableTextView, oldHeight: CGFloat, newHeight: CGFloat)
}

Scrolling

SelectableTextView supports scrolling and forwards scroll events through SelectableTextViewScrollDelegate.

public protocol SelectableTextViewScrollDelegate: class {
    
    func selectableTextViewDidScroll(_ scrollView: UIScrollView)
    func selectableTextViewWillBeginDragging(_ scrollView: UIScrollView)
    func selectableTextViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
    func selectableTextViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
    func selectableTextViewWillBeginDecelerating(_ scrollView: UIScrollView)
    func selectableTextViewDidEndDecelerating(_ scrollView: UIScrollView)
    func selectableTextViewDidEndScrollingAnimation(_ scrollView: UIScrollView)
}

You can also scroll to specific words or the first word that passes a validator.

/// Scrolls to the first instance of the word
/// Attempts to match the text and display text of a word
public func scrollToWord(_ word: String, position: ScrollPosition, animated: Bool)
    
   /// Scrolls to the first instance of a word that passes the provided TextSelectionValidator
public func scrollToWordPassingValidator(_ validator: TextSelectionValidator, position: ScrollPosition, animated: Bool)

Goals

  • Character wrapping
  • More truncation styles: .head, .center

Contact Info && Contributing

Feel free to email me at [email protected]. I'd love to hear your thoughts on this, or see examples where this has been used.

MIT License

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].