2012-06-15 36 views
6

Tôi có chế độ xem có hai nhãn. Khi tôi vuốt sang trái, tôi điền nội dung tiếp theo vào nhãn văn bản. Tương tự, vuốt phải tải nội dung trước đó. Tôi muốn tạo hiệu ứng cho các nhãn như chúng đang cuộn từ trái sang phải. Tôi đã sử dụng scrollview trước nhưng nó có vấn đề về bộ nhớ. Vì vậy, tôi đang sử dụng một chế độ xem và thao tác vuốt sẽ tải nội dung tiếp theo hoặc trước đó. Tôi muốn thêm hiệu ứng trượt của scrollview vào nhãn. Làm thế nào tôi có thể làm điều đó?Hiệu ứng cuộn với cử chỉ vuốt trong iOS

+0

Nhân tiện, trong khi tôi hiển thị một cách tạo hiệu ứng nhãn bên dưới, tôi không hiểu tại sao bạn lại gặp phải vấn đề về bộ nhớ "" với chế độ xem cuộn. Nếu bạn đăng mã đó, chúng tôi có thể giúp bạn tìm thấy vấn đề bộ nhớ của bạn ở đó, nếu bạn muốn. – Rob

+0

sử dụng dòng chảy bao gồm một tốt nhất của nó và cung cấp cho cái nhìn tốt đẹp – parag

Trả lời

15

Tôi không chắc chắn chính xác hiệu ứng bạn đang tìm kiếm, nhưng bạn có thể làm một cái gì đó như thế này, tạo nhãn mới, tạm thời, đặt nó ra khỏi màn hình, làm động nó di chuyển trên nhãn bạn có màn hình, và sau đó khi hoàn tất, đặt lại màn hình cũ và xóa nhãn tạm thời. Đây là cách triển khai không tự động hoàn thành có thể trông giống như:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 

    UISwipeGestureRecognizer *left = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(leftSwipe:)]; 
    [left setDirection:UISwipeGestureRecognizerDirectionLeft]; 
    [self.view addGestureRecognizer:left]; 
    // if non-ARC, release it 
    // [release left]; 

    self.label1.text = @"Mo"; 
} 

- (void)leftSwipe:(UISwipeGestureRecognizer *)gesture 
{ 
    NSString *newText; 
    UILabel *existingLabel = self.label1; 

    // in my example, I'm just going to toggle the value between Mo and Curly 

    if ([existingLabel.text isEqualToString:@"Curly"]) 
     newText = @"Mo"; 
    else 
     newText = @"Curly"; 

    // create new label 

    UILabel *tempLabel = [[UILabel alloc] initWithFrame:existingLabel.frame]; 
    [existingLabel.superview addSubview:tempLabel]; 
    tempLabel.text = newText; 

    // move the new label off-frame to the right 

    tempLabel.transform = CGAffineTransformMakeTranslation(tempLabel.superview.bounds.size.width, 0); 

    // animate the sliding of them into place 

    [UIView animateWithDuration:0.5 
        animations:^{ 
         tempLabel.transform = CGAffineTransformIdentity; 
         existingLabel.transform = CGAffineTransformMakeTranslation(-existingLabel.superview.bounds.size.width, 0); 
        } 
        completion:^(BOOL finished) { 
         existingLabel.text = newText; 
         existingLabel.transform = CGAffineTransformIdentity; 
         [tempLabel removeFromSuperview]; 
        }]; 

    // if non-ARC, release it 
    // [release tempLabel]; 
} 

Hoạt ảnh này làm nổi bật nhãn đối với người giám sát của nó. Bạn có thể muốn đảm bảo rằng superview được đặt thành "clip subviews". Bằng cách này, hoạt ảnh sẽ bị giới hạn ở các giới hạn của superview, mang lại một cái nhìn được đánh bóng hơn một chút.

