Skip to content

Instantly share code, notes, and snippets.

@MosheBerman
Created January 20, 2016 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MosheBerman/d65408b75dc28a7046e0 to your computer and use it in GitHub Desktop.
Save MosheBerman/d65408b75dc28a7046e0 to your computer and use it in GitHub Desktop.
A broken agreement view class that its supposed to interpolate text fields with the form text.
//
// AgreementView.swift
// Intake
//
// Created by Moshe Berman on 12/11/15.
// Copyright © 2015 Moshe Berman. All rights reserved.
//
import UIKit
class AgreementView: UITextView, NSLayoutManagerDelegate {
var delimiter = "__x__"
var indices : [NSRange] = []
var textFields : [AgreementTextField] = []
var formfields : [FormField] = []
var agreement : Form? {
didSet {
self.cleanup()
if let agreement = self.agreement {
self.text = agreement.agreementText
self.formfields = agreement.allFields()
self.showTextFields()
}
}
}
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
self.textContainer.layoutManager?.delegate = self
self.font = UIFont(descriptor: UIFontDescriptor.preferredFontDescriptorWithTextStyle(UIFontTextStyleBody), size: 0)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.textContainer.layoutManager?.delegate = self
self.font = UIFont(descriptor: UIFontDescriptor.preferredFontDescriptorWithTextStyle(UIFontTextStyleBody), size: 0)
}
// MARK: - Show the agreement input fields
func showTextFields() {
self.calculateTextFieldIndices()
self.createTextFieldsForFormFields()
self.createAndAssignExclusionPathsForInputTextFields()
self.installTextFields()
}
// MARK: - Form Fields
func createTextFieldsForFormFields () {
self.textFields = []
var index = 0
let count = self.formfields.count
while index < count {
let formField = self.formfields[index]
let textField = AgreementTextField(frame: CGRectZero, formField: formField)
textField.placeholder = formField.displayName
self.textFields.append(textField)
index = index + 1
}
}
// Calculate where to put the text fields
func createAndAssignExclusionPathsForInputTextFields () {
var index = 0
let textFieldCount = self.textFields.count
var exclusionPaths : [UIBezierPath] = []
while index < textFieldCount {
let textField : AgreementTextField = self.textFields[index]
let location = self.calculatePositionOfPlaceholderAtIndex(index)
let size = textField.intrinsicContentSize()
textField.frame = CGRectMake(location.x, location.y, size.width, size.height)
exclusionPaths.append(textField.exclusionPath())
self.textContainer.exclusionPaths = exclusionPaths
self.layoutManager.ensureLayoutForTextContainer(self.textContainer)
index = index + 1
}
self.textContainer.exclusionPaths = exclusionPaths
}
func installTextFields() {
for field in self.textFields {
self.addSubview(field)
}
}
// MARK: - Helpers
// Find the indices of all of the placeholders.
func calculateTextFieldIndices () {
var indicesOfDelimiters : [NSRange] = []
let searchString = NSString(string: self.textStorage.string)
var nextDelimiterRange : NSRange = NSMakeRange(0, searchString.length)
while nextDelimiterRange.location != NSNotFound
{
nextDelimiterRange = searchString.rangeOfString(self.delimiter, options: [], range: nextDelimiterRange)
if nextDelimiterRange.location != NSNotFound {
let location = nextDelimiterRange.location - (self.delimiter.characters.count * indicesOfDelimiters.count)
let rangeToAppend = NSMakeRange(location, self.delimiter.characters.count)
indicesOfDelimiters.append(rangeToAppend) // Grab actual location
nextDelimiterRange = NSMakeRange(nextDelimiterRange.location + nextDelimiterRange.length, searchString.length - (nextDelimiterRange.location + nextDelimiterRange.length))
}
}
self.indices = indicesOfDelimiters
}
// Figure out where the text container wanted to put the
// placeholder glyph and use that to show the text field.
func calculatePositionOfPlaceholderAtIndex(textIndex : NSInteger) -> CGPoint {
let layoutManager : NSLayoutManager = self.textContainer.layoutManager!
let delimiterRange = self.indices[textIndex]
let characterIndex = delimiterRange.location
let glyphRange = self.layoutManager.glyphRangeForCharacterRange(delimiterRange, actualCharacterRange:nil)
let glyphIndex = glyphRange.location
let rect = layoutManager.lineFragmentRectForGlyphAtIndex(glyphIndex, effectiveRange: nil, withoutAdditionalLayout: true)
let remainingRect : UnsafeMutablePointer<CGRect> = nil
let textContainerRect = self.textContainer.lineFragmentRectForProposedRect(rect, atIndex: characterIndex, writingDirection: .LeftToRight, remainingRect: remainingRect)
let position = CGPointMake(rect.origin.x, textContainerRect.origin.y)
print("Position: \(position) Character Index: \(characterIndex), Manager Rect: \(rect), Text Container Rect: \(textContainerRect)")
return position
}
// MARK: - Cleanup
func cleanup() {
for textField in self.textFields {
textField.removeFromSuperview()
}
self.textFields.removeAll()
self.indices.removeAll()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment