Ich benutze Swipe-Gesten zum Navigieren zwischen Tabs mit einem gefälschten UITabBarController, der 4 UIViewController-Unterklassen innerhalb eines UIScrollView hostet, mit UIPanGestureRecognizers auf jedem von ihnen, um Swipes zu erkennen und entsprechend Tabs zu wechseln. Der daraus resultierende Effekt ist die Kernnavigation, wie Sie sie auf Snapchat sehen. Einer dieser Bildschirme enthält jedoch eine Kartenansicht (Mapbox-Map), in die eigene Gestenerkenner integriert sind.Wie verwende ich 2 Gestenerkenner, um Ereignisse gleichzeitig zu empfangen?
Ich möchte, dass der Benutzer in der Lage ist, auf der Karte selbst zu wischen, um zu einem anderen Tab zu navigieren, indem er einen Streifzug vom rechten Rand des Bildschirms erkennt. Ich habe versucht, einen UIPanGestureRecognizer zu einem unsichtbaren UIView in diesem Bereich auf der rechten Seite hinzuzufügen, aber dies bietet einen ruckligen, nicht übereinstimmenden Tab-Schalter, und es fängt Berührungsereignisse von der Karte unten ab.
Wie kann ich beiden Gestenerkennern erlauben, Ereignisse gleichzeitig zu empfangen, oder einige Ereignisse filtern, die nur auf der Startposition des Swipe und seiner Entfernung und Richtung basieren?
-Code für swiping View-Controller:
class KUSwipeViewController: EZSwipeController {
fileprivate var fakeTabBar: UIView!
fileprivate var tabBarHeight: CGFloat = 50
override func viewDidLoad() {
initUI()
}
override func setupView() {
super.setupView()
datasource = self
navigationBarShouldNotExist = true
}
func initUI() {
fakeTabBar = UIView(frame: CGRect(x: 0, y: Screen.height - tabBarHeight, width: Screen.width, height: tabBarHeight))
fakeTabBar.backgroundColor = .black
let tab0 = UIButton(frame: CGRect(x: Screen.width * 0.08, y: 9, width: 32, height: 32))
tab0.setBackgroundImage(#imageLiteral(resourceName: "tab-events"), for: .normal)
tab0.addTarget(self, action: #selector(tapped0), for: .touchUpInside)
fakeTabBar.addSubview(tab0)
let tab1 = UIButton(frame: CGRect(x: Screen.width * 0.32, y: 9, width: 32, height: 32))
tab1.setBackgroundImage(#imageLiteral(resourceName: "tab-feat"), for: .normal)
tab1.addTarget(self, action: #selector(tapped1), for: .touchUpInside)
fakeTabBar.addSubview(tab1)
let tab2 = UIButton(frame: CGRect(x: Screen.width * 0.58, y: 9, width: 32, height: 32))
tab2.setBackgroundImage(#imageLiteral(resourceName: "tab-chat"), for: .normal)
tab2.addTarget(self, action: #selector(tapped2), for: .touchUpInside)
fakeTabBar.addSubview(tab2)
let tab3 = UIButton(frame: CGRect(x: Screen.width * 0.82, y: 9, width: 32, height: 32))
tab3.setBackgroundImage(#imageLiteral(resourceName: "tab-profile"), for: .normal)
tab3.addTarget(self, action: #selector(tapped3), for: .touchUpInside)
fakeTabBar.addSubview(tab3)
view.addSubview(fakeTabBar)
}
func tapped0() {
self.moveToPage(0, animated: true)
}
func tapped1() {
self.moveToPage(1, animated: true)
}
func tapped2() {
self.moveToPage(2, animated: true)
}
func tapped3() {
self.moveToPage(3, animated: true)
}
}
extension KUSwipeViewController: EZSwipeControllerDataSource {
func viewControllerData() -> [UIViewController] {
let nav0 = UINavigationController()
let nav3 = UINavigationController()
let mapVC = EventMapViewController()
let featuredVC = FeaturedEventsViewController()
let chatVC = MessagesViewController()
let profileVC = ProfileViewController()
nav0.viewControllers = [mapVC]
nav3.viewControllers = [profileVC]
return [nav0, featuredVC, chatVC, nav3]
}
func titlesForPages() -> [String] {
return ["", "", "", ""]
}
func indexOfStartingPage() -> Int {
return 0
}
func changedToPageIndex(_ index: Int) {
Haptic.selection.generate()
}
}
-Code für Kartenansicht Controller:
class EventMapViewController: CommonViewController {
fileprivate var mapView: MGLMapView!
fileprivate var statusBarView: UIView!
fileprivate var searchBar: FloatingSearchBar!
fileprivate var searchButton: UIButton!
fileprivate var filterButton: UIButton!
fileprivate var peekView: UIView!
fileprivate var architectView: UIView!
fileprivate var panArchitectView: UIView!
fileprivate var peekArchitectView: UIView!
fileprivate var peekLabel: UILabel!
fileprivate var panView: UIPanGestureRecognizer!
fileprivate let peekViewHeight: CGFloat = 140
fileprivate var selectedEvent: Event?
fileprivate var cardShowing: Bool = false
fileprivate var peekShowing: Bool = false
/*
override func statusBarStyle() -> UIStatusBarStyle {
return cardShowing ? .lightContent : .default
}
*/
override func navigationBarHidden() -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
initUI()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "eventSegue" {
let dvc = segue.destination as! EventViewController
dvc.event = selectedEvent!
}
}
func initUI() {
mapView = MGLMapView(frame: view.bounds)
mapView.styleURL = (UIColor.theme == .light) ? URL(string: mbThemeLight)! : URL(string: mbThemeDark)!
mapView.showsUserLocation = true
mapView.userTrackingMode = .none
mapView.delegate = self
mapView.setCenter(CLLocationCoordinate2D(latitude: 34, longitude: -118), zoomLevel: 5, animated: false)
view.addSubview(mapView)
mapView.snp.makeConstraints { (make) in
make.edges.equalTo(view)
}
//architect view (for intercepting touch)
architectView = UIView(frame: self.view.bounds)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EventMapViewController.handleTap(gestureRecognizer:)))
gestureRecognizer.delegate = self
architectView.addGestureRecognizer(gestureRecognizer)
architectView.isHidden = true
view.addSubview(architectView)
statusBarView = UIView()
statusBarView.backgroundColor = UIColor.clear
view.addSubview(statusBarView)
statusBarView.snp.makeConstraints { (make) in
make.left.right.top.equalTo(0)
make.height.equalTo(20)
}
searchButton = UIButton()
searchButton.backgroundColor = UIColor.kuLightBackground
searchButton.tintColor = (UIColor.theme == .light) ? UIColor.kuPrimary : UIColor.kuDeselected
searchButton.setImage(#imageLiteral(resourceName: "icon_search_white").withRenderingMode(.alwaysTemplate), for: .normal)
searchButton.layer.cornerRadius = 25
searchButton.layer.borderColor = UIColor.kuExtraLightBackground.cgColor
searchButton.layer.borderWidth = 1
searchButton.addTarget(self, action: #selector(searchButtonTapped(_:)), for: .touchUpInside)
view.addSubview(searchButton)
searchButton.snp.makeConstraints { (make) in
make.width.height.equalTo(50)
make.left.equalTo(24)
make.top.equalTo(34)
}
filterButton = UIButton()
filterButton.backgroundColor = UIColor.kuLightBackground
filterButton.tintColor = (UIColor.theme == .light) ? UIColor.kuPrimary : UIColor.kuDeselected
filterButton.setImage(#imageLiteral(resourceName: "icon_filter_white").withRenderingMode(.alwaysTemplate), for: .normal)
filterButton.layer.cornerRadius = 20
filterButton.layer.borderColor = UIColor.kuExtraLightBackground.cgColor
filterButton.layer.borderWidth = 1
filterButton.addTarget(self, action: #selector(filterButtonTapped(_:)), for: .touchUpInside)
view.addSubview(filterButton)
filterButton.snp.makeConstraints { (make) in
make.width.height.equalTo(40)
make.left.equalTo(80)
make.top.equalTo(40)
}
//peek view
peekView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height, width: UIScreen.main.bounds.width, height: peekViewHeight))
peekView.backgroundColor = UIColor(white: 1, alpha: 0.5)
peekView.layer.cornerRadius = 10
view.addSubview(peekView)
//peek label
peekLabel = UILabel(frame: CGRect(x: 0, y: 12, width: UIScreen.main.bounds.width, height: 68))
peekLabel.font = UIFont.kuBoldFont(ofSize: 38)
peekLabel.textColor = .black
peekLabel.textAlignment = .center
peekView.addSubview(peekLabel)
//peek architect
peekArchitectView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: peekViewHeight))
let peekGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EventMapViewController.peekSelected(gestureRecognizer:)))
peekGestureRecognizer.delegate = self
peekArchitectView.addGestureRecognizer(peekGestureRecognizer)
peekView.addSubview(peekArchitectView)
loadEventAnnotations()
}
func enterPeekView() {
guard !peekShowing else { return }
architectView.isHidden = false
peekLabel.text = "\(selectedEvent!.title!) >"
peekView.cheetah
.move(0, peekViewHeight * -1)
.duration(0.18)
.easeOutExpo
.run()
peekShowing = true
}
func exitPeekView() {
guard peekShowing else { return }
architectView.isHidden = true
peekView.cheetah
.move(0, peekViewHeight)
.duration(0.18)
.easeInExpo
.run()
peekShowing = false
}
func loadEventAnnotations() {
RealmManager.shared.defaultRealm.objects(Event.self).forEach { (event) in
let annotation = EventAnnotation()
annotation.event = event
mapView.addAnnotation(annotation)
}
}
func searchButtonTapped(_ sender: UIButton) {
let eventSearchCardViewController = EventSearchCardViewController()
eventSearchCardViewController.delegate = self
UIApplication.rootViewController()?.presentCardViewController(eventSearchCardViewController)
}
func filterButtonTapped(_ sender: UIButton) {
let eventFilterCardViewController = EventFilterCardViewController()
eventFilterCardViewController.delegate = self
UIApplication.rootViewController()?.presentCardViewController(eventFilterCardViewController)
}
}
extension EventMapViewController: CardViewControllerDelegate {
func cardViewControllerWillAppear(cardViewController: CardViewController) {
cardShowing = true
setNeedsStatusBarAppearanceUpdate()
}
func cardViewControllerWillDisappear(cardViewController: CardViewController) {
cardShowing = false
setNeedsStatusBarAppearanceUpdate()
}
}
extension EventMapViewController: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
guard let eventAnnotation = annotation as? EventAnnotation else {
return
}
selectedEvent = eventAnnotation.event
enterPeekView()
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return false
}
func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: UIColor.kuMarkerName)
if annotationImage == nil {
var image = UIImage(named: UIColor.kuMarkerName)!
image = image.withAlignmentRectInsets(UIEdgeInsets(top: 0, left: 0, bottom: image.size.height/2, right: 0))
annotationImage = MGLAnnotationImage(image: image, reuseIdentifier: UIColor.kuMarkerName)
}
return annotationImage
}
}
extension EventMapViewController: UIGestureRecognizerDelegate {
func handleTap(gestureRecognizer: UIGestureRecognizer) {
//close peek and keyboard on tap
view.endEditing(true)
if peekShowing {
exitPeekView()
}
}
func peekSelected(gestureRecognizer: UIGestureRecognizer) {
// performSegue(withIdentifier: "eventSegue", sender: nil)
let eventController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EventViewController") as! EventViewController
self.navigationController?.pushViewController(eventController, animated: true)
}
}