MKMapView가 드래그 / 이동되었는지 확인
MKMapView가 드래그되었는지 확인하는 방법이 있습니까?
사용자가 사용하여지도를 끌 때마다 중심 위치를 얻고 싶지만 사용자가지도를 CLLocationCoordinate2D centre = [locationMap centerCoordinate];탐색하자마자 실행되는 델리게이트 메서드 또는 무언가가 필요합니다.
미리 감사드립니다
상기 봐 MKMapViewDelegate의 참조입니다.
특히 다음 방법이 유용 할 수 있습니다.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
해당 메서드가 호출되도록 맵 뷰의 대리자 속성이 설정되어 있는지 확인합니다.
어떤 이유로 든 지역이 변경되면 수락 된 답변의 코드가 실행됩니다. 지도 끌기를 제대로 감지하려면 UIPanGestureRecognizer를 추가해야합니다. Btw, 이것은 드래그 제스처 인식기입니다 (패닝 = 드래그).
1 단계 : viewDidLoad에 제스처 인식기 추가 :
-(void) viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didDragMap:)];
[panRec setDelegate:self];
[self.mapView addGestureRecognizer:panRec];
}
2 단계 : UIGestureRecognizerDelegate 프로토콜을 뷰 컨트롤러에 추가하여 델리게이트로 작동합니다.
@interface MapVC : UIViewController <UIGestureRecognizerDelegate, ...>
3 단계 : UIPanGestureRecognizer가 MKMapView의 기존 제스처 인식기와 함께 작동하도록 다음 코드를 추가합니다.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
4 단계 : 메서드를 드래그 할 때마다 50 번 대신 한 번 호출하려면 선택기에서 "드래그 종료"상태를 감지합니다.
- (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateEnded){
NSLog(@"drag ended");
}
}
이것은 사용자가 시작한 확대 / 축소 변경뿐만 아니라 이동을 감지하는 유일한 방법입니다.
- (BOOL)mapViewRegionDidChangeFromUserInteraction
{
UIView *view = self.mapView.subviews.firstObject;
// Look through gesture recognizers to determine whether this region change is from user interaction
for(UIGestureRecognizer *recognizer in view.gestureRecognizers) {
if(recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateEnded) {
return YES;
}
}
return NO;
}
static BOOL mapChangedFromUserInteraction = NO;
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
mapChangedFromUserInteraction = [self mapViewRegionDidChangeFromUserInteraction];
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
(그냥) @mobi의 탁월한 솔루션의 Swift 버전 :
private var mapChangedFromUserInteraction = false
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
let view = self.mapView.subviews[0]
// Look through gesture recognizers to determine whether this region change is from user interaction
if let gestureRecognizers = view.gestureRecognizers {
for recognizer in gestureRecognizers {
if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
return true
}
}
}
return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if (mapChangedFromUserInteraction) {
// user changed map region
}
}
위 의 Jano의 답변에 대한 Swift 3 솔루션 :
ViewController에 프로토콜 UIGestureRecognizerDelegate 추가
class MyViewController: UIViewController, UIGestureRecognizerDelegate
에서 UIPanGestureRecognizer를 viewDidLoad만들고 delegateself로 설정 합니다.
viewDidLoad() {
// add pan gesture to detect when the map moves
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didDragMap(_:)))
// make your class the delegate of the pan gesture
panGesture.delegate = self
// add the gesture to the mapView
mapView.addGestureRecognizer(panGesture)
}
제스처 인식기가 기존 MKMapView 제스처와 함께 작동하도록 프로토콜 메서드를 추가합니다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
이동 제스처에서 선택기에 의해 호출 될 메서드를 추가합니다.
func didDragMap(_ sender: UIGestureRecognizer) {
if sender.state == .ended {
// do something here
}
}
또 다른 가능한 해결책은 다음과 같이지도보기를 보유하는보기 컨트롤러에서 touchesMoved : (또는 touchesEnded : 등)를 구현하는 것입니다.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
for (UITouch * touch in touches) {
CGPoint loc = [touch locationInView:self.mapView];
if ([self.mapView pointInside:loc withEvent:event]) {
#do whatever you need to do
break;
}
}
}
경우에 따라 제스처 인식기를 사용하는 것보다 더 간단 할 수 있습니다.
내 경험상 "입력하는 동안 검색"과 유사하게 타이머가 가장 신뢰할 수있는 솔루션이라는 것을 알았습니다. 이동, 집기, 회전, 두드리기, 두 번 두드리기 등을위한 제스처 인식기를 추가 할 필요가 없습니다.
해결책은 간단합니다.
- 지도 지역이 변경되면 타이머 설정 / 초기화
타이머가 실행되면 새 지역의 마커를로드합니다.
import MapKit class MyViewController: MKMapViewDelegate { @IBOutlet var mapView: MKMapView! var mapRegionTimer: NSTimer? // MARK: MapView delegate func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { setMapRegionTimer() } func setMapRegionTimer() { mapRegionTimer?.invalidate() // Configure delay as bet fits your application mapRegionTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "mapRegionTimerFired:", userInfo: nil, repeats: false) } func mapRegionTimerFired(sender: AnyObject) { // Load markers for current region: // mapView.centerCoordinate or mapView.region } }
Interface Builder에서지도에 제스처 인식기를 추가 할 수도 있습니다. viewController에서 작업을 수행 할 콘센트에 연결합니다. 저는 "mapDrag"라고 불렀습니다.
그런 다음 viewController의 .m에서 다음과 같은 작업을 수행합니다.
- (IBAction)mapDrag:(UIPanGestureRecognizer *)sender {
if(sender.state == UIGestureRecognizerStateBegan){
NSLog(@"drag started");
}
}
이것도 거기에 있는지 확인하십시오.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
물론 작동하려면 .h 파일에서 viewController를 UIGestureRecognizerDelegate로 만들어야합니다.
그렇지 않으면지도의 응답자는 제스처 이벤트를 듣는 유일한 사람입니다.
이러한 솔루션 중 상당수는 Swift가 의도 한 것이 아닌 해키에 해당하므로 더 깨끗한 솔루션을 선택했습니다.
간단히 MKMapView를 하위 클래스로 만들고 touchesMoved를 재정의합니다. 이 스 니펫에는 포함되어 있지 않지만 이동과 관련하여 원하는 정보를 전달하는 위임 또는 알림을 만드는 것이 좋습니다.
import MapKit
class MapView: MKMapView {
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
print("Something moved")
}
}
이 하위 클래스를 가리 키도록 스토리 보드 파일의 클래스를 업데이트하고 다른 방법을 통해 만든 맵을 수정해야합니다.
false이면 사용자가 드래그 한지도에 애니메이션 속성을 확인할 수 있습니다.
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if animated == false {
//user dragged map
}
}
맵뷰에서 제스처가 언제 종료되었는지 인식하려면 :
http://b2cloud.com.au/tutorial/mkmapview-determining-whether-region-change-is-from-user-interaction/
이것은 사용자가지도를 확대 / 회전 / 드래그 한 후에 만 데이터베이스 쿼리를 수행하는 데 매우 유용합니다.
나에게 regionDidChangeAnimated 메소드는 제스처가 완료된 후에 만 호출되었고 드래그 / 줌 / 회전 중에 여러 번 호출되지 않았지만 제스처 때문인지 아닌지 아는 것이 유용합니다.
Jano의 답변이 저에게 효과적 이었기 때문에 Objective C에 특히 능숙하지 않기 때문에 Swift 4 / XCode 9에 대한 업데이트 버전을 남겨 둘 것이라고 생각했으며 둘 중 하나가 아닌 다른 몇 가지가 있다고 확신합니다.
1 단계 : viewDidLoad에이 코드를 추가합니다.
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didDragMap(_:)))
panGesture.delegate = self
2 단계 : 클래스가 UIGestureRecognizerDelegate를 준수하는지 확인합니다.
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UIGestureRecognizerDelegate {
3 단계 : panGesture가 다른 제스처와 동시에 작동하는지 확인하려면 다음 기능을 추가합니다.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
4 단계 : Jano가 올바르게 지적한대로 방법이 "드래그 당 50 회"호출되지 않도록합니다.
@objc func didDragMap(_ gestureRecognizer: UIPanGestureRecognizer) {
if (gestureRecognizer.state == UIGestureRecognizerState.ended) {
redoSearchButton.isHidden = false
resetLocationButton.isHidden = false
}
}
* 마지막 단계에서 @objc를 추가했습니다. XCode는 컴파일을 위해 함수에이 접두사를 강제합니다.
enter code hereI managed to do implement this in easiest way, which handles all interaction with map (tapping/double/N tapping with 1/2/N fingers, pan with 1/2/N fingers, pinch and rotations
- Create
gesture recognizerand add to map view's container - Set
gesture recognizer'sdelegateto some object implementingUIGestureRecognizerDelegate - Implement
gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)method
private func setupGestureRecognizers() { let gestureRecognizer = UITapGestureRecognizer(target: nil, action: nil) gestureRecognizer.delegate = self self.addGestureRecognizer(gestureRecognizer) } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { self.delegate?.mapCollectionViewBackgroundTouched(self) return false }
I was trying to have an annotation in the center of the map that is always at the center of the map no matter what the uses does. I tried several of the approaches mentioned above, and none of them were good enough. I eventually found a very simple way of solving this, borrowing from the Anna's answer and combining with Eneko's answer. It basically treats the regionWillChangeAnimated as the start of a drag, and regionDidChangeAnimated as the end of one, and uses a timer to update the pin in real-time:
var mapRegionTimer: Timer?
public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapRegionTimer?.invalidate()
mapRegionTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { (t) in
self.myAnnotation.coordinate = CLLocationCoordinate2DMake(mapView.centerCoordinate.latitude, mapView.centerCoordinate.longitude);
self.myAnnotation.title = "Current location"
self.mapView.addAnnotation(self.myAnnotation)
})
}
public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
mapRegionTimer?.invalidate()
}
First, make sure your current view controller is a delegate of the map. So set your Map View delegate to self and add MKMapViewDelegate to your view controller. Example below.
class Location_Popup_ViewController: UIViewController, MKMapViewDelegate {
// Your view controller stuff
}
And add this to your map view
var myMapView: MKMapView = MKMapView()
myMapView.delegate = self
Second, add this function which is fired when the map is moved. It will filter out any animations and only fire if interacted with.
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if !animated {
// User must have dragged this, filters out all animations
// PUT YOUR CODE HERE
}
}
I know this is an old post but here my Swift 4/5 code of Jano's answer whit Pan and Pinch gestures.
class MapViewController: UIViewController, MapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didDragMap(_:)))
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(self.didPinchMap(_:)))
panGesture.delegate = self
pinchGesture.delegate = self
mapView.addGestureRecognizer(panGesture)
mapView.addGestureRecognizer(pinchGesture)
}
}
extension MapViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@objc func didDragMap(_ sender: UIGestureRecognizer) {
if sender.state == .ended {
//code here
}
}
@objc func didPinchMap(_ sender: UIGestureRecognizer) {
if sender.state == .ended {
//code here
}
}
}
Enjoy!
참고URL : https://stackoverflow.com/questions/5556977/determine-if-mkmapview-was-dragged-moved
'Program Club' 카테고리의 다른 글
| Vim 파일 탐색 (0) | 2020.10.10 |
|---|---|
| 쿼리 패턴의 구현을 찾을 수 없습니다. (0) | 2020.10.10 |
| 끝부터 목록을 인덱싱 할 때 Python이 인덱스 -1 (0이 아닌)에서 시작하는 이유는 무엇입니까? (0) | 2020.10.10 |
| Groovy의 숨겨진 기능? (0) | 2020.10.10 |
| Python을 사용한 Quicksort (0) | 2020.10.10 |