2010-09-01 35 views
6

Tôi đang cố gắng tạo điều khiển quay số, về cơ bản là 6 chữ số quay xung quanh để tạo hiệu ứng của đồng hồ đo quay số (tương tự như công suất/nước của bạn) mét, hoặc có lẽ một máy poker, trên thực tế rất giống với điều khiển UIPickerView hiện có, nhưng với một cái nhìn hoàn toàn khác và cảm nhận).Các khó khăn về hoạt ảnh lõi với điều khiển quay số (rất chi tiết)

Cho đến nay, tôi gần như đã làm việc, nhưng Im ở một giai đoạn mà hoạt hình cốt lõi là cho tôi đau buồn.

Đoạn mã rất phức tạp của nó sẽ rất khó để có được ảnh chụp nhanh về những gì đang diễn ra, vì vậy tôi nghĩ mã giả sẽ đủ.

Thứ nhất, về thiết lập chế độ xem, tôi có 6 riêng biệt UIView s (được gọi là NumberView1, NumberView2, v.v ...), mỗi cái cho mỗi số trong điều khiển.

Bên trong mỗi NumberViewX tôi đã khác UIView, đó là một cái nhìn container, gọi ContainerView1, 2, vv ...

Sau đó tôi có 10 UIImageView s xếp chồng lên nhau tại các độ lệch Y khác nhau. Những hình ảnh này là tất cả 30x30 mà làm cho nó tốt đẹp. 9 là đầu tiên, sau đó 8 tại y-bù 30, sau đó 7 tại y-bù đắp 60, vv ... tất cả các con đường xuống 0 tại y-offset 270.

LƯU Ý QUAN TRỌNG: Các con số của tôi chỉ bao giờ cuộn lên trên

Các số đại diện cho số điểm 5 thập phân (nghĩa là 2.34677) sẽ cuộn lên (ví dụ: 2.61722).

Tôi cũng có một số từ điển mà giữ giá trị số hiện tại cho mỗi số và hiệu số cho mỗi số:

NSArray *offsets = [[NSArray alloc] initWithObjects: 
        [NSNumber numberWithInt:0], //9 
        [NSNumber numberWithInt:-30], //8 
        [NSNumber numberWithInt:-60], //7 
        [NSNumber numberWithInt:-90], //6 
        [NSNumber numberWithInt:-120], //5 
        [NSNumber numberWithInt:-150], //4 
        [NSNumber numberWithInt:-180], //3 
        [NSNumber numberWithInt:-210], //2 
        [NSNumber numberWithInt:-240], //1 
        [NSNumber numberWithInt:-270], //0 
        nil]; 

NSArray *keys = [[NSArray alloc] initWithObjects: 
       [NSNumber numberWithInt:9], 
       [NSNumber numberWithInt:8], 
       [NSNumber numberWithInt:7], 
       [NSNumber numberWithInt:6], 
       [NSNumber numberWithInt:5], 
       [NSNumber numberWithInt:4], 
       [NSNumber numberWithInt:3], 
       [NSNumber numberWithInt:2], 
       [NSNumber numberWithInt:1], 
       [NSNumber numberWithInt:0], nil]; 

offsetDict = [[NSDictionary alloc] initWithObjects:offsets forKeys:keys]; 

[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:2] forKey: [NSValue valueWithNonretainedObject: self.containerViewDollarSlot1]]; 
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:8] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace1]]; 
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:3] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace2]]; 
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:3] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace3]]; 
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:8] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace4]]; 
[currentValuesForDecimalPlace setObject:[NSNumber numberWithInt:5] forKey: [NSValue valueWithNonretainedObject: self.containerViewDecimalPlace5]]; 

Bây giờ cho logic, tôi bắt đầu thiết lập các thuộc lớp của ContainerView được offsets nhất định Y sẽ chuyển các số hiện tại vào các vị trí chính xác của chúng, như vậy:

self.containerViewDollarSlot1.layer.transform = CATransform3DTranslate(self.containerViewDollarSlot1.layer.transform, 0, -210, 0); 
self.containerViewDecimalPlace1.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace1.layer.transform, 0, -30, 0); 
self.containerViewDecimalPlace2.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace2.layer.transform, 0, -180, 0); 
self.containerViewDecimalPlace3.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace3.layer.transform, 0, -180, 0); 
self.containerViewDecimalPlace4.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace4.layer.transform, 0, -30, 0); 
self.containerViewDecimalPlace5.layer.transform = CATransform3DTranslate(self.containerViewDecimalPlace5.layer.transform, 0, -120, 0); 

sẽ hiển thị số, 2.83385, là số tùy ý để kiểm tra.

Sau đó, tôi nhập vào một giá trị trong một textbox và nhấn nút đi tour diễn khởi động logic hình ảnh động, đó là nơi mà tôi nhận được những khó khăn trong Core Animation (như tựa đề)

tôi gọi:

