├── .DS_Store
├── .gitignore
├── PFollow.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── PFollow.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── PFollow
├── AppDelegate.swift
├── Assets.xcassets
│ ├── .DS_Store
│ ├── Annotation_details
│ │ ├── Contents.json
│ │ ├── annotation_details_addPhoto.imageset
│ │ │ ├── Contents.json
│ │ │ └── annotation_details_addPhoto.png
│ │ ├── annotation_details_addTime.imageset
│ │ │ ├── Contents.json
│ │ │ ├── annotation_details_addTime@2x.png
│ │ │ └── annotation_details_addTime@3x.png
│ │ ├── annotation_details_altitude.imageset
│ │ │ ├── Contents.json
│ │ │ ├── annotation_details_altitude@2x.png
│ │ │ └── annotation_details_altitude@3x.png
│ │ ├── annotation_details_env.imageset
│ │ │ ├── Contents.json
│ │ │ ├── annotation_details_env@2x.png
│ │ │ └── annotation_details_env@3x.png
│ │ └── annotation_details_save.imageset
│ │ │ ├── Contents.json
│ │ │ ├── annotation_details_save@2x.png
│ │ │ └── annotation_details_save@3x.png
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-Small.png
│ │ ├── Icon-Small@2x.png
│ │ ├── Icon-Small@3x.png
│ │ ├── Icon-Spotlight-40@2x.png
│ │ ├── Icon-Spotlight-40@3x.png
│ │ ├── Icon.png
│ │ ├── Icon@2x.png
│ │ └── PLook_logo.png
│ ├── BaseViewController
│ │ ├── Contents.json
│ │ ├── nav_back.imageset
│ │ │ ├── Contents.json
│ │ │ ├── nav_back@2x.png
│ │ │ └── nav_back@3x.png
│ │ └── nav_close.imageset
│ │ │ ├── Contents.json
│ │ │ ├── nav_close@2x.png
│ │ │ └── nav_close@3x.png
│ ├── Contents.json
│ ├── Home_bottom
│ │ ├── Contents.json
│ │ ├── home_bottom_compass.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_bottom_compass@2x.png
│ │ │ └── home_bottom_compass@3x.png
│ │ ├── home_cloud.imageset
│ │ │ ├── Contents.json
│ │ │ └── home_cloud.png
│ │ ├── home_friend.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_friend@2x.png
│ │ │ └── home_friend@3x.png
│ │ ├── home_places.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_places@2x.png
│ │ │ └── home_places@3x.png
│ │ ├── home_tap.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_tap@2x.png
│ │ │ └── home_tap@3x.png
│ │ ├── home_tap_.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_tap@2x.png
│ │ │ └── home_tap@3x.png
│ │ └── home_tap_ok.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_tap_ok@2x.png
│ │ │ └── home_tap_ok@3x.png
│ ├── Map
│ │ ├── .DS_Store
│ │ ├── Contents.json
│ │ ├── callout_delete.imageset
│ │ │ ├── Contents.json
│ │ │ ├── callout_delete@2x.png
│ │ │ └── callout_delete@3x.png
│ │ ├── callout_share.imageset
│ │ │ ├── Contents.json
│ │ │ ├── callout_share@2x.png
│ │ │ └── callout_share@3x.png
│ │ ├── home_map_makers_02.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_map_makers_02@2x.png
│ │ │ └── home_map_makers_02@3x.png
│ │ ├── home_map_makers_02_b.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_map_makers_02_b@2x.png
│ │ │ └── home_map_makers_02_b@3x.png
│ │ ├── home_map_makers_03.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_map_makers_03@2x.png
│ │ │ └── home_map_makers_03@3x.png
│ │ ├── home_map_makers_03_b.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_map_makers_03_b@2x.png
│ │ │ └── home_map_makers_03_b@3x.png
│ │ ├── home_map_userlocation.imageset
│ │ │ ├── Contents.json
│ │ │ ├── home_map_userlocation@2x.png
│ │ │ └── home_map_userlocation@3x.png
│ │ └── userPosition.imageset
│ │ │ ├── Contents.json
│ │ │ ├── userPosition.png
│ │ │ └── userPosition@2x.png
│ ├── Places
│ │ ├── Contents.json
│ │ ├── places_bgView.imageset
│ │ │ ├── Contents.json
│ │ │ └── bgView.png
│ │ └── places_null.imageset
│ │ │ ├── Contents.json
│ │ │ └── places_null.png
│ └── Weather
│ │ ├── Contents.json
│ │ ├── 中雨.imageset
│ │ ├── Contents.json
│ │ └── 中雨.png
│ │ ├── 中雨转大雨.imageset
│ │ ├── Contents.json
│ │ └── 中雨转大雨.png
│ │ ├── 中雪.imageset
│ │ ├── Contents.json
│ │ └── 中雪.png
│ │ ├── 中雪转大雪.imageset
│ │ ├── Contents.json
│ │ └── 中雪转大雪.png
│ │ ├── 冻雨.imageset
│ │ ├── Contents.json
│ │ └── 冻雨.png
│ │ ├── 多云.imageset
│ │ ├── Contents.json
│ │ └── 多云.png
│ │ ├── 大暴雨.imageset
│ │ ├── Contents.json
│ │ └── 大暴雨.png
│ │ ├── 大雨.imageset
│ │ ├── Contents.json
│ │ └── 大雨.png
│ │ ├── 大雨转暴雨.imageset
│ │ ├── Contents.json
│ │ └── 大雨转暴雨.png
│ │ ├── 大雪.imageset
│ │ ├── Contents.json
│ │ └── 大雪.png
│ │ ├── 大雪转暴雪.imageset
│ │ ├── Contents.json
│ │ └── 大雪转暴雪.png
│ │ ├── 小雨.imageset
│ │ ├── Contents.json
│ │ └── 小雨.png
│ │ ├── 小雨转中雨.imageset
│ │ ├── Contents.json
│ │ └── 小雨转中雨.png
│ │ ├── 小雪.imageset
│ │ ├── Contents.json
│ │ └── 小雪.png
│ │ ├── 小雪转中雪.imageset
│ │ ├── Contents.json
│ │ └── 小雪转中雪.png
│ │ ├── 扬沙.imageset
│ │ ├── Contents.json
│ │ └── 扬沙.png
│ │ ├── 晴.imageset
│ │ ├── Contents.json
│ │ └── 晴.png
│ │ ├── 暴雨.imageset
│ │ ├── Contents.json
│ │ └── 暴雨.png
│ │ ├── 暴雨转大暴雨.imageset
│ │ ├── Contents.json
│ │ └── 暴雨转大暴雨.png
│ │ ├── 沙尘暴.imageset
│ │ ├── Contents.json
│ │ └── 沙尘暴.png
│ │ ├── 浮尘.imageset
│ │ ├── Contents.json
│ │ └── 浮尘.png
│ │ ├── 特大暴雨.imageset
│ │ ├── Contents.json
│ │ └── 特大暴雨.png
│ │ ├── 特大沙尘暴.imageset
│ │ ├── Contents.json
│ │ └── 特大沙尘暴.png
│ │ ├── 阴.imageset
│ │ ├── Contents.json
│ │ └── 阴.png
│ │ ├── 阵雨.imageset
│ │ ├── Contents.json
│ │ └── 阵雨.png
│ │ ├── 阵雪.imageset
│ │ ├── Contents.json
│ │ └── 阵雪.png
│ │ ├── 雨夹雪.imageset
│ │ ├── Contents.json
│ │ └── 雨夹雪.png
│ │ ├── 雷阵雨.imageset
│ │ ├── Contents.json
│ │ └── 雷阵雨.png
│ │ ├── 雷雨冰雹.imageset
│ │ ├── Contents.json
│ │ └── 雷雨冰雹.png
│ │ ├── 雾.imageset
│ │ ├── Contents.json
│ │ └── 雾.png
│ │ └── 雾霾.imageset
│ │ ├── Contents.json
│ │ └── 雾霾.png
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Common
│ ├── PJBaseViewController.swift
│ ├── PJCoreDataHelper.swift
│ ├── PJDefine.swift
│ ├── PJTapic.swift
│ └── PJTools-UIView+Position.swift
├── Info.plist
├── PFollow-Bridging-Header.h
├── PFollow.entitlements
├── PFollow.xcdatamodeld
│ ├── .xccurrentversion
│ └── PFollow.xcdatamodel
│ │ └── contents
├── Page
│ ├── Home
│ │ ├── controller
│ │ │ └── PJHomeViewController.swift
│ │ ├── model
│ │ │ └── AnnotationModel.swift
│ │ └── view
│ │ │ ├── MapView
│ │ │ ├── PJHomeMapAnnotetionView.swift
│ │ │ ├── PJHomeMapCalloutView.swift
│ │ │ └── PJHomeMapView.swift
│ │ │ └── bottomView
│ │ │ └── PJHomeBottomView.swift
│ ├── InfoFlow
│ │ └── controller
│ │ │ ├── Details
│ │ │ ├── Controller
│ │ │ │ └── PJAnnotationDetailsViewController.swift
│ │ │ └── View
│ │ │ │ ├── PJDatePickerView.swift
│ │ │ │ └── PJDatePickerView.xib
│ │ │ └── Flow
│ │ │ └── PJInfoFlowViewController.swift
│ └── Places
│ │ ├── Controller
│ │ └── PJPlacesViewController.swift
│ │ └── View
│ │ └── Scene
│ │ └── PJPlacesAnnotationScene.swift
└── mapView.data
├── PFollowTests
├── Info.plist
└── PFollowTests.swift
├── PFollowUITests
├── Info.plist
└── PFollowUITests.swift
├── Podfile.lock
├── README.md
├── banner.png
└── podfile
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | Pods
50 | !Podfile
51 | !Podfile.lock
52 | #
53 | # Add this line if you want to avoid checking in source code from the Xcode workspace
54 | # *.xcworkspace
55 |
56 | # Carthage
57 | #
58 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
59 | # Carthage/Checkouts
60 |
61 | Carthage/Build
62 |
63 | # fastlane
64 | #
65 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
66 | # screenshots whenever they are needed.
67 | # For more information about the recommended setup visit:
68 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
69 |
70 | fastlane/report.xml
71 | fastlane/Preview.html
72 | fastlane/screenshots/**/*.png
73 | fastlane/test_output
74 |
75 | # Code Injection
76 | #
77 | # After new code Injection tools there's a generated folder /iOSInjectionProject
78 | # https://github.com/johnno1962/injectionforxcode
79 |
80 | iOSInjectionProject/
81 |
82 |
--------------------------------------------------------------------------------
/PFollow.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PFollow.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PFollow.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/PFollow.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PFollow/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | import IQKeyboardManagerSwift
13 |
14 | @UIApplicationMain
15 | class AppDelegate: UIResponder, UIApplicationDelegate {
16 |
17 | var window: UIWindow?
18 |
19 |
20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
21 |
22 | IQKeyboardManager.shared.enable = true
23 |
24 | window = UIWindow.init(frame: UIScreen.main.bounds)
25 | let navigationControllrt = UINavigationController.init(rootViewController: PJHomeViewController())
26 | window?.rootViewController = navigationControllrt
27 | window?.makeKeyAndVisible()
28 |
29 | AMapServices.shared().apiKey = "9481ea9de167f7b11a192b11b620dd84"
30 |
31 | return true
32 | }
33 |
34 | func applicationWillResignActive(_ application: UIApplication) {
35 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
36 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
37 | }
38 |
39 | func applicationDidEnterBackground(_ application: UIApplication) {
40 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
41 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
42 | }
43 |
44 | func applicationWillEnterForeground(_ application: UIApplication) {
45 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
46 | }
47 |
48 | func applicationDidBecomeActive(_ application: UIApplication) {
49 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
50 | }
51 |
52 | func applicationWillTerminate(_ application: UIApplication) {
53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
54 | // Saves changes in the application's managed object context before the application terminates.
55 | self.saveContext()
56 | }
57 |
58 | // MARK: - Core Data stack
59 |
60 | lazy var persistentContainer: NSPersistentContainer = {
61 | /*
62 | The persistent container for the application. This implementation
63 | creates and returns a container, having loaded the store for the
64 | application to it. This property is optional since there are legitimate
65 | error conditions that could cause the creation of the store to fail.
66 | */
67 | let container = NSPersistentContainer(name: "PFollow")
68 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in
69 | if let error = error as NSError? {
70 | // Replace this implementation with code to handle the error appropriately.
71 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
72 |
73 | /*
74 | Typical reasons for an error here include:
75 | * The parent directory does not exist, cannot be created, or disallows writing.
76 | * The persistent store is not accessible, due to permissions or data protection when the device is locked.
77 | * The device is out of space.
78 | * The store could not be migrated to the current model version.
79 | Check the error message to determine what the actual problem was.
80 | */
81 | fatalError("Unresolved error \(error), \(error.userInfo)")
82 | }
83 | })
84 | return container
85 | }()
86 |
87 | // MARK: - Core Data Saving support
88 |
89 | func saveContext () {
90 | let context = persistentContainer.viewContext
91 | if context.hasChanges {
92 | do {
93 | try context.save()
94 | } catch {
95 | // Replace this implementation with code to handle the error appropriately.
96 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
97 | let nserror = error as NSError
98 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
99 | }
100 | }
101 | }
102 |
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_addPhoto.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "annotation_details_addPhoto.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_addPhoto.imageset/annotation_details_addPhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_addPhoto.imageset/annotation_details_addPhoto.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_addTime.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "annotation_details_addTime@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "annotation_details_addTime@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_addTime.imageset/annotation_details_addTime@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_addTime.imageset/annotation_details_addTime@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_addTime.imageset/annotation_details_addTime@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_addTime.imageset/annotation_details_addTime@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_altitude.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "annotation_details_altitude@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "annotation_details_altitude@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_altitude.imageset/annotation_details_altitude@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_altitude.imageset/annotation_details_altitude@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_altitude.imageset/annotation_details_altitude@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_altitude.imageset/annotation_details_altitude@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_env.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "annotation_details_env@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "annotation_details_env@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_env.imageset/annotation_details_env@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_env.imageset/annotation_details_env@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_env.imageset/annotation_details_env@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_env.imageset/annotation_details_env@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_save.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "annotation_details_save@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "annotation_details_save@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_save.imageset/annotation_details_save@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_save.imageset/annotation_details_save@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Annotation_details/annotation_details_save.imageset/annotation_details_save@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Annotation_details/annotation_details_save.imageset/annotation_details_save@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "size" : "29x29",
15 | "idiom" : "iphone",
16 | "filename" : "Icon-Small.png",
17 | "scale" : "1x"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "iphone",
22 | "filename" : "Icon-Small@2x.png",
23 | "scale" : "2x"
24 | },
25 | {
26 | "size" : "29x29",
27 | "idiom" : "iphone",
28 | "filename" : "Icon-Small@3x.png",
29 | "scale" : "3x"
30 | },
31 | {
32 | "size" : "40x40",
33 | "idiom" : "iphone",
34 | "filename" : "Icon-Spotlight-40@2x.png",
35 | "scale" : "2x"
36 | },
37 | {
38 | "size" : "40x40",
39 | "idiom" : "iphone",
40 | "filename" : "Icon-Spotlight-40@3x.png",
41 | "scale" : "3x"
42 | },
43 | {
44 | "size" : "57x57",
45 | "idiom" : "iphone",
46 | "filename" : "Icon.png",
47 | "scale" : "1x"
48 | },
49 | {
50 | "size" : "57x57",
51 | "idiom" : "iphone",
52 | "filename" : "Icon@2x.png",
53 | "scale" : "2x"
54 | },
55 | {
56 | "size" : "60x60",
57 | "idiom" : "iphone",
58 | "filename" : "Icon-60@2x.png",
59 | "scale" : "2x"
60 | },
61 | {
62 | "size" : "60x60",
63 | "idiom" : "iphone",
64 | "filename" : "Icon-60@3x.png",
65 | "scale" : "3x"
66 | },
67 | {
68 | "idiom" : "ipad",
69 | "size" : "20x20",
70 | "scale" : "1x"
71 | },
72 | {
73 | "idiom" : "ipad",
74 | "size" : "20x20",
75 | "scale" : "2x"
76 | },
77 | {
78 | "idiom" : "ipad",
79 | "size" : "29x29",
80 | "scale" : "1x"
81 | },
82 | {
83 | "idiom" : "ipad",
84 | "size" : "29x29",
85 | "scale" : "2x"
86 | },
87 | {
88 | "idiom" : "ipad",
89 | "size" : "40x40",
90 | "scale" : "1x"
91 | },
92 | {
93 | "idiom" : "ipad",
94 | "size" : "40x40",
95 | "scale" : "2x"
96 | },
97 | {
98 | "idiom" : "ipad",
99 | "size" : "76x76",
100 | "scale" : "1x"
101 | },
102 | {
103 | "idiom" : "ipad",
104 | "size" : "76x76",
105 | "scale" : "2x"
106 | },
107 | {
108 | "idiom" : "ipad",
109 | "size" : "83.5x83.5",
110 | "scale" : "2x"
111 | },
112 | {
113 | "size" : "1024x1024",
114 | "idiom" : "ios-marketing",
115 | "filename" : "PLook_logo.png",
116 | "scale" : "1x"
117 | }
118 | ],
119 | "info" : {
120 | "version" : 1,
121 | "author" : "xcode"
122 | }
123 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/AppIcon.appiconset/PLook_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/AppIcon.appiconset/PLook_logo.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "nav_back@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "nav_back@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_back.imageset/nav_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/BaseViewController/nav_back.imageset/nav_back@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_back.imageset/nav_back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/BaseViewController/nav_back.imageset/nav_back@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "nav_close@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "nav_close@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_close.imageset/nav_close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/BaseViewController/nav_close.imageset/nav_close@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/BaseViewController/nav_close.imageset/nav_close@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/BaseViewController/nav_close.imageset/nav_close@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_bottom_compass.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_bottom_compass@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_bottom_compass@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_bottom_compass.imageset/home_bottom_compass@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_bottom_compass.imageset/home_bottom_compass@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_bottom_compass.imageset/home_bottom_compass@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_bottom_compass.imageset/home_bottom_compass@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_cloud.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "home_cloud.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_cloud.imageset/home_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_cloud.imageset/home_cloud.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_friend.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_friend@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_friend@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_friend.imageset/home_friend@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_friend.imageset/home_friend@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_friend.imageset/home_friend@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_friend.imageset/home_friend@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_places.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_places@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_places@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_places.imageset/home_places@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_places.imageset/home_places@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_places.imageset/home_places@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_places.imageset/home_places@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_tap@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_tap@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap.imageset/home_tap@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap.imageset/home_tap@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap.imageset/home_tap@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap.imageset/home_tap@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_tap@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_tap@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_.imageset/home_tap@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap_.imageset/home_tap@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_.imageset/home_tap@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap_.imageset/home_tap@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_ok.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_tap_ok@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_tap_ok@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_ok.imageset/home_tap_ok@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap_ok.imageset/home_tap_ok@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Home_bottom/home_tap_ok.imageset/home_tap_ok@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Home_bottom/home_tap_ok.imageset/home_tap_ok@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/.DS_Store
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_delete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "callout_delete@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "callout_delete@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_delete.imageset/callout_delete@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/callout_delete.imageset/callout_delete@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_delete.imageset/callout_delete@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/callout_delete.imageset/callout_delete@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_share.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "callout_share@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "callout_share@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_share.imageset/callout_share@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/callout_share.imageset/callout_share@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/callout_share.imageset/callout_share@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/callout_share.imageset/callout_share@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_map_makers_02@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_map_makers_02@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02.imageset/home_map_makers_02@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_02.imageset/home_map_makers_02@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02.imageset/home_map_makers_02@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_02.imageset/home_map_makers_02@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02_b.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_map_makers_02_b@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_map_makers_02_b@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02_b.imageset/home_map_makers_02_b@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_02_b.imageset/home_map_makers_02_b@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_02_b.imageset/home_map_makers_02_b@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_02_b.imageset/home_map_makers_02_b@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_map_makers_03@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_map_makers_03@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03.imageset/home_map_makers_03@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_03.imageset/home_map_makers_03@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03.imageset/home_map_makers_03@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_03.imageset/home_map_makers_03@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03_b.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_map_makers_03_b@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_map_makers_03_b@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03_b.imageset/home_map_makers_03_b@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_03_b.imageset/home_map_makers_03_b@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_makers_03_b.imageset/home_map_makers_03_b@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_makers_03_b.imageset/home_map_makers_03_b@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_userlocation.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "home_map_userlocation@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "home_map_userlocation@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_userlocation.imageset/home_map_userlocation@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_userlocation.imageset/home_map_userlocation@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/home_map_userlocation.imageset/home_map_userlocation@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/home_map_userlocation.imageset/home_map_userlocation@3x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/userPosition.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "userPosition.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "userPosition@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/userPosition.imageset/userPosition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/userPosition.imageset/userPosition.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Map/userPosition.imageset/userPosition@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Map/userPosition.imageset/userPosition@2x.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Places/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Places/places_bgView.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bgView.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Places/places_bgView.imageset/bgView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Places/places_bgView.imageset/bgView.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Places/places_null.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "places_null.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Places/places_null.imageset/places_null.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Places/places_null.imageset/places_null.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "中雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雨.imageset/中雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/中雨.imageset/中雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雨转大雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "中雨转大雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雨转大雨.imageset/中雨转大雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/中雨转大雨.imageset/中雨转大雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "中雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雪.imageset/中雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/中雪.imageset/中雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雪转大雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "中雪转大雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/中雪转大雪.imageset/中雪转大雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/中雪转大雪.imageset/中雪转大雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/冻雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "冻雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/冻雨.imageset/冻雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/冻雨.imageset/冻雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/多云.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "多云.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/多云.imageset/多云.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/多云.imageset/多云.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大暴雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "大暴雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大暴雨.imageset/大暴雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/大暴雨.imageset/大暴雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "大雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雨.imageset/大雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/大雨.imageset/大雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雨转暴雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "大雨转暴雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雨转暴雨.imageset/大雨转暴雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/大雨转暴雨.imageset/大雨转暴雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "大雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雪.imageset/大雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/大雪.imageset/大雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雪转暴雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "大雪转暴雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/大雪转暴雪.imageset/大雪转暴雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/大雪转暴雪.imageset/大雪转暴雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "小雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雨.imageset/小雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/小雨.imageset/小雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雨转中雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "小雨转中雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雨转中雨.imageset/小雨转中雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/小雨转中雨.imageset/小雨转中雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "小雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雪.imageset/小雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/小雪.imageset/小雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雪转中雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "小雪转中雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/小雪转中雪.imageset/小雪转中雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/小雪转中雪.imageset/小雪转中雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/扬沙.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "扬沙.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/扬沙.imageset/扬沙.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/扬沙.imageset/扬沙.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/晴.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "晴.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/晴.imageset/晴.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/晴.imageset/晴.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/暴雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "暴雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/暴雨.imageset/暴雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/暴雨.imageset/暴雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/暴雨转大暴雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "暴雨转大暴雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/暴雨转大暴雨.imageset/暴雨转大暴雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/暴雨转大暴雨.imageset/暴雨转大暴雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/沙尘暴.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "沙尘暴.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/沙尘暴.imageset/沙尘暴.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/沙尘暴.imageset/沙尘暴.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/浮尘.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "浮尘.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/浮尘.imageset/浮尘.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/浮尘.imageset/浮尘.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/特大暴雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "特大暴雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/特大暴雨.imageset/特大暴雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/特大暴雨.imageset/特大暴雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/特大沙尘暴.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "特大沙尘暴.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/特大沙尘暴.imageset/特大沙尘暴.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/特大沙尘暴.imageset/特大沙尘暴.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阴.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "阴.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阴.imageset/阴.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/阴.imageset/阴.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阵雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "阵雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阵雨.imageset/阵雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/阵雨.imageset/阵雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阵雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "阵雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/阵雪.imageset/阵雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/阵雪.imageset/阵雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雨夹雪.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "雨夹雪.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雨夹雪.imageset/雨夹雪.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/雨夹雪.imageset/雨夹雪.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雷阵雨.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "雷阵雨.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雷阵雨.imageset/雷阵雨.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/雷阵雨.imageset/雷阵雨.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雷雨冰雹.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "雷雨冰雹.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雷雨冰雹.imageset/雷雨冰雹.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/雷雨冰雹.imageset/雷雨冰雹.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雾.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "雾.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雾.imageset/雾.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/雾.imageset/雾.png
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雾霾.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "雾霾.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/PFollow/Assets.xcassets/Weather/雾霾.imageset/雾霾.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/Assets.xcassets/Weather/雾霾.imageset/雾霾.png
--------------------------------------------------------------------------------
/PFollow/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PFollow/Common/PJBaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJBaseViewController.swift
3 | // PFollow
4 | //
5 | // Created by PJHubs on 2018/8/27.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PJBaseViewController: UIViewController {
12 |
13 | var headerView: UIView?
14 | var navBarHeigt: CGFloat?
15 | var rightBarButton: UIButton?
16 | var leftBarButton: UIButton?
17 |
18 |
19 | // MARK: - life cycle
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
24 | navigationController?.navigationBar.shadowImage = UIImage()
25 | navigationController?.navigationBar.isTranslucent = true
26 | navigationController?.navigationBar.barStyle = .black
27 | // 自定义了 leftBarButtonItem ,需要
28 | navigationController?.interactivePopGestureRecognizer?.isEnabled = true
29 | navigationController?.interactivePopGestureRecognizer?.delegate = nil
30 |
31 | initView()
32 | }
33 |
34 |
35 | override func didReceiveMemoryWarning() {
36 | super.didReceiveMemoryWarning()
37 | }
38 |
39 |
40 | // MARK: life cycle
41 | private func initView() {
42 | navBarHeigt = navigationController!.navigationBar.height + PJStatusHeight
43 |
44 | headerView = UIView(frame: CGRect(x: 0, y: 0, width: view.width,
45 | height: navBarHeigt!))
46 | view.addSubview(headerView!)
47 | }
48 |
49 |
50 | func leftBarButtonItemAction(action: Selector) {
51 | let leftButton = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
52 | leftButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0)
53 | leftButton.setImage(UIImage(named: "nav_back"), for: .normal)
54 | leftButton.addTarget(self, action: action, for: .touchUpInside)
55 | let leftBarButtonItem = UIBarButtonItem(customView: leftButton)
56 | navigationItem.leftBarButtonItem = leftBarButtonItem
57 | }
58 |
59 |
60 | func rightBarButtonItem(imageName: String, action: Selector) {
61 | let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
62 | rightButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -15)
63 | rightButton.setImage(UIImage(named: imageName), for: .normal)
64 | rightButton.addTarget(self, action: action, for: .touchUpInside)
65 | let rightBarButtonItem = UIBarButtonItem(customView: rightButton)
66 | rightBarButton = rightButton
67 | navigationItem.rightBarButtonItem = rightBarButtonItem
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/PFollow/Common/PJCoreDataHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJCoreDataHelper.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/18.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | class PJCoreDataHelper: NSObject {
13 |
14 | // 单例
15 | static let shared = PJCoreDataHelper()
16 |
17 | private let delegate = UIApplication.shared.delegate as! AppDelegate
18 | private let context: NSManagedObjectContext?
19 |
20 |
21 | // MAEK: life Cycle
22 | override init() {
23 | context = delegate.persistentContainer.viewContext
24 | }
25 |
26 |
27 | func addAnnotation(model: AnnotationModel) -> Bool {
28 | let annotationEntity = NSEntityDescription.insertNewObject(forEntityName: "Annotation", into: context!) as! Annotation
29 | annotationEntity.created_time = model.createdTimeString
30 | annotationEntity.weather = model.weatherString
31 | annotationEntity.environment = model.environmentString
32 | annotationEntity.latitude = model.latitude
33 | annotationEntity.longitude = model.longitude
34 | annotationEntity.altitude = model.altitude
35 | annotationEntity.stepCount = model.stepCount
36 | annotationEntity.city = model.city
37 | annotationEntity.formatterAddress = model.formatterAddress
38 | annotationEntity.markerName = model.markerName
39 |
40 | do {
41 | try context?.save()
42 | print("保存成功")
43 | return true
44 | } catch {
45 | print("不能保存:\(error)")
46 | return false
47 | }
48 | }
49 |
50 |
51 | func allAnnotation() -> [AnnotationModel] {
52 | var annotationArray = [AnnotationModel]()
53 | let fetchRequest = NSFetchRequest(entityName:"Annotation")
54 | do {
55 | let fetchedObjects = try context?.fetch(fetchRequest)
56 | for info in fetchedObjects!{
57 | let data = [
58 | "createdTimeString": info.created_time,
59 | "weatherString": info.weather,
60 | "environmentString": info.environment,
61 | "latitude": info.latitude,
62 | "longitude": info.longitude,
63 | "altitude": info.altitude,
64 | "stepCount": info.stepCount,
65 | "city": info.city,
66 | "formatterAddress": info.formatterAddress,
67 | "markerName": info.markerName,
68 | ]
69 |
70 | if let json = try? JSONSerialization.data(withJSONObject: data, options: []) {
71 | if let annotationModel = try? JSONDecoder().decode(AnnotationModel.self, from: json) {
72 | annotationArray.append(annotationModel)
73 | }
74 | }
75 | }
76 | print("查询成功")
77 | return annotationArray
78 | }
79 | catch {
80 | print("查询失败:\(error)")
81 | return []
82 | }
83 | }
84 |
85 |
86 | func updateAnnotation(formatString: String, updateTime: String) -> Bool {
87 | let fetchRequest = NSFetchRequest(entityName:"Annotation")
88 | let predict = NSPredicate(format: formatString, argumentArray: nil)
89 | fetchRequest.predicate = predict
90 | do {
91 | let annotation = try context?.fetch(fetchRequest)[0]
92 | annotation?.created_time = updateTime
93 | do {
94 | try context?.save()
95 | print("保存成功")
96 | return true
97 | } catch {
98 | print("不能保存:\(error)")
99 | return false
100 | }
101 | } catch {
102 | print("查询成功")
103 | return false
104 | }
105 | }
106 |
107 |
108 | func deleteAnnotation(model: AnnotationModel) {
109 | let fetchRequest = NSFetchRequest(entityName:"Annotation")
110 | let coordinate = NSPredicate(format: "longitude=\(model.longitude) and latitude=\(model.latitude)")
111 | fetchRequest.predicate = coordinate
112 | do {
113 | let fetchedObjects = try context?.fetch(fetchRequest)
114 | for instance in fetchedObjects! {
115 | context?.delete(instance)
116 | }
117 | } catch {
118 | print("删除查询出错:\(error)")
119 | print("查询成功")
120 | }
121 | do {
122 | try context?.save()
123 | print("删除成功")
124 | } catch {
125 | print("删除出错:\(error)")
126 | }
127 | }
128 |
129 |
130 | func annotationContent(model: AnnotationModel) -> String {
131 | let fetchRequest = NSFetchRequest(entityName:"AnnotationContent")
132 | let contentPredicate = NSPredicate(format: "longitude=\(model.longitude) and latitude=\(model.latitude)")
133 | fetchRequest.predicate = contentPredicate
134 | do {
135 | let fetchedObjects = try context?.fetch(fetchRequest)
136 | print("查询成功")
137 | return fetchedObjects?.first?.content ?? ""
138 | }
139 | catch {
140 | print("查询失败:\(error)")
141 | return ""
142 | }
143 | }
144 |
145 |
146 | func addAnnotationContent(content: String, model: AnnotationModel) -> Bool {
147 | let fetchRequest = NSFetchRequest(entityName:"AnnotationContent")
148 | let contentPredicate = NSPredicate(format: "longitude=\(model.longitude) and latitude=\(model.latitude)")
149 | fetchRequest.predicate = contentPredicate
150 | do {
151 | let fetchedObjects = try context?.fetch(fetchRequest)
152 | print("查询成功")
153 |
154 | let object = fetchedObjects?.first
155 |
156 | if object?.content != nil {
157 | context?.delete(object!)
158 | }
159 |
160 | let annotationEntity = NSEntityDescription.insertNewObject(forEntityName: "AnnotationContent", into: context!) as! AnnotationContent
161 | annotationEntity.content = content
162 | annotationEntity.longitude = model.longitude
163 | annotationEntity.latitude = model.latitude
164 |
165 | do {
166 | try context?.save()
167 | print("保存成功")
168 | return true
169 | } catch {
170 | print("不能保存:\(error)")
171 | return false
172 | }
173 | }
174 | catch {
175 | print("查询失败:\(error)")
176 | return false
177 | }
178 | }
179 |
180 |
181 | func addAnnotationPhoto(photoImage: UIImage, model: AnnotationModel) -> Bool {
182 |
183 | _ = deleteAnnotationImage(model: model)
184 |
185 | let annotationEntity = NSEntityDescription.insertNewObject(forEntityName: "AnnotationImage", into: context!) as! AnnotationImage
186 | annotationEntity.image = UIImageJPEGRepresentation(photoImage, 1)
187 | annotationEntity.longitude = model.longitude
188 | annotationEntity.latitude = model.latitude
189 |
190 | do {
191 | try context?.save()
192 | print("保存成功")
193 | return true
194 | } catch {
195 | print("不能保存:\(error)")
196 | return false
197 | }
198 | }
199 |
200 |
201 | func annotationImage(model: AnnotationModel) -> UIImage? {
202 | let fetchRequest = NSFetchRequest(entityName:"AnnotationImage")
203 | let contentPredicate = NSPredicate(format: "longitude=\(model.longitude) and latitude=\(model.latitude)")
204 | fetchRequest.predicate = contentPredicate
205 | do {
206 | let fetchedObjects = try context?.fetch(fetchRequest)
207 | print("查询成功")
208 | if fetchedObjects?.first != nil {
209 | return UIImage(data: fetchedObjects!.first!.image!)!
210 | } else {
211 | return nil
212 | }
213 | }
214 | catch {
215 | print("查询失败:\(error)")
216 | return nil
217 | }
218 | }
219 |
220 |
221 | func deleteAnnotationImage(model: AnnotationModel) -> Bool {
222 | let fetchRequest = NSFetchRequest(entityName:"AnnotationImage")
223 | let contentPredicate = NSPredicate(format: "longitude=\(model.longitude) and latitude=\(model.latitude)")
224 | fetchRequest.predicate = contentPredicate
225 | do {
226 | let fetchedObjects = try context?.fetch(fetchRequest)
227 | for instance in fetchedObjects! {
228 | context?.delete(instance)
229 | }
230 |
231 | print("查询成功")
232 | return true
233 | }
234 | catch {
235 | print("查询失败:\(error)")
236 | return false
237 | }
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/PFollow/Common/PJDefine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJDefine.swift
3 | // DiDiData
4 | //
5 | // Created by PJ on 2018/4/24.
6 | // Copyright © 2018年 Didi.Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 |
12 |
13 | // MARK: - 设备
14 | let PJSCREEN_HEIGHT = CGFloat(UIScreen.main.bounds.height)
15 | let PJSCREEN_WIDTH = CGFloat(UIScreen.main.bounds.width)
16 | let PJTABBAR_HEIGHT = CGFloat(48)
17 | let PJStatusHeight = UIApplication.shared.statusBarFrame.size.height
18 |
19 | // 不能直接这么写死 34
20 | let PJBottomLinerHeight = iPhoneX ? CGFloat(34) : 0
21 | let iPhoneX = PJSCREEN_HEIGHT == 812
22 |
23 | func PJDeviceWithPortrait() -> Bool {
24 | return UIDevice.current.orientation == .portrait || UIDevice.current.orientation == .portraitUpsideDown
25 | }
26 |
27 | func PJDevice() -> String {
28 | let currentScreen = UIScreen.main.currentMode?.size
29 | if currentScreen == CGSize.init(width: 1125, height: 2436) {
30 | return "iPhoneX"
31 | } else {
32 | return "None"
33 | }
34 | }
35 |
36 | func PJUILength(length: Int) -> CGFloat {
37 | return PJSCREEN_WIDTH * CGFloat(length) / 375
38 | }
39 |
40 |
41 | // MARK: - 位置
42 | func x(object: UIView) -> CGFloat {
43 | return object.frame.origin.x
44 | }
45 | func y(object: UIView) -> CGFloat {
46 | return object.frame.origin.y
47 | }
48 | func w(object: UIView) -> CGFloat {
49 | return object.frame.size.width
50 | }
51 | func h(object: UIView) -> CGFloat {
52 | return object.frame.size.height
53 | }
54 |
55 |
56 | // MARK: - 字符串
57 | func getStringLength(string: String) -> CGFloat {
58 | let count = string.count;
59 | if inputLetterAndSpace(string) {
60 | return CGFloat(9 * count)
61 | }
62 | return CGFloat(16 * count)
63 | }
64 |
65 | func inputLetterAndSpace(_ string: String) -> Bool {
66 | let regex = "[ a-zA-Z]*"
67 | let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
68 | let inputString = predicate.evaluate(with: string)
69 | return inputString
70 | }
71 |
72 |
73 | // MARK: - 颜色
74 | func PJRGB(r: CGFloat, g:CGFloat, b:CGFloat) -> UIColor {
75 | return UIColor.init(red: r/255.0, green: g/255.0, blue: b/255.0, alpha: 1)
76 | }
77 |
78 |
79 | // MARK: - 视图
80 | func PJInsertRoundingCorners(_ view: UIView) {
81 | let path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 8.0, height: 8.0))
82 | let pathMaskLayer = CAShapeLayer()
83 | pathMaskLayer.frame = view.bounds
84 | pathMaskLayer.path = path.cgPath
85 | view.layer.mask = pathMaskLayer
86 | }
87 |
88 | // MARK: - 通知
89 | let PJNotificationName_changeLanguage = "PJNotificationNameChangeLanguage"
90 | let PJNotificationName_appOut = "PJNotificationNameAppOut"
91 | let PJNotificationName_network = "kONEONENetworkStatusChange"
92 | let PJNotificationName_updateCallouView = "PJNotitficationNameUpdateCallout"
93 |
94 |
95 |
--------------------------------------------------------------------------------
/PFollow/Common/PJTapic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJTapic.swift
3 | // Bonfire
4 | //
5 | // Created by pjpjpj on 2018/5/19.
6 | // Copyright © 2018年 #incloud. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PJTapic: NSObject {
12 |
13 | class func select() {
14 | let g = UISelectionFeedbackGenerator.init()
15 | g.selectionChanged()
16 | g.prepare()
17 | }
18 |
19 | class func succee() {
20 | let g = UINotificationFeedbackGenerator.init()
21 | g.notificationOccurred(.success)
22 | g.prepare()
23 | }
24 |
25 | class func warning() {
26 | let g = UINotificationFeedbackGenerator.init()
27 | g.notificationOccurred(.warning)
28 | g.prepare()
29 | }
30 |
31 | class func error() {
32 | let g = UINotificationFeedbackGenerator.init()
33 | g.notificationOccurred(.error)
34 | g.prepare()
35 | }
36 |
37 | class func tap() {
38 | UIImpactFeedbackGenerator.init(style: .light).impactOccurred()
39 | }
40 |
41 | class func tipsTap() {
42 | // if crash, use AudioServicesPlaySystemSound(1519)
43 | UIImpactFeedbackGenerator.init(style: .heavy).impactOccurred()
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/PFollow/Common/PJTools-UIView+Position.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJTools-UIView+Position.swift
3 | // DiDiData
4 | //
5 | // Created by PJ on 2018/4/26.
6 | // Copyright © 2018年 Didi.Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 |
13 | static private let PJSCREEN_SCALE = UIScreen.main.scale
14 |
15 | private func getPixintegral(pointValue: CGFloat) -> CGFloat {
16 | return round(pointValue * UIView.PJSCREEN_SCALE) / UIView.PJSCREEN_SCALE
17 | }
18 |
19 | public var x: CGFloat {
20 | get {
21 | return self.frame.origin.x
22 | }
23 | set(x) {
24 | self.frame = CGRect.init(
25 | x: getPixintegral(pointValue: x),
26 | y: self.y,
27 | width: self.width,
28 | height: self.height
29 | )
30 | }
31 | }
32 |
33 | public var y: CGFloat {
34 | get {
35 | return self.frame.origin.y
36 | }
37 | set(y) {
38 | self.frame = CGRect.init(
39 | x: self.x,
40 | y: getPixintegral(pointValue: y),
41 | width: self.width,
42 | height: self.height
43 | )
44 | }
45 | }
46 |
47 | public var width: CGFloat {
48 | get {
49 | return self.frame.size.width
50 | }
51 | set(width) {
52 | self.frame = CGRect.init(
53 | x: self.x,
54 | y: self.y,
55 | width: getPixintegral(pointValue: width),
56 | height: self.height
57 | )
58 | }
59 | }
60 |
61 | public var height: CGFloat {
62 | get {
63 | return self.frame.size.height
64 | }
65 | set (height) {
66 | self.frame = CGRect.init(
67 | x: self.x,
68 | y: self.y,
69 | width: self.width,
70 | height: getPixintegral(pointValue: height)
71 | )
72 | }
73 | }
74 |
75 | public var bottom: CGFloat {
76 | get {
77 | return self.y + self.height
78 | }
79 | set(bottom) {
80 | self.y = bottom - self.height
81 | }
82 | }
83 |
84 | public var right: CGFloat {
85 | get {
86 | return self.x + self.width
87 | }
88 | set (right) {
89 | self.x = right - self.width
90 | }
91 | }
92 |
93 | public var left: CGFloat {
94 | get {
95 | return self.x
96 | }
97 | set(left) {
98 | self.x = left
99 | }
100 | }
101 |
102 | public var top: CGFloat {
103 | get {
104 | return self.y
105 | }
106 | set(top) {
107 | self.y = top
108 | }
109 | }
110 |
111 | public var centerX: CGFloat {
112 | get {
113 | return self.center.x
114 | }
115 | set(centerX) {
116 | self.center = CGPoint.init(
117 | x: getPixintegral(pointValue: centerX),
118 | y: self.center.y
119 | )
120 | }
121 | }
122 |
123 | public var centerY: CGFloat {
124 | get {
125 | return self.center.y
126 | }
127 | set (centerY) {
128 | self.center = CGPoint.init(x: self.center.x, y: getPixintegral(pointValue: centerY))
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/PFollow/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPhotoLibraryAddUsageDescription
6 | PFollow 需要获取您的相册读取权限以供您进行读取和保存照片
7 | NSCameraUsageDescription
8 | PFollow 需要获取您的相机运行权限以供您进行拍照
9 | CFBundleDevelopmentRegion
10 | zh_CN
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSLocationWhenInUseUsageDescription
28 | PFollow 需要获取您的地理位置信息以标识大头针和海拔高度
29 | NSMotionUsageDescription
30 | PFollow 需要获取您的健康信息以显示步数
31 | UILaunchStoryboardName
32 | LaunchScreen
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UIStatusBarStyle
38 | UIStatusBarStyleLightContent
39 | UISupportedInterfaceOrientations
40 |
41 | UIInterfaceOrientationPortrait
42 |
43 | UISupportedInterfaceOrientations~ipad
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/PFollow/PFollow-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import
6 | #import
7 | #import
8 |
9 |
--------------------------------------------------------------------------------
/PFollow/PFollow.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.healthkit
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PFollow/PFollow.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | PFollow.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PFollow/PFollow.xcdatamodeld/PFollow.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/controller/PJHomeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJHomeViewController.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PJHomeViewController: PJBaseViewController, PJHomeBottomViewDelegate, PJMapViewDelete {
12 |
13 | var mapView: PJHomeMapView?
14 | var bottomView: PJHomeBottomView?
15 | var realAnnotations = [AnnotationModel]()
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | initView()
20 | }
21 |
22 | override func viewDidAppear(_ animated: Bool) {
23 | super.viewDidAppear(animated)
24 |
25 | if bottomView?.tapBtn.alpha == 0 {
26 | UIView.animate(withDuration: 0.25) {
27 | self.bottomView?.tapBtn.alpha = 1
28 | }
29 | }
30 | }
31 |
32 | override func didReceiveMemoryWarning() {
33 | super.didReceiveMemoryWarning()
34 | }
35 |
36 |
37 | // MARK: life cycle
38 | private func initView() {
39 | view.backgroundColor = .white
40 |
41 | mapView = PJHomeMapView.init(frame: CGRect(x: 0, y: 0,
42 | width: PJSCREEN_WIDTH,
43 | height: PJSCREEN_HEIGHT - PJBottomLinerHeight))
44 | mapView?.viewDelegate = self
45 | view.addSubview(mapView!)
46 |
47 | bottomView = PJHomeBottomView.init(frame: CGRect(x: -PJSCREEN_WIDTH * 0.1,
48 | y: PJSCREEN_HEIGHT - 120 - PJBottomLinerHeight,
49 | width: PJSCREEN_WIDTH * 1.2,
50 | height: 160 - PJBottomLinerHeight))
51 | bottomView?.viewDelegate = self
52 | view.addSubview(bottomView!)
53 |
54 | // 视图载入完成后,设置地图缩放等级
55 | mapView?.mapView.setZoomLevel(15, animated: true)
56 | }
57 |
58 |
59 | // MARK: - Action
60 | private func addAnnotationViewToMapView(_ coordinate: CLLocationCoordinate2D,
61 | isLongPress: Bool) {
62 | // 添加新的标记点
63 | self.mapView?.isNewAnnotation = true
64 |
65 | let pointAnnotation = MAPointAnnotation()
66 | pointAnnotation.coordinate = coordinate
67 | self.mapView?.mapView.addAnnotation(pointAnnotation)
68 | }
69 |
70 |
71 | // MARK: delegate
72 | func homeBottomViewPlacesBtnClick(view: PJHomeBottomView) {
73 | UIView.animate(withDuration: 0.25, animations: {
74 | self.bottomView?.tapBtn.alpha = 0
75 | }) { (finished) in
76 | if finished {
77 | let vc = PJPlacesViewController()
78 | vc.annotationModels = self.realAnnotations
79 | let nav = UINavigationController(rootViewController: vc)
80 | self.present(nav, animated: true, completion: nil)
81 | }
82 | }
83 | }
84 |
85 |
86 | func homeBottomViewTapBtnClick(view: PJHomeBottomView, tapBtn: UIButton) {
87 | bottomView?.isRequest = true
88 | UIView.animate(withDuration: 0.15, animations: {
89 | tapBtn.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
90 | }) { (finished) in
91 | if finished {
92 | UIView.animate(withDuration: 0.15, animations: {
93 | tapBtn.transform = CGAffineTransform(scaleX: 1, y: 1)
94 | }) {(finished) in
95 | if finished {
96 | let point = self.mapView?.mapView.convert((self.mapView?.mapView.userLocation.location.coordinate)!, toPointTo: self.mapView)
97 | print(point as Any)
98 | let tempTapImageView = UIImageView(image: UIImage(named: "home_tap"))
99 | tempTapImageView.frame.size = CGSize(width: 50, height: 50)
100 | tempTapImageView.centerX = view.centerX
101 | tempTapImageView.bottom = (self.bottomView?.bottom)!
102 | self.view.addSubview(tempTapImageView)
103 | UIView.animate(withDuration: 0.25, animations: {
104 | tempTapImageView.center = point!
105 | }) {(finished) in
106 | if finished {
107 | UIView.animate(withDuration: 0.5, animations: {
108 | tempTapImageView.alpha = 0
109 | }, completion: { (finished) in
110 | if finished {
111 | tempTapImageView.removeFromSuperview()
112 | self.addAnnotationViewToMapView((self.mapView?.mapView.userLocation.location.coordinate)!,
113 | isLongPress: false)
114 | }
115 | })
116 | }
117 | }
118 | }
119 | }
120 | }
121 | }
122 | }
123 |
124 |
125 | func mapViewTappedCalloutView(_ mapView: PJHomeMapView, annotationView: PJHomeMapAnnotationView) {
126 | let vc = PJAnnotationDetailsViewController()
127 | vc.annotationView = annotationView
128 | vc.isHiddenRightBarButton = false
129 | navigationController?.pushViewController(vc, animated: true)
130 | }
131 |
132 |
133 | func mapView(mapView: PJHomeMapView, rotateDegree: CGFloat) {
134 | // 调整指南针选择方向角度
135 | bottomView?.rotateDegree = (rotateDegree - 45)
136 | }
137 |
138 |
139 | func mapView(mapView: PJHomeMapView, isRequested: Bool) {
140 | // 如果失败要给 HUD 提示
141 | if isRequested {
142 | bottomView?.isRequest = !isRequested
143 | }
144 | }
145 |
146 |
147 | func mapViewInitComplate(_ mapView: PJHomeMapView) {
148 | // 读取 Annotation 缓存
149 | let caches = PJCoreDataHelper.shared.allAnnotation()
150 | if caches.count != 0 {
151 | mapView.models = caches
152 | // 从 CoreData 中读取数据
153 | mapView.isCache = true
154 | // 不是新加入的标记点
155 | mapView.isNewAnnotation = false
156 | var index = 0
157 | for annotation in caches {
158 | let pointAnnotation = MAPointAnnotation()
159 | pointAnnotation.coordinate = CLLocationCoordinate2D.init(latitude: Double(annotation.latitude)!, longitude: Double(annotation.longitude)!)
160 | mapView.mapView.addAnnotation(pointAnnotation)
161 |
162 | if annotation.createdTimeString.contains("/") {
163 | realAnnotations.append(annotation)
164 | }
165 |
166 | index += 1
167 | }
168 | }
169 | }
170 |
171 |
172 | func mapView(mapView: PJHomeMapView, didLongPressCoordinate: CLLocationCoordinate2D) {
173 | PJTapic.tap()
174 | addAnnotationViewToMapView(didLongPressCoordinate, isLongPress: true)
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/model/AnnotationModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnnotationModel.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/18.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 | struct AnnotationModel: Codable {
13 | // 天气信息
14 | var weatherString: String
15 | // 创建时间
16 | var createdTimeString: String
17 | // 环境信息
18 | var environmentString: String
19 | // 纬度
20 | var latitude: String
21 | // 精度
22 | var longitude: String
23 | // 海拔高度
24 | var altitude: String
25 | // 步数
26 | var stepCount: String
27 | // 城市
28 | var city: String
29 | // 格式化地址
30 | var formatterAddress: String
31 | // 大头针图片名字
32 | var markerName: String
33 | }
34 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/view/MapView/PJHomeMapAnnotetionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJHomeMapAnnotetionView.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/16.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol PJHomeMapAnnotationViewDelegate {
12 | @objc optional func homeMapAnnotationView(annotationView: PJHomeMapAnnotationView, removeAnnotaion: MAAnnotation)
13 | @objc optional func homeMapAnnotationView(annotationView: PJHomeMapAnnotationView, shareAnnotaion: MAAnnotation)
14 | @objc optional func homeMapAnnotationViewTappedView(calloutView: PJHomeMapCalloutView, annotationView: PJHomeMapAnnotationView)
15 | }
16 |
17 | class PJHomeMapAnnotationView: MAAnnotationView, PJHomeMapCalloutViewDelegate, CAAnimationDelegate {
18 |
19 | var viewDelegate: PJHomeMapAnnotationViewDelegate?
20 | var model: AnnotationModel?
21 |
22 | private var calloutView: PJHomeMapCalloutView?
23 | private var kCalloutWidth = 180.0
24 | private var kCalloutHeight = 100.0
25 |
26 |
27 | override init!(annotation: MAAnnotation!, reuseIdentifier: String!) {
28 | super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
29 |
30 | NotificationCenter.default.addObserver(self,
31 | selector: #selector(updateCalloutView),
32 | name: NSNotification.Name(rawValue: PJNotificationName_updateCallouView),
33 | object: nil)
34 | }
35 |
36 |
37 | required init?(coder aDecoder: NSCoder) {
38 | model = nil
39 | super.init(coder: aDecoder)
40 | }
41 |
42 |
43 | // MARK: override
44 | override func setSelected(_ selected: Bool, animated: Bool) {
45 | if self.isSelected == selected {
46 | return
47 | }
48 | if selected {
49 | if calloutView == nil {
50 | calloutView = PJHomeMapCalloutView(frame: CGRect(x: 0, y: 0, width: kCalloutWidth, height: kCalloutHeight))
51 | calloutView?.center = CGPoint(x: bounds.width / 2.0 + calloutOffset.x, y: -((calloutView?.bounds.height)! / 2.0) + calloutOffset.y)
52 | }
53 | calloutView?.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
54 | calloutView?.viewDelegate = self
55 | calloutView?.y += 20
56 | calloutView?.alpha = 0
57 |
58 | if model != nil {
59 | calloutView?.model = model
60 | }
61 |
62 | UIView.animateKeyframes(withDuration: 0.15, delay: 0, options: .calculationModeCubic, animations: {
63 | self.calloutView?.alpha = 1.0
64 | self.calloutView?.y -= 20
65 | self.calloutView?.transform = CGAffineTransform(scaleX: 1, y: 1)
66 | }) { (finished) in
67 | PJTapic.tipsTap()
68 | }
69 |
70 | addSubview(calloutView!)
71 | } else {
72 | calloutView?.removeFromSuperview()
73 | }
74 |
75 | super.setSelected(selected, animated: animated)
76 | }
77 |
78 |
79 | // 修改响应链
80 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
81 | if calloutView != nil {
82 | let deletePoint = calloutView?.deleteBtn.convert(point, from: self)
83 | if (calloutView?.deleteBtn.bounds.contains(deletePoint!))! {
84 | return calloutView?.deleteBtn
85 | }
86 | let sharePoint = calloutView?.shareBtn.convert(point, from: self)
87 | if (calloutView?.shareBtn.bounds.contains(sharePoint!))! {
88 | return calloutView?.shareBtn
89 | }
90 | let calloutPoint = calloutView?.convert(point, from: self)
91 | if (calloutView?.bounds.contains(calloutPoint!))! {
92 | return calloutView
93 | }
94 | }
95 | return super.hitTest(point, with: event)
96 | }
97 |
98 |
99 | override func willMove(toSuperview newSuperview: UIView?) {
100 | super.willMove(toSuperview: newSuperview)
101 |
102 | // 防止删除大头针的时候调用该方法,传入 nil
103 | if newSuperview == nil {
104 | return
105 | }
106 |
107 | if(newSuperview?.bounds.contains(self.center))! {
108 | let growAnimation = CABasicAnimation.init(keyPath: "transform.scale")
109 | growAnimation.delegate = self
110 | growAnimation.duration = 0.25;
111 | growAnimation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear)
112 | growAnimation.fromValue = 0
113 | growAnimation.toValue = 1.0
114 |
115 | self.layer.add(growAnimation, forKey: "growAnimation")
116 | }
117 | }
118 |
119 |
120 | // MARK: Notification
121 | @objc private func updateCalloutView(notifi: Notification) {
122 | let timeString = notifi.userInfo!["time"] as! String
123 | calloutView?.titleString = timeString
124 | }
125 |
126 |
127 | // MARK: delegate
128 | func homeMapCalloutRemoveAnnotation(callout: PJHomeMapCalloutView) {
129 | viewDelegate?.homeMapAnnotationView!(annotationView: self, removeAnnotaion: self.annotation)
130 | }
131 |
132 |
133 | func homeMapCalloutShareAnnotation(callout: PJHomeMapCalloutView) {
134 | viewDelegate?.homeMapAnnotationView!(annotationView: self, shareAnnotaion: self.annotation)
135 | }
136 |
137 |
138 | func homeMapCalloutTapped(callout: PJHomeMapCalloutView) {
139 | viewDelegate?.homeMapAnnotationViewTappedView!(calloutView: callout, annotationView: self)
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/view/MapView/PJHomeMapCalloutView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJHomeMapCalloutView.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/14.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol PJHomeMapCalloutViewDelegate {
12 | @objc optional func homeMapCalloutRemoveAnnotation(callout: PJHomeMapCalloutView)
13 | @objc optional func homeMapCalloutShareAnnotation(callout: PJHomeMapCalloutView)
14 | @objc optional func homeMapCalloutTapped(callout: PJHomeMapCalloutView)
15 | }
16 |
17 | class PJHomeMapCalloutView: UIView {
18 |
19 | var viewDelegate: PJHomeMapCalloutViewDelegate?
20 | var model: AnnotationModel? {
21 | willSet(model) {
22 | willSetModel(model!)
23 | }
24 | }
25 |
26 | var titleString: String = "" {
27 | willSet(s) {
28 | willSetTitleString(s)
29 | }
30 | }
31 |
32 | private(set) var shareBtn = UIButton()
33 | private(set) var deleteBtn = UIButton()
34 | private var weatherImageView = UIImageView()
35 | private var titleLabel = UILabel()
36 | private var temperatureLabel = UILabel()
37 | private let kArrorHeight = CGFloat(10)
38 |
39 | override init(frame: CGRect) {
40 | super.init(frame: frame)
41 | self.backgroundColor = .clear
42 | self.isUserInteractionEnabled = true
43 | let tapped = UITapGestureRecognizer.init(target: self, action: #selector(calloutViewTapped))
44 | self.addGestureRecognizer(tapped)
45 |
46 | weatherImageView.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
47 | addSubview(weatherImageView)
48 |
49 | temperatureLabel.textColor = .black
50 | temperatureLabel.textAlignment = .left
51 | temperatureLabel.font = UIFont.systemFont(ofSize: 12, weight: .thin)
52 | temperatureLabel.frame = CGRect(x: 22, y: weatherImageView.y, width: 30, height: 20)
53 | addSubview(temperatureLabel)
54 |
55 | titleLabel.textColor = .black
56 | titleLabel.textAlignment = .center
57 | titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular)
58 | titleLabel.frame = CGRect(x: 5, y: temperatureLabel.bottom + 10, width: self.width - 10, height: 20)
59 | addSubview(titleLabel)
60 |
61 | let stackView = UIStackView(frame: CGRect(x: 0, y: self.bottom - 45, width: self.width, height: 30))
62 | stackView.alignment = .fill
63 | stackView.axis = .horizontal
64 | stackView.spacing = 10
65 | stackView.distribution = .fillEqually
66 | addSubview(stackView)
67 |
68 | deleteBtn.addTarget(self, action: #selector(deleteBtnAction), for: .touchUpInside)
69 | deleteBtn.setImage(UIImage(named: "callout_delete"), for: .normal)
70 | stackView.addArrangedSubview(deleteBtn)
71 |
72 | shareBtn.addTarget(self, action: #selector(shareBtnAction), for: .touchUpInside)
73 | shareBtn.setImage(UIImage(named: "callout_share"), for: .normal)
74 | stackView.addArrangedSubview(shareBtn)
75 | }
76 |
77 | required init?(coder aDecoder: NSCoder) {
78 | super.init(coder: aDecoder)
79 | }
80 |
81 |
82 | // MARK: Action
83 | @objc private func deleteBtnAction() {
84 | viewDelegate?.homeMapCalloutRemoveAnnotation!(callout: self)
85 | }
86 |
87 |
88 | @objc private func shareBtnAction() {
89 | viewDelegate?.homeMapCalloutShareAnnotation!(callout: self)
90 | }
91 |
92 |
93 | @objc private func calloutViewTapped() {
94 | viewDelegate?.homeMapCalloutTapped!(callout: self)
95 | }
96 |
97 |
98 | private func willSetTitleString(_ s: String) {
99 | titleLabel.text = s
100 | }
101 |
102 |
103 | override func draw(_ rect: CGRect) {
104 | if let aContext = UIGraphicsGetCurrentContext() {
105 | draw(in: aContext)
106 | }
107 | layer.shadowColor = UIColor.black.cgColor
108 | layer.shadowOpacity = 0.3
109 | layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
110 | }
111 |
112 | func draw(in context: CGContext) {
113 | context.setLineWidth(2.0)
114 | context.setFillColor(UIColor.white.cgColor)
115 | getDrawPath(context)
116 | context.fillPath()
117 | }
118 |
119 | func getDrawPath(_ context: CGContext?) {
120 | let rrect: CGRect = bounds
121 | let radius: CGFloat = 6.0
122 | let minx = rrect.minX
123 | let midx = rrect.midX
124 | let maxx = rrect.maxX
125 | let miny = rrect.minY
126 | let maxy: CGFloat = rrect.maxY - kArrorHeight
127 | context?.move(to: CGPoint(x: midx + kArrorHeight, y: maxy))
128 | context?.addLine(to: CGPoint(x: midx, y: maxy + kArrorHeight))
129 | context?.addLine(to: CGPoint(x: midx - kArrorHeight, y: maxy))
130 | context?.addArc(tangent1End: CGPoint(x: minx, y: maxy), tangent2End: CGPoint(x: minx, y: miny), radius: radius)
131 | context?.addArc(tangent1End: CGPoint(x: minx, y: minx), tangent2End: CGPoint(x: maxx, y: miny), radius: radius)
132 | context?.addArc(tangent1End: CGPoint(x: maxx, y: miny), tangent2End: CGPoint(x: maxx, y: maxx), radius: radius)
133 | context?.addArc(tangent1End: CGPoint(x: maxx, y: maxy), tangent2End: CGPoint(x: midx, y: maxy), radius: radius)
134 | context?.closePath()
135 | }
136 |
137 |
138 | // MARK: setter and getter
139 | private func willSetModel(_ model: AnnotationModel) {
140 | if model.createdTimeString.contains("/") {
141 | let startIndex = model.createdTimeString.startIndex
142 | let endIndex = model.createdTimeString.index(startIndex, offsetBy: 10)
143 | titleLabel.text = String(model.createdTimeString[startIndex...endIndex]) + " 来过"
144 | } else {
145 | titleLabel.text = model.createdTimeString
146 | }
147 |
148 | weatherImageView.image = UIImage(named: model.weatherString)
149 | temperatureLabel.text = model.environmentString
150 | temperatureLabel.sizeToFit()
151 | temperatureLabel.left = weatherImageView.right + 2
152 | temperatureLabel.centerY = weatherImageView.centerY + 2
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/view/MapView/PJHomeMapView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJHomeMapView.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreMotion
11 |
12 | protocol PJMapViewDelete: class {
13 | func mapView(mapView: PJHomeMapView,
14 | rotateDegree: CGFloat)
15 | func mapView(mapView: PJHomeMapView,
16 | isRequested: Bool)
17 | func mapView(mapView: PJHomeMapView,
18 | didLongPressCoordinate: CLLocationCoordinate2D)
19 | func mapViewInitComplate(_ mapView: PJHomeMapView)
20 | func mapViewTappedCalloutView(_ mapView: PJHomeMapView,
21 | annotationView: PJHomeMapAnnotationView)
22 | }
23 | extension PJMapViewDelete {
24 | func mapView(mapView: PJHomeMapView,
25 | rotateDegree: CGFloat) {}
26 | func mapView(mapView: PJHomeMapView,
27 | isRequested: Bool) {}
28 | func mapView(mapView: PJHomeMapView,
29 | didLongPressCoordinate: CLLocationCoordinate2D) {}
30 | func mapViewInitComplate(_ mapView: PJHomeMapView) {}
31 | func mapViewTappedCalloutView(_ mapView: PJHomeMapView,
32 | annotationView: PJHomeMapAnnotationView) {}
33 | }
34 |
35 | class PJHomeMapView: UIView, MAMapViewDelegate, AMapSearchDelegate, PJHomeMapAnnotationViewDelegate {
36 |
37 | static let PJNotificationName_annotation = Notification.Name("PJNotificationName_annotation")
38 |
39 | weak var viewDelegate: PJMapViewDelete?
40 | var models = [AnnotationModel]()
41 |
42 | // 是否从 CoreData 中读取数据
43 | var isCache = false
44 | // 是否为新建标记点
45 | var isNewAnnotation = true
46 | // 是否为用户长按添加的标记点
47 | private var isLongPress = false
48 |
49 | private var isBigZoom = false
50 | private var isSmallZoom = false
51 | private var notificationRecoder = 0
52 | private var currentCacheAnnotationIndex = 0
53 |
54 | private var currentAnnotation: MAAnnotation?
55 | private var currentAnnotationModel: AnnotationModel?
56 | private var currentAnnotationView: PJHomeMapAnnotationView?
57 |
58 | private(set) var mapView: MAMapView = MAMapView()
59 |
60 | private var r = MAUserLocationRepresentation()
61 | private var pedometer = CMPedometer()
62 | private let search = AMapSearchAPI()
63 | private let req = AMapWeatherSearchRequest()
64 | // 查询完环境和天气后的最终字典
65 | private var finalModelDict = [String: String]()
66 | // 地图上的当前所有大头针
67 | private var annotationViews = [PJHomeMapAnnotationView]()
68 | private var biggerAnnotationViews = [PJHomeMapAnnotationView]()
69 | private var smallAnnotationViews = [PJHomeMapAnnotationView]()
70 |
71 |
72 | // MARK: life cycle
73 | override init(frame: CGRect) {
74 | super.init(frame: frame)
75 | initView()
76 |
77 | NotificationCenter.default.addObserver(self,
78 | selector: #selector(messageQueueNotification(notify:)),
79 | name: PJHomeMapView.PJNotificationName_annotation,
80 | object: nil)
81 | }
82 |
83 |
84 | required init?(coder aDecoder: NSCoder) {
85 | super.init(coder: aDecoder)
86 | }
87 |
88 |
89 | fileprivate func initView() {
90 | AMapServices.shared().enableHTTPS = true
91 |
92 | search?.delegate = self
93 | req.type = AMapWeatherType.live
94 |
95 | mapView.frame = frame
96 | mapView.delegate = self
97 | // 设置比例尺原点位置
98 | mapView.scaleOrigin = CGPoint(x: 10, y: 30)
99 | // 设置罗盘原点位置
100 | mapView.compassOrigin = CGPoint(x: PJSCREEN_WIDTH - 50, y: 30)
101 | // 开启地图自定义样式
102 | mapView.customMapStyleEnabled = true;
103 | // 显示显示用户位置
104 | mapView.showsUserLocation = true
105 | // 用户模式跟踪
106 | mapView.userTrackingMode = .follow
107 | addSubview(mapView)
108 |
109 | r.image = UIImage(named: "home_map_userlocation")
110 | r.showsAccuracyRing = false
111 | mapView.update(r)
112 |
113 | var path = Bundle.main.bundlePath
114 | path.append("/mapView.data")
115 | let jsonData = NSData.init(contentsOfFile: path)
116 | mapView.setCustomMapStyleWithWebData(jsonData as Data?)
117 | }
118 |
119 |
120 | // MARK: notification
121 | @objc private func messageQueueNotification(notify: Notification) {
122 | var params = notify.userInfo as! [String: String]
123 | if params["notifi_name"] == "city" {
124 | notificationRecoder += 1
125 | params.removeValue(forKey: "notifi_name")
126 | finalModelDict.merge(params,
127 | uniquingKeysWith: { $1 })
128 | }
129 |
130 | if params["notifi_name"] == "weather" {
131 | params.removeValue(forKey: "notifi_name")
132 | notificationRecoder += 1
133 | finalModelDict.merge(params,
134 | uniquingKeysWith: { $1 })
135 | }
136 |
137 | if notificationRecoder == 2 {
138 | notificationRecoder = 0
139 | getPedonmeterData(json: finalModelDict)
140 | }
141 |
142 |
143 | if isLongPress {
144 | notificationRecoder = 0
145 | isLongPress = false
146 |
147 | let longPressModel = AnnotationModel(weatherString: "-",
148 | createdTimeString: "还未填写来过时间",
149 | environmentString: "-",
150 | latitude: String(Double(currentAnnotation!.coordinate.latitude)),
151 | longitude: String(Double(currentAnnotation!.coordinate.longitude)),
152 | altitude: "-",
153 | stepCount: "-",
154 | city: finalModelDict["city"]!,
155 | formatterAddress: finalModelDict["formatterAddress"]!,
156 | markerName: "home_map_makers_03")
157 |
158 | currentAnnotationView?.model = longPressModel
159 | // models 为 controller 传入,更新 annotationView 时需要用到它,所以当在 mapview 内部添加新 model 时,需要更新 models
160 | models.append(longPressModel)
161 |
162 | if mapView.zoomLevel < 12.8 {
163 | currentAnnotationView?.image = UIImage(named: longPressModel.markerName)
164 | } else {
165 | currentAnnotationView?.image = UIImage(named: longPressModel.markerName + "_b")
166 | }
167 | let _ = addNewAnnotationView(annotationModel: longPressModel,
168 | annotationView: currentAnnotationView!)
169 | }
170 | }
171 |
172 |
173 | private func getPedonmeterData(json: [String: String]) {
174 | pedometer = CMPedometer()
175 | if CMPedometer.isStepCountingAvailable(){
176 | let calendar = Calendar.current
177 | let now = Date()
178 | let components = calendar.dateComponents([.year, .month, .day],
179 | from: now)
180 | let startDate = calendar.date(from: components)
181 | pedometer.queryPedometerData(from: startDate!, to: Date(), withHandler: { (data, error) in
182 | if error != nil{
183 | print("/(error?.localizedDescription)")
184 | }else{
185 | if data != nil {
186 | var json = json
187 | json["stepCount"] = String(Int(truncating: (data?.numberOfSteps)!))
188 | if let json = try? JSONSerialization.data(withJSONObject: json,
189 | options: []) {
190 | if let annotationModel = try? JSONDecoder().decode(AnnotationModel.self,
191 | from: json) {
192 | DispatchQueue.main.async {
193 | self.currentAnnotationView?.model = annotationModel
194 |
195 | if self.mapView.zoomLevel < 12.8 {
196 | self.currentAnnotationView?.image = UIImage(named: annotationModel.markerName)
197 | } else {
198 | self.currentAnnotationView?.image = UIImage(named: annotationModel.markerName + "_b")
199 | }
200 |
201 | self.models.append(annotationModel)
202 | // 添加新大头针
203 | let isRequest = self.addNewAnnotationView(annotationModel: annotationModel,
204 | annotationView: self.currentAnnotationView!)
205 | self.viewDelegate?.mapView(mapView: self,
206 | isRequested: isRequest)
207 | }
208 | }
209 | }
210 | }
211 | }
212 | })
213 | }
214 | }
215 |
216 |
217 | // tag == 0 为用户位置蓝点,在添加上 mapView 之前先判断然后不允许进行交互
218 | func mapView(_ mapView: MAMapView!, didAddAnnotationViews views: [Any]!) {
219 | for view in views {
220 | let v = view as! MAAnnotationView
221 | if v.tag == 0 {
222 | v.isUserInteractionEnabled = false
223 | }
224 | }
225 | }
226 |
227 |
228 | func mapView(_ mapView: MAMapView!,
229 | viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
230 | // 若为用户标签则 nil
231 | if annotation.isKind(of: MAUserLocation.self) {
232 | return nil
233 | }
234 |
235 | // 判断如果是 `MAPointAnnotation` 类型则返回自定义大头针
236 | if annotation.isKind(of: MAPointAnnotation.self) {
237 | let annotationStyleReuseIndetifier = "annotationStyleReuserIdentifier"
238 |
239 | var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationStyleReuseIndetifier) as! PJHomeMapAnnotationView?
240 |
241 | if annotationView == nil {
242 | annotationView = PJHomeMapAnnotationView(annotation: annotation,
243 | reuseIdentifier: annotationStyleReuseIndetifier)
244 | }
245 | annotationView?.canShowCallout = false
246 | annotationView?.viewDelegate = self
247 | // 该 tag 只是用于跟 userLocal 标记分开,不能唯一标识一个大头针
248 | annotationView?.tag = -2333
249 |
250 | currentAnnotation = annotation
251 | currentAnnotationView = annotationView
252 |
253 | if isCache && !isNewAnnotation {
254 | for model in models {
255 | if model.latitude == String(Double(annotation.coordinate.latitude)) &&
256 | model.longitude == String(Double(annotation.coordinate.longitude)) {
257 | annotationView?.model = model
258 | if mapView.zoomLevel < 12.8 {
259 | annotationView?.image = UIImage(named: model.markerName)
260 | } else {
261 | annotationView?.image = UIImage(named: model.markerName + "_b")
262 | }
263 |
264 | annotationViews.append(annotationView!)
265 | break
266 | }
267 | }
268 | return annotationView
269 | }
270 |
271 | // 请求环境数据
272 | let request = AMapReGeocodeSearchRequest()
273 | request.location = AMapGeoPoint.location(withLatitude: CGFloat(annotation.coordinate.latitude),
274 | longitude: CGFloat(annotation.coordinate.longitude))
275 | request.requireExtension = true
276 | search?.aMapReGoecodeSearch(request)
277 |
278 | // 添加完新的标记点后,设置为 false
279 | isNewAnnotation = false
280 | return annotationView
281 | }
282 |
283 | return nil
284 | }
285 |
286 |
287 | func addNewAnnotationView(annotationModel: AnnotationModel,
288 | annotationView: PJHomeMapAnnotationView) -> Bool {
289 | self.annotationViews.append(annotationView)
290 | let isSaved = PJCoreDataHelper.shared.addAnnotation(model: annotationModel)
291 | return isSaved
292 | }
293 |
294 |
295 | // MARK:delegate
296 | func homeMapAnnotationView(annotationView: PJHomeMapAnnotationView,
297 | shareAnnotaion: MAAnnotation) {
298 |
299 | }
300 |
301 |
302 | func homeMapAnnotationView(annotationView: PJHomeMapAnnotationView,
303 | removeAnnotaion: MAAnnotation) {
304 | PJCoreDataHelper.shared.deleteAnnotation(model: annotationView.model!)
305 |
306 | UIView.animate(withDuration: 0.2, animations: {
307 | annotationView.y -= 15
308 | }) { (finished) in
309 | if finished {
310 | UIView.animate(withDuration: 0.2, animations: {
311 | annotationView.y += 20
312 | }, completion: { (finished) in
313 | if finished {
314 | UIView.animate(withDuration: 0.25, animations: {
315 | annotationView.y -= 5
316 | }, completion: { (finished) in
317 | if finished {
318 | UIView.animate(withDuration: 0.25, animations: {
319 | annotationView.alpha = 0
320 | }, completion: { (finished) in
321 | if finished {
322 | self.mapView.removeAnnotation(removeAnnotaion)
323 | var index = 0
324 | for annotation in self.annotationViews {
325 | if Double(annotation.model!.latitude) == removeAnnotaion.coordinate.latitude &&
326 | Double(annotation.model!.longitude) == removeAnnotaion.coordinate.longitude {
327 | self.annotationViews.remove(at: index)
328 | // 删除完要退出。😂
329 | return
330 | }
331 | index += 1
332 | }
333 | }
334 | })
335 | }
336 | })
337 | }
338 | })
339 | }
340 | }
341 | }
342 |
343 |
344 | func homeMapAnnotationViewTappedView(calloutView: PJHomeMapCalloutView,
345 | annotationView: PJHomeMapAnnotationView) {
346 | viewDelegate?.mapViewTappedCalloutView(self, annotationView: annotationView)
347 | }
348 |
349 |
350 | func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!,
351 | updatingLocation: Bool) {
352 | if !updatingLocation {
353 | viewDelegate?.mapView(mapView: self,
354 | rotateDegree: CGFloat(userLocation.heading.trueHeading) - mapView.rotationDegree)
355 | }
356 | }
357 |
358 |
359 | func onReGeocodeSearchDone(_ request: AMapReGeocodeSearchRequest!,
360 | response: AMapReGeocodeSearchResponse!) {
361 | if response.regeocode != nil {
362 | // 请求天气数据,如果是长按添加的大头针则不请求
363 | if !isLongPress {
364 | req.city = response.regeocode.addressComponent.city
365 | search?.aMapWeatherSearch(req)
366 | }
367 |
368 | let params: [String: String] = [
369 | "notifi_name": "city",
370 |
371 | "city": response.regeocode.addressComponent.city,
372 | "formatterAddress": response.regeocode.formattedAddress,
373 | "markerName": "home_map_makers_02",
374 | ]
375 | NotificationCenter.default.post(name: PJHomeMapView.PJNotificationName_annotation,
376 | object: nil,
377 | userInfo: params)
378 |
379 | print(response.regeocode.addressComponent.city)
380 | print(response.regeocode.addressComponent.citycode)
381 | }
382 | }
383 |
384 |
385 | func onWeatherSearchDone(_ request: AMapWeatherSearchRequest!,
386 | response: AMapWeatherSearchResponse!) {
387 | let environmentString = response.lives[0].temperature + "° " +
388 | response.lives[0].windDirection + "风" +
389 | response.lives[0].windPower + "级 " +
390 | response.lives[0].humidity + "%rh"
391 |
392 | let timeFormatter = DateFormatter()
393 | timeFormatter.dateFormat = "yyyy/MM/dd HH:mm"
394 |
395 |
396 | let params: [String: String] = [
397 | "notifi_name": "weather",
398 |
399 | "createdTimeString": timeFormatter.string(from: Date()) as String + " 来过",
400 | "weatherString": response.lives[0].weather,
401 | "environmentString": environmentString,
402 | "latitude": String(Double((currentAnnotation?.coordinate.latitude)!)),
403 | "longitude": String(Double((currentAnnotation?.coordinate.longitude)!)),
404 | "altitude": String(Int(mapView.userLocation.location.altitude))
405 | ]
406 | NotificationCenter.default.post(name: PJHomeMapView.PJNotificationName_annotation,
407 | object: nil,
408 | userInfo: params)
409 | }
410 |
411 |
412 | func mapView(_ mapView: MAMapView!, mapDidZoomByUser wasUserAction: Bool) {
413 |
414 | func changeAnnotation() {
415 | let annotationSet = mapView.annotations(in: mapView.visibleMapRect).filter { (item) in
416 | !(item is MAUserLocation) } as! Set
417 |
418 | mapView.removeAnnotations(Array(annotationSet))
419 |
420 | for annotation in annotationSet {
421 | let pointAnnotation = MAPointAnnotation()
422 | pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: annotation.coordinate.latitude,
423 | longitude: annotation.coordinate.longitude)
424 | mapView.addAnnotation(pointAnnotation)
425 | }
426 | }
427 |
428 | if mapView.zoomLevel <= 12.8 {
429 | if isSmallZoom == false {
430 | isSmallZoom = true
431 | isBigZoom = false
432 |
433 | changeAnnotation()
434 | }
435 | } else {
436 | if isBigZoom == false {
437 | isBigZoom = true
438 | isSmallZoom = false
439 |
440 | changeAnnotation()
441 | }
442 | }
443 | }
444 |
445 |
446 | func mapView(_ mapView: MAMapView!, mapDidMoveByUser wasUserAction: Bool) {
447 | guard annotationViews.count != 0 else {
448 | return
449 | }
450 |
451 | let annotationArray = Array(mapView.annotations(in: mapView.visibleMapRect).filter { (item) in
452 | !(item is MAUserLocation) } as! Set)
453 |
454 | let screenAnntationView = annotationViews.filter { (item) in
455 | for annotation in annotationArray {
456 | if annotation.coordinate.latitude == Double(item.model!.latitude) &&
457 | annotation.coordinate.longitude == Double(item.model!.longitude) {
458 | return true
459 | }
460 | }
461 | return false
462 | }
463 |
464 |
465 | for annotationView in screenAnntationView {
466 | if mapView.zoomLevel < 12.8 {
467 | annotationView.image = UIImage(named: annotationView.model!.markerName)
468 | } else {
469 | annotationView.image = UIImage(named: annotationView.model!.markerName + "_b")
470 | }
471 | }
472 | }
473 |
474 |
475 | func mapView(_ mapView: MAMapView!, didLongPressedAt coordinate: CLLocationCoordinate2D) {
476 | isLongPress = true
477 | viewDelegate?.mapView(mapView: self, didLongPressCoordinate: coordinate)
478 | }
479 |
480 |
481 | func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
482 | print("Error:\(error)")
483 | }
484 |
485 |
486 | func mapInitComplete(_ mapView: MAMapView!) {
487 | viewDelegate?.mapViewInitComplate(self)
488 | }
489 |
490 |
491 | }
492 |
--------------------------------------------------------------------------------
/PFollow/Page/Home/view/bottomView/PJHomeBottomView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJHomeBottomView.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol PJHomeBottomViewDelegate: class {
12 | func homeBottomViewPlacesBtnClick(view: PJHomeBottomView)
13 | func homeBottomViewTapBtnClick(view: PJHomeBottomView, tapBtn: UIButton)
14 | }
15 | extension PJHomeBottomViewDelegate {
16 | func homeBottomViewPlacesBtnClick(view: PJHomeBottomView) {}
17 | func homeBottomViewTapBtnClick(view: PJHomeBottomView, tapBtn: UIButton) {}
18 | }
19 |
20 | class PJHomeBottomView: UIView {
21 |
22 | weak var viewDelegate: PJHomeBottomViewDelegate?
23 | var rotateDegree:CGFloat{
24 | set {
25 | self.compassImageView.transform = CGAffineTransform(rotationAngle: newValue * .pi / 180.0)
26 | }
27 | get {
28 | return self.rotateDegree
29 | }
30 | }
31 |
32 | var isRequest: Bool {
33 | willSet(b) {
34 | willSetIsRequest(b)
35 | }
36 | }
37 |
38 | private(set) var tapBtn = UIButton()
39 | private(set) var addAnnotationOKImageView = UIImageView()
40 |
41 | private var compassImageView = UIImageView()
42 | private var indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
43 |
44 | // MARK: life cycle
45 | override init(frame: CGRect) {
46 | isRequest = false
47 | super.init(frame: frame)
48 | initView()
49 | }
50 |
51 |
52 | required init?(coder aDecoder: NSCoder) {
53 | isRequest = false
54 | super.init(coder: aDecoder)
55 | }
56 |
57 |
58 | private func initView() {
59 | let backView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: 160))
60 | addSubview(backView)
61 | backView.isUserInteractionEnabled = true
62 | backView.image = UIImage(named: "home_cloud")
63 |
64 | let tapped = UITapGestureRecognizer(target: self, action: #selector(placesBtnClick))
65 | backView.addGestureRecognizer(tapped)
66 |
67 | tapBtn.width = 70
68 | tapBtn.height = 70
69 | // 0.1 为 cloud 的放大偏移量
70 | tapBtn.centerX = self.centerX + PJSCREEN_WIDTH * 0.1
71 | tapBtn.y = (height - 70) / 2
72 | tapBtn.layer.shadowColor = UIColor.black.cgColor
73 | tapBtn.layer.shadowRadius = 5
74 | tapBtn.layer.shadowOpacity = 0.3
75 | tapBtn.layer.shadowOffset = CGSize(width: 0, height: 2)
76 | tapBtn.setImage(UIImage(named: "home_tap"), for: .normal)
77 | tapBtn.addTarget(self, action: #selector(tapBtnClick(sender:)), for: .touchUpInside)
78 | addSubview(tapBtn)
79 |
80 | compassImageView.width = 30
81 | compassImageView.height = 30
82 | compassImageView.center = tapBtn.center
83 | compassImageView.image = UIImage(named: "home_bottom_compass")
84 | addSubview(compassImageView)
85 |
86 | addAnnotationOKImageView.width = 30
87 | addAnnotationOKImageView.height = 30
88 | addAnnotationOKImageView.center = tapBtn.center
89 | addAnnotationOKImageView.image = UIImage(named: "home_tap_ok")
90 | addSubview(addAnnotationOKImageView)
91 | addAnnotationOKImageView.isHidden = true
92 | addAnnotationOKImageView.alpha = 0
93 |
94 | indicator.width = 30
95 | indicator.height = 30
96 | indicator.center = tapBtn.center
97 | addSubview(indicator)
98 | indicator.isHidden = true
99 | }
100 |
101 |
102 | // MARK: Action
103 | @objc private func tapBtnClick(sender: UIButton) {
104 | print("tap")
105 | viewDelegate?.homeBottomViewTapBtnClick(view: self, tapBtn: sender)
106 | }
107 |
108 | @objc private func placesBtnClick() {
109 | print("places")
110 | viewDelegate?.homeBottomViewPlacesBtnClick(view: self)
111 | }
112 |
113 | @objc private func friendBtnClick() {
114 | print("friend")
115 | }
116 |
117 |
118 | private func willSetIsRequest(_ b: Bool) {
119 | if b {
120 | tapBtn.isEnabled = false
121 | compassImageView.isHidden = true
122 | indicator.isHidden = false
123 | indicator.startAnimating()
124 | } else {
125 | indicator.isHidden = true
126 | indicator.stopAnimating()
127 | addAnnotationOKImageView.isHidden = false
128 | UIView.animate(withDuration: 0.25, animations: {
129 | self.addAnnotationOKImageView.alpha = 1.0
130 | self.addAnnotationOKImageView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
131 | PJTapic.tap()
132 | }) { (finished) in
133 | self.addAnnotationOKImageView.transform = CGAffineTransform(scaleX: 1, y: 1)
134 | PJTapic.tipsTap()
135 |
136 | UIView.animate(withDuration: 0.25, delay: 0.5, options: .curveEaseIn , animations: {
137 | self.addAnnotationOKImageView.alpha = 0
138 | }, completion: { (finished) in
139 | if finished {
140 | self.addAnnotationOKImageView.isHidden = true
141 | self.compassImageView.isHidden = false
142 | self.tapBtn.isEnabled = true
143 | }
144 | })
145 | }
146 | }
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/PFollow/Page/InfoFlow/controller/Details/Controller/PJAnnotationDetailsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJAnnotationDetailsViewController.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/19.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PJAnnotationDetailsViewController: PJBaseViewController, UIScrollViewDelegate, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, PJDatePickerViewDelegate {
12 |
13 | var annotationView: PJHomeMapAnnotationView?
14 | var isHiddenRightBarButton: Bool?
15 |
16 | private var environmentLabel: UILabel?
17 | private var healthLabel: UILabel?
18 | private var locationLabel: UILabel?
19 | private var envImageView: UIImageView?
20 | private var heaImageView: UIImageView?
21 | private var contentTextView: UITextView?
22 | private var addTimeButton: UIButton?
23 |
24 | private var photoContentView: UIView?
25 | private var addPhotoButton: UIButton?
26 | private var contentTextViewTipsLabel: UILabel?
27 | private var backScrollView: UIScrollView?
28 | private var newPhotoImage: UIImage?
29 |
30 | private var contentTextViewLeftPadding: CGFloat?
31 |
32 | private var previousContentText: String?
33 | private var updateTimeString: String?
34 |
35 |
36 |
37 | // MARK: - life cycle
38 | override func viewDidLoad() {
39 | super.viewDidLoad()
40 |
41 | leftBarButtonItemAction(action: #selector(leftBarButtonTapped))
42 | view.backgroundColor = PJRGB(r: 31, g: 31, b: 31)
43 |
44 | initView()
45 | initData()
46 | }
47 |
48 | override func didReceiveMemoryWarning() {
49 | super.didReceiveMemoryWarning()
50 | }
51 |
52 |
53 | fileprivate func initView() {
54 | backScrollView = UIScrollView(frame: CGRect(x: 0, y: headerView!.bottom,
55 | width: view.width, height: view.height))
56 | backScrollView?.delegate = self
57 | backScrollView?.showsVerticalScrollIndicator = false
58 | view.addSubview(backScrollView!)
59 |
60 |
61 | locationLabel = UILabel(frame: CGRect(x: 10, y: 0,
62 | width: view.width - 20, height: navBarHeigt!))
63 | locationLabel?.font = UIFont.boldSystemFont(ofSize: 22)
64 | locationLabel?.textColor = .white
65 | locationLabel?.numberOfLines = 2
66 | backScrollView?.addSubview(locationLabel!)
67 |
68 |
69 | envImageView = UIImageView(frame: CGRect(x: 10, y: locationLabel!.bottom + 20,
70 | width:15, height: 20))
71 | backScrollView?.addSubview(envImageView!)
72 | envImageView?.image = UIImage(named: "annotation_details_env")
73 |
74 |
75 | environmentLabel = UILabel(frame: CGRect(x: 35, y: envImageView!.top,
76 | width: view.width - 20, height: 20))
77 | environmentLabel?.textColor = .white
78 | environmentLabel?.font = UIFont.boldSystemFont(ofSize: 15)
79 | backScrollView?.addSubview(environmentLabel!)
80 |
81 |
82 | heaImageView = UIImageView(frame: CGRect(x: 10, y: envImageView!.bottom + 10,
83 | width: 17.5, height: 20))
84 | backScrollView?.addSubview(heaImageView!)
85 | heaImageView?.image = UIImage(named: "annotation_details_altitude")
86 |
87 |
88 | healthLabel = UILabel(frame: CGRect(x: 35, y: heaImageView!.top,
89 | width: view.width - 20, height: 20))
90 | healthLabel?.textColor = .white
91 | healthLabel?.font = UIFont.boldSystemFont(ofSize: 15)
92 | backScrollView?.addSubview(healthLabel!)
93 |
94 |
95 | contentTextView = UITextView(frame: CGRect(x: 10, y: heaImageView!.bottom + 30,
96 | width: view.width - 20, height: 200))
97 | backScrollView?.addSubview(contentTextView!)
98 | contentTextView?.delegate = self
99 | contentTextView?.backgroundColor = PJRGB(r: 50, g: 50, b: 50)
100 | contentTextView?.tintColor = .white
101 | contentTextView?.layer.cornerRadius = 8
102 | contentTextView?.font = UIFont.systemFont(ofSize: 20, weight: .light)
103 | contentTextView?.textColor = .white
104 | contentTextView?.layer.masksToBounds = true
105 |
106 |
107 | contentTextViewLeftPadding = contentTextView!.textContainer.lineFragmentPadding
108 |
109 |
110 | contentTextViewTipsLabel = UILabel(frame: CGRect(x: 5, y: 10,
111 | width: contentTextView!.width, height: 20))
112 | contentTextView?.addSubview(contentTextViewTipsLabel!)
113 | contentTextViewTipsLabel?.font = contentTextView!.font
114 | contentTextViewTipsLabel?.textColor = contentTextView!.textColor
115 |
116 |
117 | photoContentView = UIView(frame: CGRect(x: contentTextView!.left,
118 | y: contentTextView!.bottom + 20,
119 | width: contentTextView!.width,
120 | height: 100))
121 | photoContentView?.backgroundColor = contentTextView!.backgroundColor
122 | backScrollView?.addSubview(photoContentView!)
123 | photoContentView?.layer.cornerRadius = 8
124 | photoContentView?.layer.masksToBounds = true
125 |
126 |
127 | addPhotoButton = UIButton(frame: CGRect(x: 0, y: 0,
128 | width: 200, height: 80))
129 | photoContentView?.addSubview(addPhotoButton!)
130 | addPhotoButton?.addTarget(self,
131 | action: #selector(addPhotoButtonTapped),
132 | for: .touchUpInside)
133 | addPhotoButton?.centerX = view.centerX - 10
134 | addPhotoButton?.top = (photoContentView!.height - 80) / 2
135 | addPhotoButton?.setTitleColor(.white, for: .normal)
136 | addPhotoButton?.titleLabel?.font = UIFont.systemFont(ofSize: 15)
137 | addPhotoButton?.setTitle("点击添加照片", for: .normal)
138 |
139 |
140 | addTimeButton = UIButton(frame: CGRect(x: photoContentView!.right - 30,
141 | y: photoContentView!.bottom - headerView!.height - PJStatusHeight,
142 | width: 30, height: 30))
143 | backScrollView?.addSubview(addTimeButton!)
144 | addTimeButton?.addTarget(self,
145 | action: #selector(showSelectTimeList),
146 | for: .touchUpInside)
147 | addTimeButton?.setImage(UIImage(named: "annotation_details_addTime"),
148 | for: .normal)
149 |
150 | }
151 |
152 | private func initData() {
153 | title = annotationView?.model?.createdTimeString
154 | locationLabel?.text = annotationView?.model?.formatterAddress
155 |
156 | if annotationView!.model!.createdTimeString.contains("/") {
157 | addTimeButton?.isHidden = true
158 | } else {
159 | addTimeButton?.isHidden = false
160 | }
161 |
162 | if let photoImage = PJCoreDataHelper.shared.annotationImage(model: annotationView!.model!) {
163 | clipNewPhotoImage(photoImage)
164 | newPhotoImage = photoImage
165 | } else {
166 | if isHiddenRightBarButton! {
167 | photoContentView?.removeFromSuperview()
168 | }
169 | }
170 |
171 | // MARK: - coreData
172 | let content = PJCoreDataHelper.shared.annotationContent(model: annotationView!.model!)
173 | if content == "" {
174 | if isHiddenRightBarButton! {
175 | contentTextView?.isHidden = true
176 | } else {
177 | contentTextViewTipsLabel?.isHidden = false
178 | contentTextViewTipsLabel?.text = "快来填写签到内容吧~"
179 | }
180 |
181 | updateBackScrollViewContentSize()
182 | } else {
183 | if isHiddenRightBarButton! {
184 | contentTextView?.isEditable = false
185 | }
186 | contentTextViewTipsLabel?.isHidden = true
187 | contentTextView?.text = content
188 | previousContentText = content
189 |
190 | updateView(showTips: false)
191 | }
192 |
193 | // MARK: update frame
194 | if annotationView?.model?.environmentString == "-" {
195 | environmentLabel?.isHidden = true
196 | healthLabel?.isHidden = true
197 | envImageView?.isHidden = true
198 | heaImageView?.isHidden = true
199 |
200 | contentTextView?.top = locationLabel!.bottom + 10
201 | photoContentView?.top = contentTextView!.bottom + 10
202 | } else {
203 | environmentLabel?.text = annotationView?.model?.environmentString
204 | healthLabel?.text = "海拔:" + annotationView!.model!.altitude + "米 步数:" + annotationView!.model!.stepCount
205 | }
206 | }
207 |
208 |
209 | // MARK: - Action
210 | @objc private func showSelectTimeList() {
211 | datePickerView.isHidden = false
212 | UIView.animate(withDuration: 0.25, animations: {
213 | self.datePickerView.bottom = self.view.height
214 | }) { (finished) in
215 | PJTapic.tap()
216 | }
217 | }
218 |
219 |
220 | @objc private func leftBarButtonTapped() {
221 | if title!.contains("/") {
222 | annotationView?.model?.createdTimeString = title!
223 | NotificationCenter.default.post(name: NSNotification.Name(rawValue: PJNotificationName_updateCallouView),
224 | object: nil,
225 | userInfo: [
226 | "time": title!,
227 | ])
228 | }
229 | navigationController?.popViewController(animated: true)
230 | }
231 |
232 |
233 | @objc private func rightButtonTapped() {
234 | var isCanSave = 0
235 |
236 | if contentTextView?.text != "" {
237 | isCanSave += 1
238 | }
239 |
240 | if newPhotoImage != nil {
241 | isCanSave += 1
242 | }
243 |
244 | if isCanSave < 1 {
245 | print("签到内容和照片必须选一个哦~")
246 | PJTapic.error()
247 | return
248 | }
249 |
250 |
251 | var isUpdateTime = true
252 | var isSaved = true
253 | var isPhotoImage = true
254 |
255 |
256 | // TODO: 做下提示
257 | if title!.contains("/") {
258 | let formatString = "longitude=\(annotationView!.model!.longitude) and latitude=\(annotationView!.model!.latitude)"
259 | isUpdateTime = PJCoreDataHelper.shared.updateAnnotation(formatString: formatString, updateTime: title!)
260 | }
261 |
262 |
263 |
264 | isSaved = PJCoreDataHelper.shared.addAnnotationContent(content: contentTextView!.text, model: annotationView!.model!)
265 |
266 | if newPhotoImage != nil {
267 | isPhotoImage = PJCoreDataHelper.shared.addAnnotationPhoto(photoImage: newPhotoImage!,
268 | model: annotationView!.model!)
269 | }
270 |
271 |
272 | if isPhotoImage && isSaved && isUpdateTime {
273 | PJTapic.succee()
274 | leftBarButtonTapped()
275 | } else {
276 | PJTapic.error()
277 | }
278 | }
279 |
280 |
281 | @objc private func addPhotoButtonTapped() {
282 | PJTapic.tap()
283 |
284 | let actionSheet = UIAlertController.init(title: "选择照片来源", message: "从相册选择或者相机拍摄一张照片吧~", preferredStyle: .actionSheet)
285 |
286 | let photoAlbumAction = UIAlertAction(title: "相册", style: .default) { (action) in
287 | self.initPhotoPicker()
288 | }
289 |
290 | let cameraAction = UIAlertAction(title: "相机", style: .default) { (action) in
291 | self.initCameraPicker()
292 | }
293 |
294 | let cancleAction = UIAlertAction(title: "取消", style: .cancel) { (action) in
295 | actionSheet.dismiss(animated: true)
296 | }
297 |
298 | actionSheet.addAction(photoAlbumAction)
299 | actionSheet.addAction(cameraAction)
300 | actionSheet.addAction(cancleAction)
301 |
302 | present(actionSheet, animated: true)
303 |
304 | }
305 |
306 |
307 | private func initPhotoPicker() {
308 | let photoPicker = UIImagePickerController()
309 | photoPicker.delegate = self
310 | photoPicker.sourceType = .photoLibrary
311 | present(photoPicker, animated: true)
312 | }
313 |
314 |
315 | private func initCameraPicker() {
316 | if UIImagePickerController.isSourceTypeAvailable(.camera) {
317 | let cameraPicker = UIImagePickerController()
318 | cameraPicker.delegate = self
319 | cameraPicker.sourceType = .camera
320 | present(cameraPicker, animated: true)
321 | } else {
322 | // TODO: 不支持拍照
323 | }
324 | }
325 |
326 |
327 | @objc func image(image:UIImage,
328 | didFinishSavingWithError error:NSError?,
329 | contextInfo:AnyObject) {
330 | if error != nil {
331 | print("保存失败")
332 | } else {
333 | clipNewPhotoImage(image)
334 | print("保存成功")
335 | }
336 | }
337 |
338 |
339 | private func updateBackScrollViewContentSize() {
340 | if annotationView!.model!.createdTimeString.contains("/") {
341 | backScrollView?.contentSize = CGSize(width: 0,
342 | height: photoContentView!.bottom + 10 + headerView!.height)
343 | } else {
344 | backScrollView?.contentSize = CGSize(width: 0,
345 | height: addTimeButton!.bottom + 10 + headerView!.height)
346 | }
347 |
348 | if backScrollView!.contentSize.height < view.height {
349 | backScrollView?.contentSize = CGSize(width: 0,
350 | height: view.height + 1)
351 | }
352 | }
353 |
354 |
355 | func clipNewPhotoImage(_ photoImage:UIImage) {
356 | addPhotoButton?.isHidden = true
357 |
358 | let photoImageSize = photoImage.size
359 | let radio = photoImageSize.width / photoImageSize.height
360 | let photoImageView = UIImageView(frame: CGRect(x: 5, y: 5,
361 | width: photoContentView!.width - 10,
362 | height: photoContentView!.width / radio))
363 | photoImageView.image = photoImage
364 | photoContentView?.height = photoImageView.height + 10
365 | photoImageView.layer.cornerRadius = 8
366 | photoImageView.layer.masksToBounds = true
367 |
368 | newPhotoImage = photoImage
369 | photoContentView?.addSubview(photoImageView)
370 |
371 | addTimeButton?.top = photoContentView!.bottom + 10
372 |
373 | updateBackScrollViewContentSize()
374 | }
375 |
376 |
377 | private func updateView(showTips: Bool) {
378 | if showTips {
379 | UIView.animate(withDuration: 0.25, animations: {
380 | self.contentTextView?.height = 200
381 | }) { (finished) in
382 | if finished {
383 | UIView.animate(withDuration: 0.25, animations: {
384 | self.photoContentView?.top = self.contentTextView!.bottom + 20
385 | self.addTimeButton?.top = self.photoContentView!.bottom + 10
386 | }, completion: { (finished) in
387 | if finished {
388 | PJTapic.tap()
389 |
390 | self.updateBackScrollViewContentSize()
391 | }
392 | })
393 | }
394 | }
395 | } else {
396 | let textSize = contentTextView!.attributedText.boundingRect(with: CGSize(width: contentTextView!.width - 2 * contentTextViewLeftPadding!, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
397 |
398 | UIView.animate(withDuration: 0.25, animations: {
399 | self.contentTextView?.height = textSize.size.height + self.contentTextViewLeftPadding! * 3.5
400 | }) { (finished) in
401 | if finished {
402 | UIView.animate(withDuration: 0.25, animations: {
403 | self.photoContentView?.top = self.contentTextView!.bottom + 20
404 | self.addTimeButton?.top = self.photoContentView!.bottom + 10
405 | }, completion: { (finished) in
406 | if finished {
407 | PJTapic.tap()
408 |
409 | self.updateBackScrollViewContentSize()
410 | }
411 | })
412 | }
413 | }
414 | }
415 | }
416 |
417 |
418 | func changeDatePickerViewStuts() {
419 | if datePickerView.bottom == view.height {
420 | UIView.animate(withDuration: 0.25,
421 | delay: 0,
422 | options: .curveEaseOut,
423 | animations: {
424 | self.datePickerView.top = self.view.height
425 | }, completion: nil)
426 | } else {
427 | UIView.animate(withDuration: 0.25,
428 | delay: 0,
429 | options: .curveEaseIn,
430 | animations: {
431 | self.datePickerView.bottom = self.view.height
432 | }, completion: nil)
433 | }
434 | }
435 |
436 |
437 | // MARK: - Delegate
438 | func textViewDidEndEditing(_ textView: UITextView) {
439 | guard textView.text != "" else {
440 | return
441 | }
442 | updateView(showTips: false)
443 | }
444 |
445 |
446 | func textViewDidChange(_ textView: UITextView) {
447 | guard textView.text != "" else {
448 | contentTextViewTipsLabel?.isHidden = false
449 | updateView(showTips: true)
450 | return
451 | }
452 | contentTextViewTipsLabel?.isHidden = true
453 | }
454 |
455 |
456 | func imagePickerController(_ picker: UIImagePickerController,
457 | didFinishPickingMediaWithInfo info: [String : Any]) {
458 | let image: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
459 | if picker.sourceType == .camera {
460 | UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(image:didFinishSavingWithError:contextInfo:)), nil)
461 | }
462 |
463 | if picker.sourceType == .photoLibrary {
464 | clipNewPhotoImage(image)
465 | }
466 |
467 | dismiss(animated: true, completion: nil)
468 | }
469 |
470 |
471 | func PJDatePickerViewOkButtonTapped(_ dateString: String) {
472 | changeDatePickerViewStuts()
473 | title = dateString
474 | }
475 |
476 |
477 | func PJDatePickerViewCloseButtonTapped() {
478 | changeDatePickerViewStuts()
479 | }
480 |
481 |
482 | // MARK: - lazy load
483 | lazy var datePickerView: PJDatePickerView = {
484 | let datePickerView = PJDatePickerView.newInstance()
485 | datePickerView?.height = 250
486 | datePickerView?.isHidden = true
487 | datePickerView?.top = view.height
488 | datePickerView?.viewDelegate = self
489 | PJInsertRoundingCorners(datePickerView!)
490 |
491 | view.addSubview(datePickerView!)
492 | return datePickerView!
493 | }()
494 | }
495 |
--------------------------------------------------------------------------------
/PFollow/Page/InfoFlow/controller/Details/View/PJDatePickerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJDatePickerView.swift
3 | // PFollow
4 | //
5 | // Created by PJHubs on 2018/9/4.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | protocol PJDatePickerViewDelegate {
13 | func PJDatePickerViewCloseButtonTapped()
14 | func PJDatePickerViewOkButtonTapped(_ dateString: String)
15 | }
16 | extension PJDatePickerViewDelegate {
17 | func PJDatePickerViewCloseButtonTapped() {}
18 | func PJDatePickerViewOkButtonTapped(_ dateString: String) {}
19 | }
20 |
21 |
22 | class PJDatePickerView: UIView {
23 |
24 | @IBOutlet weak private var datePickerView: UIDatePicker!
25 | @IBOutlet weak private var closeButton: UIButton!
26 | @IBOutlet weak private var okButton: UIButton!
27 |
28 | var viewDelegate: PJDatePickerViewDelegate?
29 |
30 |
31 | // MARK: Instance
32 | class func newInstance() -> PJDatePickerView? {
33 | let nib = Bundle.main.loadNibNamed("PJDatePickerView", owner: nil, options: nil)
34 | if let view = nib?.first as? PJDatePickerView {
35 | return view
36 | }
37 | return nil
38 | }
39 |
40 |
41 | override func awakeFromNib() {
42 | // datePickerView.maximumDate = Date()
43 | // datePickerView.minimumDate = DateFormatter().date(from: "1920-01-01")
44 | super.awakeFromNib()
45 | }
46 |
47 |
48 | @IBAction func closeButtonTapped(_ sender: UIButton) {
49 | viewDelegate?.PJDatePickerViewCloseButtonTapped()
50 | }
51 |
52 |
53 | @IBAction func okButtonTapped(_ sender: UIButton) {
54 | let timeFormatter = DateFormatter()
55 | timeFormatter.dateFormat = "yyyy/MM/dd"
56 | let dateString = timeFormatter.string(from: datePickerView.date) + " 来过"
57 | viewDelegate?.PJDatePickerViewOkButtonTapped(dateString)
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/PFollow/Page/InfoFlow/controller/Details/View/PJDatePickerView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
36 |
45 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/PFollow/Page/InfoFlow/controller/Flow/PJInfoFlowViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJInfoFlowViewController.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/18.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PJInfoFlowViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | // Do any additional setup after loading the view.
17 | }
18 |
19 | override func didReceiveMemoryWarning() {
20 | super.didReceiveMemoryWarning()
21 | // Dispose of any resources that can be recreated.
22 | }
23 |
24 |
25 | /*
26 | // MARK: - Navigation
27 |
28 | // In a storyboard-based application, you will often want to do a little preparation before navigation
29 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
30 | // Get the new view controller using segue.destinationViewController.
31 | // Pass the selected object to the new view controller.
32 | }
33 | */
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/PFollow/Page/Places/Controller/PJPlacesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJPlacesViewController.swift
3 | // PFollow
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SpriteKit
11 |
12 | class PJPlacesViewController: PJBaseViewController {
13 |
14 |
15 | var annotationModels: [AnnotationModel]?
16 |
17 | private var topView: UIImageView?
18 | private var animator: UIDynamicAnimator?
19 | private var titleLabel: UILabel?
20 | private var skView: SKView?
21 | private var currentModel: AnnotationModel?
22 |
23 |
24 | // MARK: - life cycle
25 | override func viewWillAppear(_ animated: Bool) {
26 | super.viewWillAppear(animated)
27 | self.becomeFirstResponder()
28 | }
29 |
30 |
31 | override func viewWillDisappear(_ animated: Bool) {
32 | super.viewWillDisappear(animated)
33 | self.resignFirstResponder()
34 | }
35 |
36 |
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 |
40 | initView()
41 | initScene()
42 | }
43 |
44 | override func didReceiveMemoryWarning() {
45 | super.didReceiveMemoryWarning()
46 | }
47 |
48 |
49 | private func initScene() {
50 | skView = SKView(frame: CGRect(x: 0, y: topView!.bottom,
51 | width: view.width, height: view.height - topView!.bottom))
52 | view.addSubview(skView!)
53 |
54 | let scene = PJPlacesAnnotationScene(size: skView!.frame.size)
55 | scene.scaleMode = .aspectFill
56 | scene.annotationModels = annotationModels
57 | skView?.presentScene(scene)
58 |
59 | skView?.ignoresSiblingOrder = true
60 | // scnView.showsPhysics = true
61 | // skView?.showsFPS = true
62 | // skView?.showsNodeCount = true
63 |
64 |
65 | let skViewButton = UIButton(frame: CGRect(x: skView!.x, y: skView!.y,
66 | width: skView!.width,
67 | height: skView!.height))
68 | skViewButton.addTarget(self,
69 | action: #selector(bottleViewTapped),
70 | for: .touchUpInside)
71 | view.addSubview(skViewButton)
72 | }
73 |
74 |
75 | private func initView() {
76 | view.backgroundColor = PJRGB(r: 11, g: 11, b: 11)
77 | headerView?.backgroundColor = .white
78 | UIApplication.shared.statusBarStyle = .default
79 |
80 | topView = UIImageView(frame: CGRect(x: -PJSCREEN_WIDTH * 0.1, y: -80 + PJStatusHeight,
81 | width: PJSCREEN_WIDTH * 1.2, height: 160))
82 | let tap = UITapGestureRecognizer(target: self,
83 | action: #selector(backViewTapGestureClick))
84 | topView?.addGestureRecognizer(tap)
85 | tap.numberOfTouchesRequired = 1
86 | topView?.isUserInteractionEnabled = true
87 | view.addSubview(topView!)
88 | topView?.image = UIImage(named: "home_cloud")
89 |
90 |
91 | titleLabel = UILabel(frame: CGRect(x: 0, y: -PJStatusHeight,
92 | width: view.width, height: 100))
93 | if iPhoneX {
94 | titleLabel?.y = 10
95 | }
96 | view.addSubview(titleLabel!)
97 | titleLabel?.numberOfLines = 2
98 | titleLabel?.textAlignment = .center
99 | titleLabel?.text = ""
100 | titleLabel?.font = UIFont.systemFont(ofSize: 22,
101 | weight: .light)
102 | }
103 |
104 |
105 |
106 | // MARK: - Action
107 | @objc private func backViewTapGestureClick() {
108 | self.dismiss(animated: true, completion: nil)
109 | }
110 |
111 |
112 | @objc private func bottleViewTapped() {
113 | if titleLabel?.text != "" {
114 | let annotationView = PJHomeMapAnnotationView(annotation: nil,
115 | reuseIdentifier: nil)
116 | annotationView?.model = currentModel
117 | let vc = PJAnnotationDetailsViewController()
118 | vc.annotationView = annotationView
119 | vc.isHiddenRightBarButton = true
120 | navigationController?.pushViewController(vc, animated: true)
121 | }
122 | }
123 |
124 |
125 | // MARK: - delegate
126 | override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
127 | if event?.subtype == UIEventSubtype.motionShake {
128 | guard annotationModels?.count != 0 else {
129 | return
130 | }
131 | currentModel = annotationModels![Int(arc4random_uniform(UInt32(annotationModels!.count)))]
132 | titleLabel?.text = currentModel?.formatterAddress
133 | PJTapic.succee()
134 | }
135 | }
136 |
137 |
138 | override var prefersStatusBarHidden: Bool {
139 | return true
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/PFollow/Page/Places/View/Scene/PJPlacesAnnotationScene.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PJAnnotationScene.swift
3 | // PFollow
4 | //
5 | // Created by PJHubs on 2018/9/5.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SpriteKit
11 | import CoreMotion
12 |
13 | import Schedule
14 |
15 |
16 | class PJPlacesAnnotationScene: SKScene {
17 |
18 | var annotationModels: [AnnotationModel]? {
19 | willSet(models) {
20 | willSetAnnotationModels(models!)
21 | }
22 | }
23 |
24 | private let motionManager = CMMotionManager() // 加速度计管理器
25 | private var bottleViwSprite: SKSpriteNode?
26 |
27 |
28 |
29 | // MARK: - life cycle
30 | override init(size: CGSize) {
31 | super.init(size: size)
32 |
33 | initView()
34 | }
35 |
36 |
37 | required init?(coder aDecoder: NSCoder) {
38 | super.init(coder: aDecoder)
39 | }
40 |
41 |
42 | private func initView() {
43 | self.backgroundColor = PJRGB(r: 11, g: 11, b: 11)
44 |
45 |
46 | bottleViwSprite = SKSpriteNode(imageNamed: "places_bgView")
47 | bottleViwSprite?.size = CGSize(width: self.size.width * 0.9, height: self.size.width / 0.656)
48 | bottleViwSprite?.position = CGPoint(x: self.size.width * 0.11,
49 | y: (size.height - bottleViwSprite!.size.height) / 2)
50 | bottleViwSprite?.anchorPoint = CGPoint(x: 0, y: 0)
51 | bottleViwSprite?.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: bottleViwSprite!.frame.origin.x * 0.45, y: bottleViwSprite!.size.height * 0.1, width: bottleViwSprite!.size.width * 0.75, height: bottleViwSprite!.size.height - bottleViwSprite!.size.height * 0.3))
52 | bottleViwSprite?.physicsBody?.density = 1000
53 | addChild(bottleViwSprite!)
54 |
55 |
56 | let leftBox = SKSpriteNode(imageNamed: "places_null")
57 | leftBox.size = CGSize(width: 50, height: 50)
58 | leftBox.position = CGPoint(x: bottleViwSprite!.frame.origin.x * 0.3, y: bottleViwSprite!.size.height * 0.8)
59 | leftBox.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
60 | leftBox.physicsBody?.isDynamic = false
61 | bottleViwSprite?.addChild(leftBox)
62 |
63 |
64 | let rightBox = SKSpriteNode(imageNamed: "places_null")
65 | rightBox.size = CGSize(width: 50, height: 50)
66 | let rightBoxRight = leftBox.frame.origin.x + leftBox.size.width
67 | rightBox.position = CGPoint(x: rightBoxRight + bottleViwSprite!.size.width * 0.7,
68 | y: bottleViwSprite!.size.height * 0.8)
69 | rightBox.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
70 | rightBox.physicsBody?.isDynamic = false
71 | bottleViwSprite?.addChild(rightBox)
72 |
73 |
74 | startMonitoringAcceleration()
75 | }
76 |
77 |
78 | // MARK: - 开启加速度计
79 | func startMonitoringAcceleration(){
80 | if motionManager.isAccelerometerAvailable {
81 | // 感应时间
82 | motionManager.accelerometerUpdateInterval = 0
83 | motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
84 | guard let accelerometerData = data else {
85 | return
86 | }
87 | let acceleration = accelerometerData.acceleration
88 | self.physicsWorld.gravity = CGVector(dx: acceleration.x * 9.8,
89 | dy: acceleration.y * 9.8)
90 | }
91 | }
92 | }
93 |
94 |
95 | private func willSetAnnotationModels(_ models: [AnnotationModel]) {
96 | for i in 0 ..< models.count {
97 | Schedule.after(Double(0.05 * Double(i)).second).do {
98 | DispatchQueue.main.async {
99 | let annotationSprite = SKSpriteNode(imageNamed: "home_map_makers_02")
100 | let randomX = self.bottleViwSprite!.size.width - self.bottleViwSprite!.frame.origin.x * 2 - 40
101 | let annotationX = CGFloat(arc4random_uniform(UInt32(randomX))) + self.bottleViwSprite!.frame.origin.x
102 | annotationSprite.position = CGPoint(x: annotationX, y: self.bottleViwSprite!.size.height * 0.8)
103 | annotationSprite.size = CGSize(width: 18, height: 18)
104 | annotationSprite.physicsBody = SKPhysicsBody(circleOfRadius: annotationSprite.size.height / 3)
105 | // 置于最底层
106 | annotationSprite.zPosition = -1
107 |
108 | self.bottleViwSprite?.addChild(annotationSprite)
109 | }
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/PFollow/mapView.data:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/PFollow/mapView.data
--------------------------------------------------------------------------------
/PFollowTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PFollowTests/PFollowTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PFollowTests.swift
3 | // PFollowTests
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import PFollow
11 |
12 | class PFollowTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/PFollowUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PFollowUITests/PFollowUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PFollowUITests.swift
3 | // PFollowUITests
4 | //
5 | // Created by pjpjpj on 2018/8/12.
6 | // Copyright © 2018年 pjpjpj. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class PFollowUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AMap3DMap (6.4.0):
3 | - AMapFoundation (~> 1.5)
4 | - AMapFoundation (1.5.4)
5 | - AMapLocation (2.6.1):
6 | - AMapFoundation (~> 1.4)
7 | - AMapSearch (6.1.1):
8 | - AMapFoundation (~> 1.4)
9 | - IQKeyboardManagerSwift (6.1.1)
10 | - Schedule (0.1.0)
11 |
12 | DEPENDENCIES:
13 | - AMap3DMap
14 | - AMapLocation
15 | - AMapSearch
16 | - IQKeyboardManagerSwift
17 | - Schedule
18 |
19 | SPEC REPOS:
20 | https://github.com/cocoapods/specs.git:
21 | - AMap3DMap
22 | - AMapFoundation
23 | - AMapLocation
24 | - AMapSearch
25 | - IQKeyboardManagerSwift
26 | - Schedule
27 |
28 | SPEC CHECKSUMS:
29 | AMap3DMap: ebfb4e202c2bee9c3a6c296264e29f12436b6379
30 | AMapFoundation: bff8688722e886feda4edd77f1443746ddd7e2e2
31 | AMapLocation: cf024b53dc03663efb4ea4bcce27d4cce58bb97a
32 | AMapSearch: 3dcbf85c403a2a0fe0eda5318caabc272b31f5e1
33 | IQKeyboardManagerSwift: 977affaeb4d6e971975c7790a6850f31d38f1207
34 | Schedule: 62cd2defb026a3607349b2a2b1bd8ec3fd12cccd
35 |
36 | PODFILE CHECKSUM: 9d2ccef08c058577579e43cdefb2bb103f76061f
37 |
38 | COCOAPODS: 1.5.3
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | ## 简介
6 | PFollow 为今年暑假新开的项目,期末考试完后和女票一同去了重庆青海西安十日游。在游玩的过程中,使用众多 app 协助旅行,在青海时,会经常到查看 iOS 自带的“指南针” app 看当前海拔。同时也因为在高原的天气变化多端,会非常注意第二天的天气等等这些习惯就被强制性的养成了。
7 |
8 | 旅行结束后,躺在宿舍床上慢慢回想这旅行的这段时间,很多回忆都留在了一张张照片上,虽然照片会带上当时拍摄时的一些地点及其它信息,相册也会自动识别并对照片进行归类,甚至还能自动归档生成一段回忆视频。
9 |
10 | 但是我总觉得还是不能很好的回忆起当时旅行中的一些美好的细节,因为往往会因为时间或者地点的因素被覆盖掉,却会在故地重游时再现。当时我脑海里就在想,如果我能够把游客此时所在地点配上文字和图片,形成一个个的“点”打在地图上,日后回想起这段旅程时,就可以顺着地图上的“点”,回忆起当初在这里发生的一些事情,这该是一件多么有趣的事情啊!
11 |
12 | 遂开干!
13 |
14 | ## 调研
15 | 我明确知道这种需求是一定被玩烂了的,就开始去 app store 中搜了一遍旅行类、记录类的 app,甚至也把知乎上关于“旅行记录/打卡”的相关问题都过了一遍,发现确实已经有产品在解决这些问题,总结出了以下几点:
16 |
17 | * 体验不佳;
18 | * 太丑;
19 | * 广告太多;
20 | * 忘了初心(名义上是旅行打卡,实质则为其它,例如:推销旅游产品)
21 | * 过于复杂;
22 | * 旅行打卡不是主要业务,入口太深
23 |
24 | 以上几点当然是都经过考虑的,有可能是因为单纯做“旅行打卡”工具类 app 难以存活;玩不出新花样;用户变现等等问题导致产品的方向发生了变化,都能理解。
25 |
26 | 但是,既然各个开发商都不愿意做这赔本事情,那为了满足个人需要就自己开干。
27 |
28 | ## 设计
29 | 在设计阶段花的时间不多,大概只用了前前后后合计不到四五天的时间就搞定了 1.0 的设计,因为其实自己在大一的时候就萌生出了做类似的旅游产品,很多地方可以直接用之前的设计和逻辑。
30 |
31 | 基本上把 app store 中“旅游”、“旅游打卡”、“旅行记录”等关键词下的 app 都使用并思考过了至少一遍,也结合了自己的使用习惯,使用 Sketch 设计出了一套符合个人习惯的 UI 。
32 |
33 | 但是非常遗憾,辛辛苦苦在咖啡厅调了一天,然后重装了一次系统偏偏就是忘了备份它!!!导致代码写到后边出的成果有些地方比较“怪异”。
34 |
35 | ## 实施
36 | 梳理了一遍 PFollow 中需要用到的知识,如下所示:
37 |
38 | * 自定义地图(高德、百度、MapKit)
39 | * GPS
40 | * 陀螺仪
41 | * 海拔
42 | * UI Dynamic
43 | * SpriteKit
44 | * CloudKit
45 | * CoreData
46 | * 数据库设计
47 | * UIKit
48 | * Tapic Engine
49 | * 读取相册
50 | * 相机
51 | * 其它
52 |
53 | 在这个项目中我对“自定义地图”、“UI Dynamic”、“Core Data”没有十足的把握,衡量了一下,可以不用停下目前正在做的事情把精力全部投入进行学习,因为我有个习惯,如果发现准备要做的事情超出了自己目前的知识储备,就会 all in 到学习这个事情中去,弄懂后再开始。
54 |
55 | 到最后我发现其实坑还是在 “Core Data” 这块,因为它跟我以往用过的、打着相同口号的 ORM 框架有很多不一样的地方,所以不光是思维的转换上需要斟酌斟酌,还有写法上也不太一样,需要熟悉一段时间。
56 |
57 | 不过好在到现在已经对 “Core Data” 有了一定的了解,并且也把习得的知识用在了实习公司的产品中,替换了大部分数据缓存策略。
58 |
59 | ## 展示
60 | ### 地图
61 |
62 |
63 | ### 缩放地图
64 |
65 |
66 | ### 放大地图
67 |
68 |
69 | ### 聚点详情
70 |
71 |
72 | ### 聚点瓶
73 |
74 |
75 |
76 | ## 上线计划
77 | 目前 PFollow 暂无上线计划,因为我在前段时间的一篇文章中了解到 Instagram 居然就是做“地点签到”起家的,后来因为各种原因而改变了产品方向,在当时我瞬间就明白了,Ins 一定是遇到了某些问题,这些问题会在 PFollow 上线后随着时间的流逝而暴露出来,我坚信!
78 |
79 | 因此,PFollow 我将会以开源项目的方式进行下去。
80 |
81 | ## 思考
82 | 在开发 PFollow 的过程中带给我最多的思考还是如何把自己的想法转换成实际一行行的代码,这其中会有许多的妥协和坚持,我们最终坚持下来的东西很有可能就是我们当时内心深处最真实的想法,妥协掉一些累赘。
83 |
84 | 当然 1.0 版本还有些许缺陷,很大一部分原因是因为开学了我要有其它的事情去做了,PFollow 算是在这个炎热的暑假中让我静心学习的好助手,让我重新调整了自己的状态迎接大学最后一年。
85 |
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/windstormeye/PFollow/d1f7abb9cba9fd35594fadbf68da5c51d078f603/banner.png
--------------------------------------------------------------------------------
/podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '11.0'
2 | target 'PFollow' do
3 |
4 | pod 'AMap3DMap' #3D地图 SDK
5 | pod 'AMapLocation' # 定位SDK
6 | pod 'AMapSearch' # 搜索功能 SDK
7 |
8 | pod 'IQKeyboardManagerSwift'
9 | pod 'Schedule'
10 |
11 | end
12 |
--------------------------------------------------------------------------------