2010-09-09 23 views
9

này nói về một ứng dụng iPhone sử dụng MKMapKit:subclassing MKAnnotationView và trọng setDragState

Tôi tạo ra một MKAnnotationView tùy chỉnh cho một Chú kéo. Tôi muốn tạo một hoạt hình tùy chỉnh. Tôi thiết lập một hình ảnh pin tùy chỉnh và chú thích là có thể kéo (mà cả hai không được hiển thị ở đây, nó sẽ xảy ra trong MapView) với đoạn mã sau:

- (void) movePinUpFinished { 

    [super setDragState:MKAnnotationViewDragStateDragging]; 
    [self setDragState:MKAnnotationViewDragStateDragging]; 
} 

- (void) setDragState:(MKAnnotationViewDragState) myState { 
    if (myState == MKAnnotationViewDragStateStarting) { 
      NSLog(@"starting"); 
      CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
      self.center = endPoint; 
      [self movePinUpFinished]; 
    } 
    if (myState == MKAnnotationViewDragStateEnding) { 
      NSLog(@"ending"); 
      [super setDragState:MKAnnotationViewDragStateEnding]; 
      [self setDragState:MKAnnotationViewDragStateNone]; 
      [super setDragState:MKAnnotationViewDragStateNone]; 
    } 
    if (myState == MKAnnotationViewDragStateDragging) { 
      NSLog(@"dragging"); 
    } 
    if (myState == MKAnnotationViewDragStateCanceling) { 
      NSLog(@"cancel"); 
    } 
    if (myState == MKAnnotationViewDragStateNone) { 
      NSLog(@"none"); 
    } 
} 

Tất cả mọi thứ hoạt động tốt, các chú thích được di chuyển lên một chút, là có thể kéo và khi tôi phát hành chú thích, mapview nhận được "dragstateending".

Nhưng bây giờ tôi muốn các hình ảnh động để chạy qua một khoảng thời gian và thay đổi dragStateStarting như sau:

if (myState == MKAnnotationViewDragStateStarting) { 
      NSLog(@"starting"); 
      CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
      [UIView animateWithDuration:1.0 
      animations:^{ self.center = endPoint; } 
      completion:^(BOOL finished){ [self movePinUpFinished]; }]; 
    } 

Những hình ảnh động chạy như muốn trong giai đoạn của một giây và chú thích là có thể kéo được. Nhưng khi tôi phát hành chú thích, mapview không nhận được kết thúc thông qua đại biểu. Điều tôi cũng nhận ra là khi tôi thực hiện hoạt ảnh với "UIView animateWithDuration ..." là ngay sau khi bắt đầu kéo, khi hoạt ảnh bắt đầu, dấu chú giải của chú thích mở ra. Khi tôi thiết lập trung tâm mới mà không có hình động, quả bóng sẽ đóng lại và chỉ mở sau khi hoàn tất việc kéo bằng cách nhả chú thích.

Tôi đang làm gì sai? Đây có phải là cách đúng để ghi đè setDragState không. Tôi có thực sự phải gọi lớp học siêu đẳng không? Nhưng mà không thiết lập các dragstate trong superclass mapview của tôi didnt nhận ra những thay đổi của dragstate.

Tôi tự hỏi về triển khai ban đầu của MKPinAnnotationView, nhưng bởi vì nó là một lớp nội bộ tôi không thể tìm thấy một mô tả của phương pháp setDragState.

Thx để được trợ giúp. Chúc mừng,

Bến

Trả lời

23

tôi đã kéo pin làm việc nhưng đã cố gắng tìm ra lý do tại sao annimations pin xảy ra khi bạn không ghi đè setDragState - không còn làm việc trong việc thực hiện của tôi. Câu hỏi của bạn chứa câu trả lời của tôi .. Cảm ơn!

Một phần của sự cố với mã của bạn là khi bạn ghi đè hàm setDragState, theo tài liệu xcode, bạn chịu trách nhiệm cập nhật biến dragState dựa trên trạng thái mới sắp tới. Tôi cũng sẽ lo lắng một chút về tự gọi mã (setDragState gọi [self setDragState]).

Đây là mã tôi đã kết thúc (với sự giúp đỡ của bạn) mà tất cả các thang máy, kéo và giọt như tôi mong đợi chúng xảy ra. Hy vọng điều này sẽ giúp bạn quá!

- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated 
{ 
    if (newDragState == MKAnnotationViewDragStateStarting) 
    { 
     // lift the pin and set the state to dragging 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
          { self.dragState = MKAnnotationViewDragStateDragging; }]; 
    } 
    else if (newDragState == MKAnnotationViewDragStateEnding) 
    { 
     // save the new location, drop the pin, and set state to none 

     /* my app specific code to save the new position 
     objectObservations[ACTIVE].latitude = pinAnnotation.coordinate.latitude; 
     objectObservations[ACTIVE].longitude = pinAnnotation.coordinate.longitude; 
     posChanged = TRUE; 
     */ 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
          { self.dragState = MKAnnotationViewDragStateNone; }]; 
    } 
    else if (newDragState == MKAnnotationViewDragStateCanceling) 
    { 
     // drop the pin and set the state to none 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
          { self.dragState = MKAnnotationViewDragStateNone; }]; 
    } 
} 
+0