[self animateDecimalPlace: 0 
      withAnimation: self.dollarSlot1Animation 
     andContainerView: self.containerViewDollarSlot1]; 
[self animateDecimalPlace: 1 
      withAnimation: self.decimalPlace1Animation 
     andContainerView: self.containerViewDecimalPlace1]; 
//etc... for all 6 numbers 

nơi dollarSlot1Animation là Ivar CABasicAnimation

phương pháp này được định nghĩa dưới đây:

- (void) animateDecimalPlace: (int) decimalIndex withAnimation: (CABasicAnimation*)animation andContainerView: (UIView*) containerView{ 

NSRange decimalRange = {decimalIndex == 0 ? 0 : 2, 
         decimalIndex == 0 ? 1 : decimalIndex}; 

double diff = 0; 
if (decimalIndex == 0) 
{ 
    int decimalPartTarget = [[[NSString stringWithFormat:@"%f", targetNumber] substringWithRange: decimalRange] intValue]; 
    int decimalPartCurrent = [[[NSString stringWithFormat:@"%f", currentValue] substringWithRange: decimalRange] intValue]; 
    diff = decimalPartTarget - decimalPartCurrent; 
} 
else { 
    double fullDiff = targetNumber - currentValue; 
    diff = [[[NSString stringWithFormat:@"%f", fullDiff] substringWithRange: decimalRange] doubleValue]; 
} 

animation.removedOnCompletion = NO; 
animation.fillMode = kCAFillModeRemoved; 
animation.duration = 5.0; 

NSNumber *n = [currentValuesForDecimalPlace objectForKey:[NSValue valueWithNonretainedObject: containerView]]; 
NSNumber *offset = (NSNumber*)[offsetDict objectForKey: n]; 
int rotations = [self setupNumberForAnimation: diff decimalIndex: decimalIndex forContainer: containerView]; 
int finalOffset = (rotations*30)+([offset intValue]); 
CATransform3D translation = CATransform3DMakeTranslation(0, finalOffset, 0); 

animation.fromValue = [NSValue valueWithCATransform3D:containerView.layer.transform]; 
animation.toValue = [NSValue valueWithCATransform3D:translation]; 
animation.delegate = self; 
[containerView.layer addAnimation: animation forKey: [NSString stringWithFormat:@"%i", decimalIndex] ]; 
} 

Như bạn có thể thấy (hoặc có lẽ không :)) Tôi đang xử lý từng số độc lập về cơ bản, và yêu cầu nó dịch sang vị trí Y mới, nhưng bạn có thể nhận thấy một phương thức có tên là setupNumberForAnimation. tự động thêm nhiều hơn UIImageView s vào vùng chứa UIView phía trên 10 hình ảnh ban đầu.

Ví dụ: có 10 ô để bắt đầu, nếu tôi muốn cuộn số quay 21 điểm (ví dụ từ 3 đến 24), tôi sẽ cần thêm 15 số mới trên 9, sau đó tạo hiệu ứng động bản dịch của chế độ xem vùng chứa lên đến ô hình ảnh hàng đầu nhất.

Sau khi cuộn xong, tôi xóa tự động thêm UIImageView s và định vị lại giá trị y của chế độ xem của vùng chứa trở lại giá trị trong khoảng từ 0 đến -270 (về cơ bản kết thúc trên cùng một số, nhưng xóa tất cả - xem hình ảnh cần thiết).

Điều này mang lại hiệu ứng động mượt mà sau đó. Và nó hoạt động. Hãy tin tôi :)

Vấn đề của tôi gấp hai lần, trước tiên khi hoạt ảnh ngừng hoạt ảnh Core Animation, hãy chuyển đổi hoạt ảnh thành lớp vì tôi đã đặt animation.fillMode = kCAFillModeRemoved; Tôi không thể hiểu được cách sau khi hoàn tất hoạt ảnh. y bù đắp, tôi biết nó âm thanh lẻ, nhưng nếu tôi có thuộc tính fillMode thiết lập để kCAFillModeForwards, không có gì tôi đã cố gắng dường như có tác dụng trên lớp. Thứ hai, khi hoạt ảnh dừng lại và thay đổi được hoàn nguyên, có một nhấp nháy nhỏ giữa khi hoạt ảnh trở lại bản dịch và khi tôi đặt lại bản dịch, tôi không thể tìm ra cách để giải quyết vấn đề này.

Tôi biết có một đống chi tiết và tính đặc hiệu ở đây, nhưng bất kỳ trợ giúp hoặc ý tưởng nào về cách thực hiện điều này sẽ được đánh giá rất nhiều.

Thanks a lot

+0

Nó đánh bại mơ hồ (như nhận xét này). – BoltClock

+0

Một luận án để đánh giá bởi một giáo sư;) –

+0

Cảm ơn vì "giúp đỡ" ... Tôi biết một bài viết chi tiết, nhưng Im mở ý tưởng khác là tốt, Im hạnh phúc để phế liệu thực hiện của tôi hoàn toàn – Mark

Trả lời

1

