Skip to content

Commit b88d12c

Browse files
author
iBinh
committed
add AutocompleteViewController
1 parent 1364937 commit b88d12c

File tree

14 files changed

+362
-35
lines changed

14 files changed

+362
-35
lines changed

.gitignore

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
# Created by https://www.gitignore.io/api/xcode,swift,cocoapods
3+
# Edit at https://www.gitignore.io/?templates=xcode,swift,cocoapods
4+
5+
### CocoaPods ###
6+
## CocoaPods GitIgnore Template
7+
8+
# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
9+
# - Also handy if you have a large number of dependant pods
10+
# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
11+
Pods/
12+
13+
### Swift ###
14+
# Xcode
15+
#
16+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
17+
18+
## Build generated
19+
build/
20+
DerivedData/
21+
22+
## Various settings
23+
*.pbxuser
24+
!default.pbxuser
25+
*.mode1v3
26+
!default.mode1v3
27+
*.mode2v3
28+
!default.mode2v3
29+
*.perspectivev3
30+
!default.perspectivev3
31+
*xcuserdata/
32+
33+
## Other
34+
*.moved-aside
35+
*.xccheckout
36+
*.xcscmblueprint
37+
38+
## Obj-C/Swift specific
39+
*.hmap
40+
*.ipa
41+
*.dSYM.zip
42+
*.dSYM
43+
44+
## Playgrounds
45+
timeline.xctimeline
46+
playground.xcworkspace
47+
48+
# Swift Package Manager
49+
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
50+
# Packages/
51+
# Package.pins
52+
# Package.resolved
53+
.build/
54+
# Add this line if you want to avoid checking in Xcode SPM integration.
55+
# .swiftpm/xcode
56+
57+
# CocoaPods
58+
# We recommend against adding the Pods directory to your .gitignore. However
59+
# you should judge for yourself, the pros and cons are mentioned at:
60+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
61+
# Pods/
62+
# Add this line if you want to avoid checking in source code from the Xcode workspace
63+
# *.xcworkspace
64+
65+
# Carthage
66+
# Add this line if you want to avoid checking in source code from Carthage dependencies.
67+
# Carthage/Checkouts
68+
69+
Carthage/Build
70+
71+
# Accio dependency management
72+
Dependencies/
73+
.accio/
74+
75+
# fastlane
76+
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
77+
# screenshots whenever they are needed.
78+
# For more information about the recommended setup visit:
79+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
80+
81+
fastlane/report.xml
82+
fastlane/Preview.html
83+
fastlane/screenshots/**/*.png
84+
fastlane/test_output
85+
86+
# Code Injection
87+
# After new code Injection tools there's a generated folder /iOSInjectionProject
88+
# https://github.com/johnno1962/injectionforxcode
89+
90+
iOSInjectionProject/
91+
92+
### Xcode ###
93+
# Xcode
94+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
95+
96+
## User settings
97+
98+
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
99+
100+
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
101+
102+
## Xcode Patch
103+
*.xcodeproj/*
104+
!*.xcodeproj/project.pbxproj
105+
!*.xcodeproj/xcshareddata/
106+
!*.xcworkspace/contents.xcworkspacedata
107+
/*.gcno
108+
109+
### Xcode Patch ###
110+
**/xcshareddata/WorkspaceSettings.xcsettings
111+
112+
# End of https://www.gitignore.io/api/xcode,swift,cocoapods

