Измените скорость setContentOffset: анимированный:?
Есть ли способ изменить скорость анимации при прокрутке UITableView
с помощью setContentOffset: анимированный:? Я хочу прокрутить его вверх, но медленно. Когда я пытаюсь сделать следующее, это заставляет нижние несколько ячеек исчезать до начала анимации (в частности, те, которые не будут видны при прокрутке):
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView setContentOffset:CGPointMake(0, 0)];
[UIView commitAnimations];
Любые другие способы решения этой проблемы? Существует закрытый метод _setContentOffsetAnimationDuration
, который работает, но я не хочу отклоняться из хранилища приложений.
Ответы
Ответ 1
Нет прямого способа сделать это и не делать так, как вы его написали. Единственный способ, которым я могу это сделать, - это сделать движение/анимацию самостоятельно.
Например, перемещение 1px каждые 1/10 секунды должно имитировать очень медленную анимацию прокрутки. (Поскольку его линейная анимационная математика очень проста!)
Если вы хотите получить более реалистичный или фантастический и симулировать легкий и легкий эффект, вам потребуются математические вычисления для расчета пути беззерцания, чтобы вы могли узнать точное положение за каждые 1/10 секунды, например
По крайней мере, первый подход не должен быть таким сложным.
Просто используйте или -performSelector:withObject:afterDelay or NSTimers
с помощью
-[UIScrollView setContentOffset:(CGPoint*)];`
Надеюсь, что это поможет
Ответ 2
[UIView animateWithDuration:2.0 animations:^{
scrollView.contentOffset = CGPointMake(x, y);
}];
Он работает.
Ответ 3
Я принял nacho4d ответ и внедрил код, поэтому я подумал, что было бы полезно, если бы другие люди пришли к этому вопросу, чтобы увидеть рабочий код:
Я добавил переменные-члены в мой класс:
CGPoint startOffset;
CGPoint destinationOffset;
NSDate *startTime;
NSTimer *timer;
и свойства:
@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSTimer *timer;
и обратный вызов таймера:
- (void) animateScroll:(NSTimer *)timerParam
{
const NSTimeInterval duration = 0.2;
NSTimeInterval timeRunning = -[startTime timeIntervalSinceNow];
if (timeRunning >= duration)
{
[self setContentOffset:destinationOffset animated:NO];
[timer invalidate];
timer = nil;
return;
}
CGPoint offset = [self contentOffset];
offset.x = startOffset.x +
(destinationOffset.x - startOffset.x) * timeRunning / duration;
[self setContentOffset:offset animated:NO];
}
то
- (void) doAnimatedScrollTo:(CGPoint)offset
{
self.startTime = [NSDate date];
startOffset = self.contentOffset;
destinationOffset = offset;
if (!timer)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(animateScroll:)
userInfo:nil
repeats:YES];
}
}
вам также понадобится очистка таймера в методе dealloc. Поскольку таймер сохранит ссылку на целевую (self), а self имеет ссылку на таймер, некоторый код очистки для отмены/уничтожения таймера в viewWillDisappear также может быть хорошей идеей.
Любые комментарии к вышеизложенному или предложения по улучшению были бы очень желанными, но он очень хорошо работает со мной и решает другие проблемы, которые у меня возникли с помощью setContentOffset: animated:.
Ответ 4
Мне любопытно, нашли ли вы решение проблемы. Моя первая идея заключалась в использовании вызова animateWithDuration:animations:
с настройкой блока contentOffset:
[UIView animateWithDuration:2.0 animations:^{
scrollView.contentOffset = CGPointMake(x, y);
}];
Побочные эффекты
Хотя это работает для простых примеров, оно также имеет очень нежелательные побочные эффекты. В отличие от setContentOffset:animated:
все, что вы делаете в методах делегата, также анимируется, например, метод делегата scrollViewDidScroll:
.
Я прокручиваю черепичный scrollview с многоразовыми плитками. Это проверяется в scrollViewDidScroll:
. Когда они снова используются, они получают новую позицию в представлении прокрутки, но это становится анимированным, так что в этом представлении есть фрагменты, которые полностью анимируются. Выглядит круто, но совершенно бесполезно. Другим нежелательным побочным эффектом является то, что возможное тестовое тестирование фрагментов и мои ограничения просмотра прокрутки мгновенно оказываются бесполезными, потому что contentOffset уже находится на новой позиции, как только выполняется блок анимации. Это заставляет вещи появляться и исчезать, пока они все еще видны, относительно того, где они использовались для переключения только за пределы видимости прокрутки.
С setContentOffset:animated:
все это не так. Похоже, UIScrollView не использует ту же технику внутри.
Есть ли кто-нибудь с другим предложением для изменения скорости/продолжительности выполнения UIScrollView setContentOffset:animated:
?
Ответ 5
https://github.com/dominikhofmann/PRTween
подкласс UITableview
#import "PRTween.h"
@interface JPTableView : UITableView{
PRTweenOperation *activeTweenOperation;
}
- (void) doAnimatedScrollTo:(CGPoint)destinationOffset
{
CGPoint offset = [self contentOffset];
activeTweenOperation = [PRTweenCGPointLerp lerp:self property:@"contentOffset" from:offset to:destinationOffset duration:1.5];
}
Ответ 6
ЕСЛИ все, что вы пытаетесь сделать, это прокрутить прокрутку. Думаю, вы должны использовать прокрутку прямо к видимой. Я просто пробовал этот код
[UIView animateWithDuration:.7
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
CGRect scrollToFrame = CGRectMake(0, slide.frame.origin.y, slide.frame.size.width, slide.frame.size.height + kPaddingFromTop*2);
CGRect visibleFrame = CGRectMake(0, scrollView.contentOffset.y,
scrollView.frame.size.width, scrollView.frame.size.height);
if(!CGRectContainsRect(visibleFrame, slide.frame))
[self.scrollView scrollRectToVisible:scrollToFrame animated:FALSE];}];
и он прокручивает scrollview к местоположению, в котором я нуждаюсь, для любой продолжительности, на которую я его устанавливаю. Ключ устанавливает анимацию в false. Когда он был установлен в true, скорость анимации была значением по умолчанию, заданным методом
Ответ 7
Настройка смещения содержимого напрямую не помогла мне. Однако обертка setContentOffset(offset, animated: false)
внутри блока анимации сделала трюк.
UIView.animate(withDuration: 0.5, animations: {
self.tableView.setContentOffset(
CGPoint(x: 0, y: yOffset), animated: false)
})
Ответ 8
Для людей, у которых также есть проблемы с исчезающими элементами при прокрутке UITableView или UICollectionView, вы можете развернуть представление так, чтобы у нас было больше видимых элементов. Это решение не рекомендуется для ситуаций, когда вам нужно прокручивать большое расстояние или в ситуациях, когда пользователь может отменить анимацию. В приложении, в котором я сейчас работаю, мне нужно только позволить прокручивать представление фиксированной 100px.
NSInteger scrollTo = 100;
CGRect frame = self.collectionView.frame;
frame.size.height += scrollTo;
[self.collectionView setFrame:frame];
[UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
[self.collectionView setContentOffset:CGPointMake(0, scrollTo)];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
[self.collectionView setContentOffset:CGPointMake(0, 0)];
} completion:^(BOOL finished) {
CGRect frame = self.collectionView.frame;
frame.size.height -= scrollTo;
[self.collectionView setFrame:frame];
}];
}];
Ответ 9
Собственно ответ TK189 является частично правильным.
Чтобы добиться изменения анимированного контента в анимированном формате, с правильным повторным использованием ячеек компонентами UITableView и UICollectionView, вам просто нужно добавить вызов layoutIfNeeded внутри блока анимации:
[UIView animateWithDuration:2.0 animations:^{
tableView.contentOffset = CGPointMake(x, y);
[tableView layoutIfNeeded];
}];
Ответ 10
Вы можете просто использовать блочную анимацию для анимации скорости scrollview.
Сначала вычислите точку смещения, которую вы хотите прокрутить, а затем просто передайте это значение смещения, как здесь.....
[UIView animateWithDuration:1.2
delay:0.02
options:UIViewAnimationCurveLinear
animations:^{
[colorPaletteScrollView setContentOffset: offset ];
}
completion:^(BOOL finished)
{ NSLog(@"animate");
} ];
здесь colorPaletteScrollView - это мое собственное scrollview, а смещение - это пройденное значение.
этот код отлично работает для меня.
Ответ 11
Есть ли причина, по которой вы используете setContentOffset, а не scrollRectToVisible: анимированные:?
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
Я бы рекомендовал сделать это следующим образом:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 320, 0) animated:NO];
[UIView commitAnimations];
Если это не работает. Я все еще думаю, что вы должны попробовать.
Ответ 12
В Xcode 7.1 - Swift 2.0:
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
}
return true
}
ИЛИ
func textFieldShouldReturn(textField: UITextField) -> Bool {
if(textField.returnKeyType == UIReturnKeyType.Next) {
password.becomeFirstResponder()
}
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
}
textField.resignFirstResponder()
return true
}
Примечание: self.scrollView!.setContentOffset(CGPointZero, animated: true) может иметь разные позиции в зависимости от требования
Пример:
let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/2);
scrollView!.setContentOffset(scrollPoint, animated: true);
Ответ 13
Я хотел изменить contentOffSet таблицы, когда текстовое поле начинает редактировать.
Swift 3.0
func textFieldDidBeginEditing(_ textField: UITextField) {
DispatchQueue.main.async {
UIView.animate(withDuration: 0, animations: {
self.sampleTableView.contentOffset = CGPoint(x: 0, y: 0 - (self.sampleTableView.contentInset.top - 200 ))
})
}
}