Setting up a weather map
While the AWFWeatherMapViewController
class handles all of the setup necessary to get a fully-functional weather map up and running without any work, there may be times when you want more control over your own weather map.
This example includes the various phases of setting up a weather map in much of the same way as AWFWeatherMapViewController
. Depending on your own implementation, you may choose to only use parts of this setup.
The primary steps include:
- Ensure you've setup the SDK with your Xweather account access keys.
- Configure and create your
AWFWeatherMap
instance and assign itsdelegate
. - If desired, setup the
AWFTimelineView
(or alternative custom view) which will be used to show animation progress and allow the user to control playback of the animation. You must also set the timeline view'sdelegate
to receive time change events from the view. - Create a
toggleAnimation
method that will handle starting or stopping the animation based on the animation's current state. Set the timeline view's playback control action to call this method when tapped. - Setup the appropriate
AWFTimelineViewDelegate
methods to respond to time changes from the timeline view and update the weather map accordingly. - Setup the appropriate
AWFWeatherMapDelegate
methods to respond to animation state changes from the weather map and update the timeline view accordingly.
MapViewController.swift
class MapViewController: UIViewController {
var weatherMap: AWFWeatherMap!
var timelineView: AWFTimelineView!
override func viewDidLoad() {
super.viewDidLoad()
// setup the weather map config
let config = AWFWeatherMapConfig()
// make any changes to your configuration before creating the weather map instance...
// create the weather map instance
weatherMap = AWFWeatherMap(mapType: .apple, config: config)
weatherMap.delegate = self
view.addSubview(weatherMap.weatherMapView)
timelineView = AWFTimelineView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50.0))
timelineView.delegate = self
timelineView.startDate = weatherMap.timeline.fromTime
timelineView.endDate = weatherMap.timeline.toTime
timelineView.currentTime = weatherMap.timeline.fromTime
view.addSubview(timelineView)
// layout the map view container
weatherMap.weatherMapView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([weatherMap.weatherMapView.topAnchor.constraint(equalTo: view.topAnchor),
weatherMap.weatherMapView.leftAnchor.constraint(equalTo: view.leftAnchor),
weatherMap.weatherMapView.rightAnchor.constraint(equalTo: view.rightAnchor),
weatherMap.weatherMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
// layout the timeline view
let timelineHeight: CGFloat = 50.0
timelineView.translatesAutoresizingMaskIntoConstraints = false
timelineView.preservesSuperviewLayoutMargins = true
NSLayoutConstraint.activate([timelineView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -timelineHeight),
timelineView.leftAnchor.constraint(equalTo: view.leftAnchor),
timelineView.rightAnchor.constraint(equalTo: view.rightAnchor),
timelineView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
// add an action handler for the timeline view's playback control
timelineView.playButton.addTarget(self, action: #selector(toggleAnimation(sender:)), for: .touchUpInside)
// start the weather map at the current time
weatherMap.go(toTime: Date())
}
// MARK: Control Handlers
@objc func toggleAnimation(sender: Any) {
if let btn = sender as? UIButton {
if weatherMap.isAnimating || weatherMap.isLoadingAnimation {
btn.isSelected = false
weatherMap.stopAnimating()
} else {
btn.isSelected = true
weatherMap.startAnimating()
}
}
}
}
// Observe change events on the timelineView so the weather map can be updated accordingly, such as when the user pans
// the timeline or taps the "Now" control to go to the current time/date.
extension MapViewController: AWFTimelineViewDelegate {
func timelineView(_ timelineView: AWFTimelineView!, didPanTo date: Date!) {
if weatherMap.config.timelineScrubbingEnabled {
weatherMap.pauseAnimation()
weatherMap.go(toTime: date)
}
}
func timelineView(_ timelineView: AWFTimelineView!, didSelect date: Date!) {
weatherMap.stopAnimating()
weatherMap.go(toTime: date)
}
}
// Updates to the timelineView are handled by handling several AWFWeatherMapDelegate methods that notify our controller about changes to the weather map's
// timeline, such as start/end date changes and when the map begins or stops animating.
extension MapViewController: AWFWeatherMapDelegate {
func weatherMap(_ weatherMap: AWFWeatherMap, didUpdateTimelineRangeFrom fromDate: Date, to toDate: Date) {
timelineView.startDate = fromDate
timelineView.endDate = toDate
timelineView.currentTime = weatherMap.timeline.currentTime
}
func weatherMapDidStartAnimating(_ weatherMap: AWFWeatherMap) {
timelineView.playButton.isSelected = true
}
func weatherMapDidStopAnimating(_ weatherMap: AWFWeatherMap) {
timelineView.playButton.isSelected = false
}
func weatherMapDidResetAnimation(_ weatherMap: AWFWeatherMap) {
timelineView.setProgress(0, animated: true)
}
func weatherMap(_ weatherMap: AWFWeatherMap, animationDidUpdateTo date: Date) {
timelineView.currentTime = date
}
func weatherMapDidStartLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
timelineView.playButton.isSelected = true
timelineView.showLoading(true)
}
func weatherMapDidFinishLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
timelineView.setProgress(1.0, animated: true)
timelineView.showLoading(false)
}
func weatherMapDidCancelLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
timelineView.playButton.isSelected = false
timelineView.setProgress(0, animated: true)
timelineView.showLoading(false)
}
func weatherMap(_ weatherMap: AWFWeatherMap, didUpdateAnimationDataLoadingProgress totalLoaded: Int, total: Int) {
timelineView.setProgress(CGFloat(totalLoaded) / CGFloat(total), animated: true)
}
}