Làm thế nào nó hoạt động hoàn hảo? Khi bạn kéo ghim bên ngoài màn hình, nó sẽ gây ra sự cố. – akshay1188

+0

Điều này làm việc, nhưng có một điều ngăn cản tôi: Trong MKMapViewDelegate của tôi, tôi ghi đè mapView: annotationView: didChangeDragState. Lớp cơ sở MKAnnotationView tạo ra hai chuyển tiếp: Từ 0-> 1 khi kéo bắt đầu, và 1-> 4 khi nó kết thúc. Giải pháp này ở trên dường như tuân theo hướng dẫn của Apple đối với T, nhưng nó tạo ra một chuyển đổi 0-> 2 và 2> 0. Tôi có thể sống với nó nhưng thật kỳ lạ - tôi nghĩ tài liệu của Apple đã tắt, phải trung thực. – n13

+1

Tôi nghĩ bạn cần gọi 'self.dragState = ...', không phải 'dragState ='. Nếu không, thông báo KVO sẽ không được gửi và chế độ xem bản đồ sẽ không thấy thay đổi trạng thái kéo. – Rick

2

Tôi không nghiên cứu mã của Ben nhiều nhưng nó không hiệu quả đối với tôi. Vì vậy, tôi đã thử Brian và nó hoạt động rất tốt. Cảm ơn rất nhiều! Tôi đã cố gắng giải quyết hoạt ảnh của chú thích trong suốt quá trình kéo thả trong một thời gian dài.

Nhưng tôi có một gợi ý cho giải pháp của Brian. Tôi nghĩ rằng nó sẽ là tốt hơn để hỗ trợ đại biểu của MKMapKit và thông báo cho nó về việc thay đổi dragState và lưu vị trí mới trong phương thức của đại biểu tiêu chuẩn: - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState. Đây là mã của tôi:

DraggableAnnotationView.h:

#import <Foundation/Foundation.h> 
#import <MapKit/MapKit.h> 

@interface DraggableAnnotationView : MKAnnotationView 
{ 
    id <MKMapViewDelegate> delegate; 
    MKAnnotationViewDragState dragState; 
} 

@property (nonatomic, assign) id <MKMapViewDelegate> delegate; 
@property (nonatomic, assign) MKAnnotationViewDragState dragState; 
@property (nonatomic, assign) MKMapView *mapView; 

@end 

DraggableAnnotationView.m:

#import "DraggableAnnotationView.h" 
#import "MapAnnotation.h" 

@implementation DraggableAnnotationView 
@synthesize delegate, dragState, mapView; 



- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated 
{ 
    [delegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState]; 

    if (newDragState == MKAnnotationViewDragStateStarting) { 
     // lift the pin and set the state to dragging 
     CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
     { dragState = MKAnnotationViewDragStateDragging; }]; 
    } else if (newDragState == MKAnnotationViewDragStateEnding) { 
     // drop the pin, and set state to none 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
     { dragState = MKAnnotationViewDragStateNone; }]; 
    } else if (newDragState == MKAnnotationViewDragStateCanceling) { 
     // drop the pin and set the state to none 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
     { dragState = MKAnnotationViewDragStateNone; }]; 
    } 
} 

- (void)dealloc 
{ 
    [super dealloc]; 
} 

@end 
+0

Nó đổ vỡ khi chúng tôi kéo ghim vào các cạnh của chế độ xem và ngón tay của chúng tôi trượt ra khỏi màn hình. – akshay1188

3

Trong khi Brian's solution làm việc, nó thiếu tính đến các ngón tay người dùng chặn xem chú thích mà đã được chế tác.

Điều này có nghĩa là người dùng không thể đặt chính xác ghim sau khi kéo nó. Các tiêu chuẩn MKPinAnnotationView hiện một công việc tuyệt vời ở đây, những gì sẽ xảy ra là khi ngón tay bắt đầu kéo, pin được nâng lên trên ngón tay, và điểm trực quan của pin được sử dụng cho vị trí không phải là điểm trung tâm trước đó mà nằm dưới ngón tay.

Ngoài việc triển khai này, tôi còn thêm hoạt ảnh khác khi thả ghim sau khi kéo, bằng cách nhấc chốt và thả nó với tốc độ cao hơn. Điều này rất gần với trải nghiệm người dùng gốc và sẽ được người dùng của bạn đánh giá cao.

Vui lòng xem gist on GitHub for the code của tôi.

Điều thực sự thú vị là đặt đại biểu là tùy chọn, tùy chọn một thông báo sẽ được gửi khi chế độ xem chú thích được thả trở lại bản đồ.

+1

Triển khai này gần gũi hơn với hành vi của Apple so với các câu trả lời khác. Tuyệt vời, cảm ơn! –

+0

Có một số lỗi chính tả trong tên #import và @interface nhưng chúng rất dễ sửa. Làm tốt lắm. Cảm ơn bạn! – demosten

+0

Thật xấu hổ, đã sửa nó ngay bây giờ. Cảm ơn cho những người đứng đầu lên – Daniel

Các vấn đề liên quan