Lưu ý, nếu sử dụng bố cục tự động, ý tưởng là như nhau (mặc dù việc thực thi phức tạp hơn). Về cơ bản cấu hình ràng buộc của bạn để xem mới là bên phải, sau đó, trong cập nhật khối hình động/thay thế các ràng buộc để nhãn ban đầu là bên trái và mới là tại chỗ của nhãn gốc, và cuối cùng, trong khối hoàn thành thiết lập lại các ràng buộc của nhãn gốc và loại bỏ nhãn tạm thời.


Bằng cách này, đây là tất cả vô cùng dễ dàng hơn nếu bạn cảm thấy thoải mái với một trong những xây dựng trong quá trình chuyển đổi:

- (void)leftSwipe:(UISwipeGestureRecognizer *)gesture 
{ 
    NSString *newText; 
    UILabel *existingLabel = self.label1; 

    // in my example, I'm just going to toggle the value between Mo and Curly 

    if ([existingLabel.text isEqualToString:@"Curly"]) 
     newText = @"Mo"; 
    else 
     newText = @"Curly"; 

    [UIView transitionWithView:existingLabel // or try `existingLabel.superview` 
         duration:0.5 
         options:UIViewAnimationOptionTransitionFlipFromRight 
        animations:^{ 
         existingLabel.text = newText; 
        } 
        completion:nil]; 
} 
+0

Cảm ơn bạn rất nhiều cho câu trả lời chi tiết của bạn. Các hình ảnh động là OK bây giờ. Nhưng hoạt hình của scrollview thì tốt hơn. Vấn đề với chế độ xem cuộn: Bên trong cuộn có một chế độ xem khác. Bất cứ khi nào người dùng cuộn một chế độ xem mới sẽ được thêm vào bên trong scrollview. Nhưng sau 50 lượt xem ứng dụng bị treo với cảnh báo bộ nhớ. Tôi đã thử một cái gì đó nhưng không tìm thấy một giải pháp. Vì vậy, đã quyết định xóa chế độ xem cuộn. – Oktay

+0

@Oktay có vẻ như bạn có một lỗi/rò rỉ đơn giản trong mã scrollview của mình. Rất nhiều người sử dụng scrollviews mà không có bất kỳ vấn đề. Một lần nữa, nếu bạn đăng mã của bạn, tôi nghi ngờ nó có thể dễ dàng khắc phục. – Rob

+0

@Oktay Bạn nói rằng bạn thích hoạt hình của chế độ xem cuộn tốt hơn, nhưng tôi không chắc bạn thích điều gì hơn về nó. Bởi vì nó sử dụng cử chỉ di chuyển (tức là cử chỉ liên tục bắt đầu di chuyển ngay khi bạn bắt đầu di chuyển ngón tay trên màn hình)? Tôi đã thực hiện một cử chỉ vuốt thay vì cử chỉ di chuyển vì tiêu đề của bạn gợi ý bạn muốn điều đó, nhưng cử chỉ xoay liên tục rất dễ dàng. Hoặc có cái gì khác về scrollview mà bạn thích? – Rob

6

Nếu bạn thích phim hoạt hình mà ứng xử giống như một cái nhìn cuộn (ví dụ, với thông tin phản hồi liên tục trên cử chỉ), nó có thể trông giống như sau:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandler:)]; 
    [self.view addGestureRecognizer:pan]; 

    self.label1.text = @"Mo"; 
} 