GoongGeocoder.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
FE51C654237D01950080E1F2 /* GoongGeocoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE51C653237D01950080E1F2 /* GoongGeocoder.swift */; };
1111
FE51C656237D02130080E1F2 /* GoongPlacemark.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE51C655237D02130080E1F2 /* GoongPlacemark.swift */; };
1212
FE51C67B237D3CD90080E1F2 /* CoreLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE51C67A237D3CD80080E1F2 /* CoreLocation.swift */; };
13+
FEC3B25823C2EAEE00B120F9 /* GoongAutocompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEC3B25723C2EAEE00B120F9 /* GoongAutocompleteViewController.swift */; };
14+
FEC3B27C23C31CF800B120F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FEC3B27B23C31CF800B120F9 /* Assets.xcassets */; };
1315
FEE591DB237C0E2300319874 /* GoongGeocoder.h in Headers */ = {isa = PBXBuildFile; fileRef = FEE591D9237C0E2300319874 /* GoongGeocoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
1416
FEE591E2237C114D00319874 /* GoongGeocodeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE591E1237C114D00319874 /* GoongGeocodeOptions.swift */; };
1517
/* End PBXBuildFile section */
@@ -18,6 +20,8 @@
1820
FE51C653237D01950080E1F2 /* GoongGeocoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoongGeocoder.swift; sourceTree = "<group>"; };
1921
FE51C655237D02130080E1F2 /* GoongPlacemark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoongPlacemark.swift; sourceTree = "<group>"; };
2022
FE51C67A237D3CD80080E1F2 /* CoreLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreLocation.swift; sourceTree = "<group>"; };
23+
FEC3B25723C2EAEE00B120F9 /* GoongAutocompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoongAutocompleteViewController.swift; sourceTree = "<group>"; };
24+
FEC3B27B23C31CF800B120F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2125
FEE591D6237C0E2300319874 /* GoongGeocoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GoongGeocoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2226
FEE591D9237C0E2300319874 /* GoongGeocoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoongGeocoder.h; sourceTree = "<group>"; };
2327
FEE591DA237C0E2300319874 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -59,7 +63,9 @@
5963
FE51C653237D01950080E1F2 /* GoongGeocoder.swift */,
6064
FE51C655237D02130080E1F2 /* GoongPlacemark.swift */,
6165
FE51C67A237D3CD80080E1F2 /* CoreLocation.swift */,
66+
FEC3B25723C2EAEE00B120F9 /* GoongAutocompleteViewController.swift */,
6267
FEE591DA237C0E2300319874 /* Info.plist */,
68+
FEC3B27B23C31CF800B120F9 /* Assets.xcassets */,
6369
);
6470
path = GoongGeocoder;
6571
sourceTree = "<group>";
@@ -134,6 +140,7 @@
134140
isa = PBXResourcesBuildPhase;
135141
buildActionMask = 2147483647;
136142
files = (
143+
FEC3B27C23C31CF800B120F9 /* Assets.xcassets in Resources */,
137144
);
138145
runOnlyForDeploymentPostprocessing = 0;
139146
};
@@ -147,6 +154,7 @@
147154
FE51C654237D01950080E1F2 /* GoongGeocoder.swift in Sources */,
148155
FE51C656237D02130080E1F2 /* GoongPlacemark.swift in Sources */,
149156
FEE591E2237C114D00319874 /* GoongGeocodeOptions.swift in Sources */,
157+
FEC3B25823C2EAEE00B120F9 /* GoongAutocompleteViewController.swift in Sources */,
150158
FE51C67B237D3CD90080E1F2 /* CoreLocation.swift in Sources */,
151159
);
152160
runOnlyForDeploymentPostprocessing = 0;

GoongGeocoder.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