Tôi nhớ có điều gì đó về sự cố của hoạt ảnh nhảy trở lại trạng thái trước đó của nó trong video CoreAnimation của WWDC10 bạn có thể tải xuống miễn phí từ quả táo.

Tôi phải tra cứu sau, nhưng có tất nhiên phương thức ủy nhiệm - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag được gọi khi hoạt ảnh được thực hiện. Đây sẽ là một nơi tốt đẹp để làm một số vệ sinh. Có lẽ bạn có thể đặt độ lệch y của lớp bằng cách xem thuộc tính toValue của hoạt ảnh.

Nó chỉ là một cảnh quay dài, nhưng có thể nó đang đi đúng hướng.

+0

Vâng, cảm ơn, cách mà tôi có xung quanh vấn đề này cuối cùng là để thay đổi thuộc tính fillMode thành kCAFillModeForwards, hãy đặt removeOnCompletion = NO và sau khi hoàn thành hoạt ảnh (trong phương thức animationDidStop:, hãy gọi removeAllAnimations trên lớp đang được làm động, sau đó đặt nó ngay lập tức sau đó làm việc như một nét duyên dáng không nhảy ... – Mark

+0

Cảm ơn bạn đã bình luận Vì vậy, ít nhất tôi đã đoán đúng loại – GorillaPatch

+0

đánh dấu điều này là chính xác như nhận xét của tôi và bài đăng của bạn giải quyết được các vấn đề mà tôi gặp phải trong câu hỏi – Mark

0

Tôi hiểu một cách chính xác rằng hiệu ứng hình ảnh mà bạn muốn là phải có một bánh xe số (loại một chút giống như một dartboard) mà quay xung quanh như bộ phận đo khí/nước kiểu cũ trên bên nhà của chúng tôi khi chúng tôi lớn lên?

Nếu vậy, tại sao bạn không chỉ có một hình ảnh duy nhất là các chữ số được đặt ra trong một vòng tròn, sau đó xoay một hình ảnh mà số tiền mong muốn? Một cái gì đó như (mã chưa được kiểm tra gõ vào trình duyệt):

const double degreesPerDigit = 360.0/10.0; 
    const double radPerDigit = degreesPerDigit * M_PI/180.0; 
    CGAffineTransform xfm = CGAffineTransformMakeRotation(radPerDigit * digitUp); 
    // animated or otherwise: 
    myView.transform = xfm; 

Để câu hỏi của bạn trực tiếp (một lần nữa, mã gõ vào trình duyệt):

Để thiết lập một lớp container offset:

CGRect rect = myLayer.frame; 
rect.origin.y = newYValue; 
myLayer.frame = rect; 

Để giúp bảo vệ chống nhấp nháy, có rất nhiều kỹ thuật, tùy thuộc vào bản chất của vấn đề và kết quả mong muốn, nhưng phổ biến là sử dụng 2 lượt xem gần như giống hệt nhau, thực hiện thay đổi trên view1, tại thời điểm cuối cùng, ẩn view1 và bỏ ẩn view2.

Từ câu hỏi của bạn, có vẻ như bạn có hiểu biết về công cụ này, vì vậy tôi xin lỗi nếu tôi trả lời dưới mức của bạn, nhưng thật khó để tìm ra chính xác những gì bạn đang làm và những gì đang xảy ra.

Lời khuyên: Có thể đáng để bạn thử khắc phục câu hỏi chỉ với các bit quan trọng và, tương tự, để viết một ứng dụng mẫu bị tước mà CHỈ hoạt ảnh này và không có gì khác, và sau đó thử nghiệm với trường hợp kiểm tra tối thiểu. Modularize tất cả mọi thứ, đăng nhập tất cả mọi thứ, nghiên cứu đầu ra. Lặp lại, rửa sạch, mờ dần.

+0

Ý tưởng của bạn về quay một vòng tròn hình ảnh là thú vị, bạn có thể xây dựng hoặc điều này nhiều hơn một chút? Nếu đó là những gì tôi nghĩ là, (một vòng tròn của các con số) nó sẽ không giống như những con số đang đến trong một góc thay vì eo biển xuống? Điều đó có ý nghĩa? Cảm ơn vì sự trả lời! – Mark

+0

Trên một lưu ý khác, nó sẽ khó khăn như thế nào để thực hiện một spinner 3d? Bạn có thể làm điều này chỉ đơn giản bằng cách sử dụng Core Animation? Điều đó sẽ đá! – Mark

+0

Đây là lý do tại sao tôi nói nó không rõ ràng những gì hiệu ứng hình ảnh mà bạn muốn. Bạn đang tìm kiếm để có được một cái gì đó giống như một máy khe? Hay thứ gì đó giống như đồng hồ đo gas của trường học cũ hơn? Hoặc cái gì khác, hoàn toàn. Nếu bạn có thể cung cấp một liên kết đến cái nhìn chung mà bạn muốn, điều đó sẽ giúp chúng tôi trả lời. – Olie

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