- (void)panHandler:(UIPanGestureRecognizer *)sender 
{ 
    if (sender.state == UIGestureRecognizerStateBegan) 
    { 
     _panLabel = [[UILabel alloc] init]; 

     // in my example, I'm just going to toggle the value between Mo and Curly 
     // you'll presumably set the label contents based upon the direction of the 
     // pan (if positive, swiping to the right, grab the "previous" label, if negative 
     // pan, grab the "next" label) 

     if ([self.label1.text isEqualToString:@"Curly"]) 
      _newText = @"Mo"; 
     else 
      _newText = @"Curly"; 

     // set the text 

     _panLabel.text = _newText; 

     // set the frame to just be off screen 

     _panLabel.frame = CGRectMake(self.label1.frame.origin.x + self.containerView.frame.size.width, 
            self.label1.frame.origin.y, 
            self.label1.frame.size.width, 
            self.label1.frame.size.height); 

     [self.containerView addSubview:_panLabel]; 

     _originalCenter = self.label1.center; // save where the original label originally was 
    } 
    else if (sender.state == UIGestureRecognizerStateChanged) 
    { 
     CGPoint translate = [sender translationInView:self.containerView]; 

     if (translate.x > 0) 
     { 
      _panLabel.center = CGPointMake(_originalCenter.x - self.containerView.frame.size.width + translate.x, _originalCenter.y); 
      self.label1.center = CGPointMake(_originalCenter.x + translate.x, _originalCenter.y); 
     } 
     else 
     { 
      _panLabel.center = CGPointMake(_originalCenter.x + self.containerView.frame.size.width + translate.x, _originalCenter.y); 
      self.label1.center = CGPointMake(_originalCenter.x + translate.x, _originalCenter.y); 
     } 
    } 
    else if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) 
    { 
     CGPoint translate = [sender translationInView:self.containerView]; 
     CGPoint finalNewFieldLocation; 
     CGPoint finalOriginalFieldLocation; 
     BOOL panSucceeded; 

     if (sender.state == UIGestureRecognizerStateFailed || 
      sender.state == UIGestureRecognizerStateCancelled) 
     { 
      panSucceeded = NO; 
     } 
     else 
     { 
      // by factoring in the velocity, we can capture a flick more accurately 
      // 
      // (by the way, I don't like iOS's velocity, because if you stop moving, it records the velocity 
      // prior to stopping the move rather than noting that you actually stopped, so I usually calculate my own, 
      // but I'll leave this as is for purposes of this example) 

      CGPoint velocity = [sender velocityInView:self.containerView]; 

      if (translate.x < 0) 
       panSucceeded = ((translate.x + velocity.x * 0.5) < -(self.containerView.frame.size.width/2)); 
      else 
       panSucceeded = ((translate.x + velocity.x * 0.5) > (self.containerView.frame.size.width/2)); 
     } 

     if (panSucceeded) 
     { 
      // if we succeeded, finish moving the stuff 

      finalNewFieldLocation = _originalCenter; 
      if (translate.x < 0) 
       finalOriginalFieldLocation = CGPointMake(_originalCenter.x - self.containerView.frame.size.width, _originalCenter.y); 
      else 
       finalOriginalFieldLocation = CGPointMake(_originalCenter.x + self.containerView.frame.size.width, _originalCenter.y); 
     } 
     else 
     { 
      // if we didn't, then just return everything to where it was 

      finalOriginalFieldLocation = _originalCenter; 

      if (translate.x < 0) 
       finalNewFieldLocation = CGPointMake(_originalCenter.x + self.containerView.frame.size.width, _originalCenter.y); 
      else 
       finalNewFieldLocation = CGPointMake(_originalCenter.x - self.containerView.frame.size.width, _originalCenter.y); 
     } 

     // animate the moving of stuff to their final locations, and on completion, clean everything up 

     [UIView animateWithDuration:0.3 
           delay:0.0 
          options:UIViewAnimationOptionCurveEaseOut 
         animations:^{ 
          _panLabel.center = finalNewFieldLocation; 
          self.label1.center = finalOriginalFieldLocation; 
         } 
         completion:^(BOOL finished) { 
          if (panSucceeded) 
           self.label1.text = _newText; 
          self.label1.center = _originalCenter; 
          [_panLabel removeFromSuperview]; 
          _panLabel = nil; // in non-ARC, release instead 
         } 
     ]; 
    } 
} 

Lưu ý, tôi đã đưa cả nhãn gốc, cũng như các nhãn mới được trích gay gắt trên, trong một UIVie chứa w (được gọi là containerView, đủ ngạc nhiên), để tôi có thể cắt hoạt hình cho vùng chứa đó.

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