GoongGeocoder.xcodeproj/xcuserdata/ibinh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,4 @@
33
uuid = "05FF8D67-3F86-4565-8800-C02930E65E7A"
44
type = "1"
55
version = "2.0">
6-
<Breakpoints>
7-
<BreakpointProxy
8-
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
9-
<BreakpointContent
10-
uuid = "D1B52772-CC6E-48F5-A425-935CB1241943"
11-
shouldBeEnabled = "Yes"
12-
ignoreCount = "0"
13-
continueAfterRunningActions = "No"
14-
scope = "1"
15-
stopOnStyle = "0">
16-
</BreakpointContent>
17-
</BreakpointProxy>
18-
<BreakpointProxy
19-
BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint">
20-
<BreakpointContent
21-
uuid = "2AAFE537-4AB7-44A8-ABA3-A9A91BB66498"
22-
shouldBeEnabled = "Yes"
23-
ignoreCount = "0"
24-
continueAfterRunningActions = "No">
25-
</BreakpointContent>
26-
</BreakpointProxy>
27-
</Breakpoints>
286
</Bucket>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"info" : {
3+
"version" : 1,
4+
"author" : "xcode"
5+
}
6+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"images" : [
3+
{
4+
"idiom" : "universal",
5+
"filename" : "iconLocationPin_gray.png",
6+
"scale" : "1x"
7+
},
8+
{
9+
"idiom" : "universal",
10+
"filename" : "iconLocationPin_gray@2x.png",
11+
"scale" : "2x"
12+
},
13+
{
14+
"idiom" : "universal",
15+
"filename" : "iconLocationPin_gray@3x.png",
16+
"scale" : "3x"
17+
}
18+
],
19+
"info" : {
20+
"version" : 1,
21+
"author" : "xcode"
22+
}
23+
}
Loading
Loading
Loading
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import UIKit
2+
3+
@objc public protocol GoongAutocompleteDelegate {
4+
@objc func didSelectPlacemark(_ placemark: Placemark?)
5+
}
6+
@objc open class GoongAutocompleteViewController: UIViewController {
7+
var tableView: UITableView!
8+
var searchActive : Bool = false
9+
var searchBar:UISearchBar?
10+
var searchedPlaces = [Prediction]()
11+
let decoder = JSONDecoder()
12+
let geocoder = Geocoder.shared
13+
@objc public weak var delegate: GoongAutocompleteDelegate?
14+
override open func viewDidLoad() {
15+
super.viewDidLoad()
16+
17+
if self.searchBar == nil {
18+
self.searchBar = UISearchBar()
19+
self.searchBar!.searchBarStyle = .prominent
20+
self.searchBar!.tintColor = .black
21+
self.searchBar!.barTintColor = .white
22+
self.searchBar!.delegate = self
23+
self.searchBar!.placeholder = "Search for place";
24+
}
25+
self.navigationItem.titleView = searchBar
26+
setupTableview()
27+
}
28+
func setupTableview() {
29+
self.tableView = UITableView()
30+
self.tableView.keyboardDismissMode = .onDrag
31+
self.tableView.allowsMultipleSelection = false
32+
self.tableView.delegate = self
33+
self.tableView.dataSource = self
34+
self.view.addSubview(tableView)
35+
self.tableView.frame = self.view.bounds
36+
self.tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
37+
}
38+
39+
}
40+
extension GoongAutocompleteViewController: UISearchBarDelegate {
41+
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
42+
self.cancelSearching()
43+
searchActive = false;
44+
}
45+
46+
public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
47+
self.view.endEditing(true)
48+
searchBar.searchTextField.resignFirstResponder()
49+
}
50+
51+
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
52+
self.searchBar!.setShowsCancelButton(true, animated: true)
53+
}
54+
55+
public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
56+
self.searchBar!.setShowsCancelButton(false, animated: false)
57+
}
58+
59+
func cancelSearching(){
60+
searchActive = false;
61+
self.searchBar!.resignFirstResponder()
62+
self.searchBar!.text = ""
63+
}
64+
65+
public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
66+
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.search), object: nil)
67+
self.perform(#selector(self.search), with: nil, afterDelay: 0.5)
68+
if(searchBar.text!.isEmpty){
69+
searchActive = false;
70+
} else {
71+
searchActive = true;
72+
}
73+
}
74+
75+
@objc func search() {
76+
if(searchBar?.text!.isEmpty)!{ } else {
77+
self.searchPlaces(query: (searchBar?.text)!)
78+
}
79+
}
80+
@objc func searchPlaces(query: String) {
81+
82+
let options = ForwardGeocodeOptions(query: query)
83+
geocoder.geocode(options) { (result, error) in
84+
if let err = error {
85+
print(err.localizedDescription)
86+
}
87+
guard let result = result, let predictions = result.predictions, predictions.count > 0 else {
88+
return
89+
}
90+
self.searchedPlaces = predictions
91+
self.tableView.reloadData()
92+
}
93+
}
94+
}
95+
extension GoongAutocompleteViewController: UITableViewDelegate, UITableViewDataSource {
96+
public func numberOfSections(in tableView: UITableView) -> Int {
97+
return searchedPlaces.count
98+
}
99+
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
100+
let HeaderCellIdentifier = "Header"
101+
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: HeaderCellIdentifier)
102+
let place = searchedPlaces[section]
103+
104+
cell.textLabel?.text = place.structuredFormatting?.mainText
105+
cell.detailTextLabel?.text = place.structuredFormatting?.secondaryText
106+
107+
cell.textLabel?.font = UIFont.systemFont(ofSize: 16)
108+
cell.textLabel?.textColor = .darkGray
109+
cell.detailTextLabel?.textColor = .gray
110+
cell.backgroundColor = .white
111+
let separator = UIView()
112+
separator.frame = CGRect(x: 20, y: cell.frame.size.height - 0.5, width: tableView.frame.size.width - 20, height: 0.5)
113+
separator.backgroundColor = .groupTableViewBackground
114+
cell.addSubview(separator)
115+
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleSectionTap(gesture:)))
116+
117+
tap.numberOfTapsRequired = 1
118+
tap.numberOfTouchesRequired = 1
119+
cell.tag = section
120+
cell.addGestureRecognizer(tap)
121+
return cell
122+
}
123+
124+
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
125+
let place = searchedPlaces[section]
126+
if place.hasChildren! {
127+
return place.children!.count
128+
}
129+
return 0
130+
}
131+
132+
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
133+
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
134+
let child = searchedPlaces[indexPath.section]
135+
let place = child.children![indexPath.row]
136+
cell.textLabel?.text = place.content
137+
cell.detailTextLabel?.text = place.address
138+
cell.imageView?.image = UIImage(named: "iconLocationPin_gray", in: Bundle(for:self.classForCoder), compatibleWith: nil)
139+
return cell
140+
}
141+
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
142+
return 50
143+
}
144+
public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
145+
return UIView()
146+
}
147+
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
148+
return 0.01
149+
}
150+
151+
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
152+
let place = searchedPlaces[indexPath.section].children![indexPath.row]
153+
self.fetchPlaceID(place.pid!)
154+
}
155+
156+
func fetchPlaceID(_ placeID: String) {
157+
geocoder.fetchPlace(from: placeID) { (result, err) in
158+
if let err = err {
159+
print(err.localizedDescription)
160+
}
161+
guard let result = result else {
162+
return
163+
}
164+
self.delegate?.didSelectPlacemark(result.placemark)
165+
}
166+
}
167+
@objc func handleSectionTap(gesture: UITapGestureRecognizer) {
168+
let place = searchedPlaces[gesture.view!.tag]
169+
self.fetchPlaceID(place.placeID!)
170+
}
171+
172+
173+
}

0 commit comments

Comments
 (0)