Tóm lại, tôi cần phải biết chính xác khi nào scrollview ngừng cuộn. Bằng cách 'ngừng di chuyển', tôi có nghĩa là khoảnh khắc mà nó không còn di chuyển và không bị xúc động nữa.Làm thế nào để biết chính xác thời điểm cuộn UIScrollView đã dừng?
Tôi đã làm việc trên một lớp con UIScrollView ngang (dành cho iOS 4) với các tab lựa chọn trong đó. Một trong những yêu cầu của nó là nó dừng cuộn bên dưới một tốc độ nhất định để cho phép tương tác người dùng nhanh hơn. Nó cũng sẽ snap vào đầu của một tab. Nói cách khác, khi người dùng thả scrollview và tốc độ của nó xuống thấp, nó sẽ chụp một vị trí. Tôi đã thực hiện điều này và nó hoạt động, nhưng có một lỗi trong đó.
Điều tôi hiện có:
Scrollview là đại biểu của riêng nó. ở mọi cuộc gọi đến scrollViewDidScroll :, nó làm mới nó biến tốc độ liên quan đến:
-(void)refreshCurrentSpeed
{
float currentOffset = self.contentOffset.x;
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
deltaOffset = (currentOffset - prevOffset);
deltaTime = (currentTime - prevTime);
currentSpeed = deltaOffset/deltaTime;
prevOffset = currentOffset;
prevTime = currentTime;
NSLog(@"deltaOffset is now %f, deltaTime is now %f and speed is %f",deltaOffset,deltaTime,currentSpeed);
}
Sau đó tiến hành để chụp nếu cần thiết:
-(void)snapIfNeeded
{
if(canStopScrolling && currentSpeed <70.0f && currentSpeed>-70.0f)
{
NSLog(@"Stopping with a speed of %f points per second", currentSpeed);
[self stopMoving];
float scrollDistancePastTabStart = fmodf(self.contentOffset.x, (self.frame.size.width/3));
float scrollSnapX = self.contentOffset.x - scrollDistancePastTabStart;
if(scrollDistancePastTabStart > self.frame.size.width/6)
{
scrollSnapX += self.frame.size.width/3;
}
float maxSnapX = self.contentSize.width-self.frame.size.width;
if(scrollSnapX>maxSnapX)
{
scrollSnapX = maxSnapX;
}
[UIView animateWithDuration:0.3
animations:^{self.contentOffset=CGPointMake(scrollSnapX, self.contentOffset.y);}
completion:^(BOOL finished){[self stopMoving];}
];
}
else
{
NSLog(@"Did not stop with a speed of %f points per second", currentSpeed);
}
}
-(void)stopMoving
{
if(self.dragging)
{
[self setContentOffset:CGPointMake(self.contentOffset.x, self.contentOffset.y) animated:NO];
}
canStopScrolling = NO;
}
Sau đây là các phương pháp đại biểu:
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
canStopScrolling = NO;
[self refreshCurrentSpeed];
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
canStopScrolling = YES;
NSLog(@"Did end dragging");
[self snapIfNeeded];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self refreshCurrentSpeed];
[self snapIfNeeded];
}
này hoạt động tốt hầu hết thời gian, ngoại trừ trong hai trường hợp: 1. Khi người dùng cuộn mà không cần nhả ngón tay của mình và cho phép di chuyển gần đúng lúc sau khi di chuyển, nó thường xuyên chụp vị trí của nó như nó được cho là, nhưng rất nhiều lần, thì không. Nó thường mất một vài nỗ lực để làm cho nó xảy ra. Giá trị Odd cho thời gian (rất thấp) và/hoặc khoảng cách (khá cao) xuất hiện ở bản phát hành, gây ra một giá trị tốc độ cao trong khi scrollView là, trong thực tế, gần như hoặc hoàn toàn văn phòng phẩm. 2. Khi người dùng chạm vào scrollview để dừng chuyển động của nó, có vẻ như scrollview đặt contentOffset
thành vị trí trước đó của nó. Dịch chuyển dịch này dẫn đến giá trị tốc độ rất cao. Điều này có thể được cố định bằng cách kiểm tra nếu đồng bằng trước đó là currentDelta * -1, nhưng tôi muốn một giải pháp ổn định hơn.
Tôi đã thử sử dụng didEndDecelerating
, nhưng khi trục trặc xảy ra, nó không được gọi. Điều này có thể khẳng định rằng nó đã dừng lại. Dường như không có phương thức ủy nhiệm nào được gọi khi scrollview ngừng di chuyển hoàn toàn.
Nếu bạn muốn xem các trục trặc cho mình, sau đây là một số mã để điền vào scrollview với các tab:
@interface UIScrollView <UIScrollViewDelegate>
{
bool canStopScrolling;
float prevOffset;
float deltaOffset; //remembered for debug purposes
NSTimeInterval prevTime;
NSTimeInterval deltaTime; //remembered for debug purposes
float currentSpeed;
}
-(void)stopMoving;
-(void)snapIfNeeded;
-(void)refreshCurrentSpeed;
@end
@implementation TabScrollView
-(id) init
{
self = [super init];
if(self)
{
self.delegate = self;
self.frame = CGRectMake(0.0f,0.0f,320.0f,40.0f);
self.backgroundColor = [UIColor grayColor];
float tabWidth = self.frame.size.width/3;
self.contentSize = CGSizeMake(100*tabWidth, 40.0f);
for(int i=0; i<100;i++)
{
UIView *view = [[UIView alloc] init];
view.frame = CGRectMake(i*tabWidth,0.0f,tabWidth,40.0f);
view.backgroundColor = [UIColor colorWithWhite:(float)(i%2) alpha:1.0f];
[self addSubview:view];
}
}
return self;
}
@end
Một phiên bản ngắn hơn của câu hỏi này: làm thế nào để biết khi nào scrollview ngừng di chuyển? didEndDecelerating:
không được gọi khi bạn thả nó cố định, didEndDragging:
xảy ra rất nhiều trong quá trình cuộn và kiểm tra tốc độ không đáng tin cậy do 'nhảy' kỳ lạ này đặt tốc độ thành một cái gì đó ngẫu nhiên.
Bạn có thể kết hợp 'didEndDragging' với sự kiện chạm để khi người dùng chạm vào chế độ xem bạn đặt cờ và đặt lại khi họ xóa ngón tay của họ. Sau đó, miễn là cờ được đặt, bạn không chạy logic có liên quan trong 'didEndDragging:'. – FreeAsInBeer
Cảm ơn bạn đã phản hồi. Tuy nhiên, tôi không chắc chắn về lá cờ mà bạn đề cập đến. Nó xuất hiện với tôi rằng bạn có nghĩa là cờ cho thấy khi scrollview đã được phát hành một lần, nhưng tôi không thể tìm ra cách đó sẽ hữu ích, xem xét người dùng phát hành scrollview nhiều lần trong khi di chuyển, hoặc chỉ ở một điểm tĩnh mà không có nhấc ngón tay lên. – Aberrant