Skip to content

Commit 945fdde

Browse files
authored
Add files via upload
1 parent fe34bb8 commit 945fdde

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+7731
-0
lines changed
Lines changed: 398 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,398 @@
1+
//
2+
// VPAutoComplete.swift
3+
// VPAutoComplete
4+
//
5+
// Created by Vivek on 25/01/18.
6+
// Copyright © 2018 Vivek. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class VPAutoComplete: UIView {
12+
13+
// Data source for show DropDown.
14+
public var dataSource : [String] = [String]()
15+
// Textfield for DropDown to show.
16+
public var onTextField : UITextField!
17+
// Completion Block For Selection in DropDown.
18+
public var completionHandler: CompletionHandler?
19+
// TableView For DropDown.
20+
var tableView : UITableView?
21+
public var dropDownHeight : CGFloat?
22+
// Parents View for Show DropDown.
23+
public var onView : UIView?
24+
// Filter data when writing on textfield.
25+
var filterDataSource : [String] = [String]()
26+
public var indexPath : IndexPath?
27+
// MultiLine for DropDown List (For Now dosent added properly and tested)
28+
private var isMultiLine = false
29+
// Cell Height for DropDown
30+
public var cellHeight : CGFloat!
31+
// Make Searched Text Bold Or Not.
32+
public var isSearchBig = true
33+
34+
var is_filter = false
35+
var isOnTop = false
36+
37+
// Arrow Indicator For DropDown.
38+
fileprivate lazy var arrowIndication: UIImageView = {
39+
UIGraphicsBeginImageContextWithOptions(CGSize(width: 20, height: 10), false, 0)
40+
let path = UIBezierPath()
41+
path.move(to: CGPoint(x: 0, y: 10))
42+
path.addLine(to: CGPoint(x: 20, y: 10))
43+
path.addLine(to: CGPoint(x: 10, y: 0))
44+
path.addLine(to: CGPoint(x: 0, y: 10))
45+
UIColor.black.setFill()
46+
path.fill()
47+
let img = UIGraphicsGetImageFromCurrentImageContext()
48+
UIGraphicsEndImageContext()
49+
let tintImg = img?.withRenderingMode(.alwaysTemplate)
50+
let imgv = UIImageView(image: tintImg)
51+
imgv.frame = CGRect(x: 0, y: -10, width: 15, height: 10)
52+
return imgv
53+
}()
54+
55+
// Completion BLock.
56+
typealias CompletionHandler = (_ text: String , _ index : Int) -> Void
57+
58+
// Remove observer
59+
deinit{
60+
self.deregisterFromKeyboardNotifications()
61+
}
62+
63+
// Override Init
64+
override init(frame: CGRect) {
65+
super.init(frame: frame)
66+
// SetUp View
67+
self.setUp()
68+
}
69+
70+
public convenience init() {
71+
self.init(frame: .zero)
72+
}
73+
74+
required init(coder aDecoder: NSCoder) {
75+
fatalError("init(coder:) has not been implemented")
76+
}
77+
78+
public convenience init(onTextField: UITextField , dataSource : [String], onView: UIView, completionHandler: @escaping CompletionHandler){
79+
self.init()
80+
self.dataSource = dataSource
81+
self.onTextField = onTextField
82+
self.onView = onView
83+
self.tableView?.frame = CGRect(x: 0, y: 0, width: onTextField.frame.width, height: 150)
84+
self.frame = CGRect(x: onTextField.frame.minX, y: onTextField.frame.maxY, width: onTextField.frame.width, height: 150)
85+
86+
self.addSubview(tableView!)
87+
onView.addSubview(self)
88+
self.tableView?.reloadData()
89+
90+
self.onTextField.addTarget(self, action: #selector(didBeganText(textField:)), for: .editingDidBegin)
91+
self.onTextField.addTarget(self, action: #selector(didChangeText(textField:)), for: .editingChanged)
92+
self.onTextField.addTarget(self, action: #selector(didEndText(textField:)), for: .editingDidEnd)
93+
94+
self.isShowView(is_show: false)
95+
self.completionHandler = completionHandler
96+
}
97+
98+
// MARK: - Show DropDown.(Add DropDown)
99+
/********** For Show DropDown for View And get selection in
100+
completion block.***********/
101+
public func show(completionHandler: @escaping CompletionHandler){
102+
103+
self.tableView?.frame = CGRect(x: 0, y: 0, width: onTextField.frame.width, height: 150)
104+
self.frame = CGRect(x: onTextField.frame.minX, y: onTextField.frame.maxY, width: onTextField.frame.width, height: 150)
105+
106+
onTextField.addTarget(self, action: #selector(didBeganText(textField:)), for: .editingDidBegin)
107+
onTextField.addTarget(self, action: #selector(didChangeText(textField:)), for: .editingChanged)
108+
onTextField.addTarget(self, action: #selector(didEndText(textField:)), for: .editingDidEnd)
109+
110+
self.addSubview(tableView!)
111+
self.onView?.addSubview(self)
112+
113+
self.alpha = 0
114+
self.isHidden = true
115+
116+
self.tableView?.alpha = 0
117+
self.tableView?.isHidden = true
118+
119+
self.completionHandler = completionHandler
120+
}
121+
122+
/********** For Show DropDown for TableView And get selection in
123+
completion block.***********/
124+
public func show(onTableView : UITableView, atIndexPath: IndexPath, completionHandler: @escaping CompletionHandler){
125+
126+
self.tableView?.frame = CGRect(x: 0, y: 0, width: onTextField.frame.width, height: cellHeight * 3)
127+
128+
let cellRectInTable: CGRect = onTableView.rectForRow(at: atIndexPath)
129+
let cellInSuperview: CGRect = onTableView.convert(cellRectInTable, to: onTableView)
130+
self.frame = CGRect(x: onTextField.frame.minX, y: cellInSuperview.minY + onTextField.frame.maxY, width: onTextField.frame.width, height: cellHeight * 3)
131+
132+
self.onView = onTableView
133+
134+
onTextField.addTarget(self, action: #selector(didBeganText(textField:)), for: .editingDidBegin)
135+
onTextField.addTarget(self, action: #selector(didChangeText(textField:)), for: .editingChanged)
136+
onTextField.addTarget(self, action: #selector(didEndText(textField:)), for: .editingDidEnd)
137+
138+
self.addSubview(tableView!)
139+
onTableView.addSubview(self)
140+
141+
self.alpha = 0
142+
self.isHidden = true
143+
144+
self.tableView?.alpha = 0
145+
self.tableView?.isHidden = true
146+
147+
self.completionHandler = completionHandler
148+
}
149+
150+
static func hide(){
151+
152+
}
153+
154+
// MARK: - SetUp View
155+
156+
func setUp(){
157+
self.tableView = UITableView()
158+
self.tableView?.register(UINib(nibName: "VPAutoCompleteViewCell", bundle: nil), forCellReuseIdentifier: "VPAutoCompleteViewCell")
159+
self.tableView?.delegate = self
160+
self.tableView?.dataSource = self
161+
self.tableView?.tableFooterView = UIView()
162+
163+
self.tableView?.layer.cornerRadius = 10
164+
self.tableView?.clipsToBounds = true
165+
166+
self.layer.cornerRadius = 10
167+
self.clipsToBounds = true
168+
169+
self.cellHeight = 50
170+
171+
self.addShadow(customView: self)
172+
self.registerForKeyboardNotifications()
173+
}
174+
175+
// Shadow for DropDown
176+
public func addShadow(customView: UIView){
177+
178+
customView.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
179+
customView.layer.shadowOffset = CGSize(width: 0, height: 1)
180+
customView.layer.shadowOpacity = 1.0
181+
customView.layer.shadowRadius = 2.0
182+
customView.layer.masksToBounds = false
183+
}
184+
185+
186+
187+
@objc func didChangeText(textField: UITextField) {
188+
if let textInField = onTextField.text {
189+
if textInField.count == 0{
190+
is_filter = false
191+
self.tableView?.reloadData()
192+
}else{
193+
is_filter = true
194+
let tempData = dataSource.filter { $0.localizedCaseInsensitiveContains(textInField) }
195+
filterDataSource = tempData
196+
self.isShowView(is_show: true)
197+
self.tableView?.reloadData()
198+
}
199+
}
200+
}
201+
202+
@objc func didBeganText(textField: UITextField) {
203+
self.isShowView(is_show: true);
204+
}
205+
206+
@objc func didEndText(textField: UITextField) {
207+
is_filter = false
208+
self.isShowView(is_show: false)
209+
self.tableView?.reloadData()
210+
}
211+
212+
func isShowView(is_show : Bool){
213+
214+
if !self.isHidden && is_show{
215+
return
216+
}
217+
218+
if is_show {
219+
self.alpha = 0
220+
self.isHidden = false
221+
222+
self.tableView?.alpha = 0
223+
self.tableView?.isHidden = false
224+
225+
UIView.animate(withDuration: 0.3) {
226+
self.alpha = 1
227+
self.tableView?.alpha = 1
228+
}
229+
230+
}else{
231+
UIView.animate(withDuration: 0.3, animations: {
232+
self.tableView?.alpha = 0
233+
self.alpha = 0
234+
}) { (finished) in
235+
self.tableView?.isHidden = finished
236+
self.isHidden = finished
237+
}
238+
}
239+
240+
}
241+
242+
func changeHeightForCount(count: Int){
243+
if cellHeight == nil {
244+
return
245+
}
246+
var newFrame = self.frame
247+
newFrame.size.height = cellHeight * CGFloat(count)
248+
if isOnTop {
249+
newFrame.origin.y = self.frame.maxY - newFrame.size.height
250+
}
251+
self.frame = newFrame
252+
self.tableView?.frame = CGRect(x: 0, y: 0, width: newFrame.width, height: newFrame.height)
253+
print("self frame :\(self.frame)")
254+
self.setNeedsLayout()
255+
}
256+
257+
func attributedText(withString string: String, boldString: String, font: UIFont) -> NSAttributedString {
258+
let attributedString = NSMutableAttributedString(string: string,
259+
attributes: [NSAttributedStringKey.font: font])
260+
let boldFontAttribute: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font.withSize(font.pointSize + 3)]
261+
let range = (string as NSString).range(of: boldString, options: .caseInsensitive)
262+
attributedString.addAttributes(boldFontAttribute, range: range)
263+
return attributedString
264+
}
265+
266+
267+
}
268+
269+
270+
// MARK: - TableView Delegate.
271+
272+
extension VPAutoComplete : UITableViewDelegate{
273+
274+
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
275+
276+
if !isMultiLine {
277+
return cellHeight
278+
}
279+
280+
if is_filter{
281+
let selectedStr = filterDataSource[indexPath.row]
282+
return selectedStr.height(constraintedWidth: self.onTextField.frame.width, font: self.onTextField.font!)
283+
}
284+
let selectedStr = dataSource[indexPath.row]
285+
return selectedStr.height(constraintedWidth: self.onTextField.frame.width, font: self.onTextField.font!)
286+
}
287+
288+
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
289+
if is_filter{
290+
let selectedStr = filterDataSource[indexPath.row]
291+
let selectedIndex = filterDataSource.index(of: selectedStr)
292+
self.isShowView(is_show: false)
293+
self.completionHandler!(selectedStr, selectedIndex!)
294+
return
295+
}
296+
let selectedStr = dataSource[indexPath.row]
297+
let selectedIndex = indexPath.row
298+
self.isShowView(is_show: false)
299+
self.completionHandler!(selectedStr, selectedIndex)
300+
}
301+
302+
303+
}
304+
305+
// MARK: - TableView DataSource.
306+
307+
extension VPAutoComplete : UITableViewDataSource{
308+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
309+
if is_filter{
310+
self.changeHeightForCount(count: self.filterDataSource.count < 4 ? self.filterDataSource.count : 3)
311+
return self.filterDataSource.count
312+
}
313+
self.changeHeightForCount(count: self.dataSource.count < 4 ? self.dataSource.count : 3)
314+
return self.dataSource.count
315+
}
316+
317+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
318+
let cell = tableView.dequeueReusableCell(withIdentifier: "VPAutoCompleteViewCell") as! VPAutoCompleteViewCell
319+
if is_filter {
320+
cell.lblTitle.text = filterDataSource[indexPath.row]
321+
}else{
322+
cell.lblTitle.text = dataSource[indexPath.row]
323+
}
324+
if isSearchBig {
325+
let formattedString = self.attributedText(withString: cell.lblTitle.text!, boldString: onTextField.text!, font: onTextField.font!)
326+
cell.lblTitle.attributedText = formattedString
327+
}
328+
return cell
329+
}
330+
}
331+
332+
extension VPAutoComplete {
333+
334+
func heightForLabel(text:String) -> CGFloat{
335+
let label:UILabel = UILabel(frame: CGRect(x:0, y:0, width: self.onTextField.frame.width, height: CGFloat.greatestFiniteMagnitude))
336+
label.numberOfLines = 0
337+
label.lineBreakMode = NSLineBreakMode.byWordWrapping
338+
label.font = self.onTextField.font
339+
label.text = text
340+
341+
label.sizeToFit()
342+
return label.frame.height + 20
343+
}
344+
345+
func addIndicator(color: UIColor, onRight: Bool, forView: UIView){
346+
347+
self.arrowIndication.frame = CGRect(x: 10, y: onRight ? forView.frame.width - 20 : 20, width: 10 , height: 10)
348+
self.arrowIndication.tintColor = color
349+
forView.addSubview(self.arrowIndication)
350+
}
351+
352+
func registerForKeyboardNotifications(){
353+
//Adding notifies on keyboard appearing
354+
NotificationCenter.default.addObserver(self, selector: #selector(keyboarDidShown(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
355+
}
356+
357+
func deregisterFromKeyboardNotifications(){
358+
//Removing notifies on keyboard appearing
359+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
360+
}
361+
362+
@objc func keyboarDidShown(notification: NSNotification){
363+
//Need to calculate keyboard exact size due to Apple suggestions
364+
var info = notification.userInfo!
365+
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
366+
367+
var aRect : CGRect = (self.onView?.frame)!
368+
aRect.size.height -= keyboardSize!.height
369+
if (self.onTextField) != nil {
370+
print("self frame : \(self.frame.origin)")
371+
if aRect.height < (self.frame.origin.y + self.frame .height) {
372+
if !isOnTop {
373+
self.frame = CGRect(x: onTextField.frame.minX, y: self.frame.origin.y - self.frame.height - self.onTextField.frame.height, width: onTextField.frame.width, height: self.frame.height)
374+
isOnTop = true
375+
self.setNeedsDisplay()
376+
}
377+
378+
}
379+
}
380+
}
381+
382+
}
383+
384+
385+
// MARK: - Height for text.
386+
extension String {
387+
func height(constraintedWidth width: CGFloat, font: UIFont) -> CGFloat {
388+
let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude))
389+
label.numberOfLines = 0
390+
label.lineBreakMode = NSLineBreakMode.byWordWrapping
391+
label.text = self
392+
label.font = font
393+
label.sizeToFit()
394+
395+
return label.frame.height + 30
396+
}
397+
}
398+

0 commit comments

Comments
 (0)