Могу ли я использовать UIRefreshControl в UIScrollView?
у меня около 5 UIScrollView
уже в моем приложении, которое все загружает несколько .xib
файлы. Теперь мы хотим использовать UIRefreshControl
. Они построены для использования с UITableViewControllers (для ссылки на класс UIRefreshControl). Я не хочу повторять, как все 5 UIScrollView
работа. Я уже пытался использовать UIRefreshControl
в своем UIScrollView
, и он работает так, как ожидалось, за исключением нескольких вещей.
сразу после того, как изображение обновления превращается в загрузчик,
UIScrollView
прыгает вниз около 10 пикселей, чего только не происходит, когда я очень осторожно перетаскиваюUIScrollview
вниз очень медленно.когда я прокручиваю вниз и инициирую перезагрузку, затем отпустите
UIScrollView
наUIScrollView
остается там, где я его отпустил. После его завершения перезагрузкиUIScrollView
прыгает вверх без анимации.
вот мой код:
-(void)viewDidLoad
{
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[myScrollView addSubview:refreshControl];
}
-(void)handleRefresh:(UIRefreshControl *)refresh {
// Reload my data
[refresh endRefreshing];
}
есть ли способ сэкономить кучу времени и использовать UIRefreshControl
в UIScrollView
?
Спасибо!!!
8 ответов
у меня есть UIRefreshControl
на работу с UIScrollView
:
- (void)viewDidLoad
{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
scrollView.userInteractionEnabled = TRUE;
scrollView.scrollEnabled = TRUE;
scrollView.backgroundColor = [UIColor whiteColor];
scrollView.contentSize = CGSizeMake(500, 1000);
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(testRefresh:) forControlEvents:UIControlEventValueChanged];
[scrollView addSubview:refreshControl];
[self.view addSubview:scrollView];
}
- (void)testRefresh:(UIRefreshControl *)refreshControl
{
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:@"Refreshing data..."];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:3];//for 3 seconds, prevent scrollview from bouncing back down (which would cover up the refresh view immediately and stop the user from even seeing the refresh text / animation)
dispatch_async(dispatch_get_main_queue(), ^{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MMM d, h:mm a"];
NSString *lastUpdate = [NSString stringWithFormat:@"Last updated on %@", [formatter stringFromDate:[NSDate date]]];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:lastUpdate];
[refreshControl endRefreshing];
NSLog(@"refresh end");
});
});
}
необходимо выполнить обновление данных в отдельном потоке, или он заблокирует основной поток (который пользовательский интерфейс использует для обновления пользовательского интерфейса). Таким образом, пока основной поток занят обновлением данных, пользовательский интерфейс также заблокирован или заморожен, и вы никогда не увидите плавную анимацию или счетчик.
EDIT: хорошо, я делаю то же самое, что и OP, и теперь я добавил к нему текст (т. е. "потяните, чтобы обновить"), и ему нужно вернуться к основному поток для обновления этого текста.
обновленный ответ.
добавление к приведенным выше ответам, в некоторых ситуациях вы не можете установить contentSize (возможно, используя auto layout?) или высота contentSize меньше или равна высоте UIScrollView. В этих случаях UIRefreshControl не будет работать, потому что UIScrollView не будет отскакивать.
чтобы исправить это, установите свойство alwaysBounceVertical до правда.
если и когда вам посчастливилось поддерживать iOS 10+, Теперь вы можете просто установить refreshControl
на UIScrollView
. Это работает так же, как и ранее существующий refreshControl
on UITableView
.
вот как вы это делаете в C# / Monotouch. Я не могу найти образцы для C# в любом месте, так что вот он.. Спасибо Log139!
public override void ViewDidLoad ()
{
//Create a scrollview object
UIScrollView MainScrollView = new UIScrollView(new RectangleF (0, 0, 500, 600));
//set the content size bigger so that it will bounce
MainScrollView.ContentSize = new SizeF(500,650);
// initialise and set the refresh class variable
refresh = new UIRefreshControl();
refresh.AddTarget(RefreshEventHandler,UIControlEvent.ValueChanged);
MainScrollView.AddSubview (refresh);
}
private void RefreshEventHandler (object obj, EventArgs args)
{
System.Threading.ThreadPool.QueueUserWorkItem ((callback) => {
InvokeOnMainThread (delegate() {
System.Threading.Thread.Sleep (3000);
refresh.EndRefreshing ();
});
});
}
для прыжков вопрос,ответ Тима Нормана решает ее.
вот версия swift, если вы используете swift2:
import UIKit
class NoJumpRefreshScrollView: UIScrollView {
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
override var contentInset:UIEdgeInsets {
willSet {
if self.tracking {
let diff = newValue.top - self.contentInset.top;
var translation = self.panGestureRecognizer.translationInView(self)
translation.y -= diff * 3.0 / 2.0
self.panGestureRecognizer.setTranslation(translation, inView: self)
}
}
}
}
Как это сделать в Swift 3:
override func viewDidLoad() {
super.viewDidLoad()
let scroll = UIScrollView()
scroll.isScrollEnabled = true
view.addSubview(scroll)
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(pullToRefresh(_:)), for: .valueChanged)
scroll.addSubview(refreshControl)
}
func pullToRefresh(_ refreshControl: UIRefreshControl) {
// Update your conntent here
refreshControl.endRefreshing()
}
Я UIRefreshControl
работает должным образом внутри UIScrollView
. Я унаследовал UIScrollView
, заблокировано изменение contentInset и переопределено contentoffset setter:
class ScrollViewForRefreshControl : UIScrollView {
override var contentOffset : CGPoint {
get {return super.contentOffset }
set {
if newValue.y < -_contentInset.top || _contentInset.top == 0 {
super.contentOffset = newValue
}
}
}
private var _contentInset = UIEdgeInsetsZero
override var contentInset : UIEdgeInsets {
get { return _contentInset}
set {
_contentInset = newValue
if newValue.top == 0 && contentOffset.y < 0 {
self.setContentOffset(CGPointZero, animated: true)
}
}
}
}
вы можете просто создать экземпляр элемента управления обновить и добавить его в верхней части прокрутки. затем в методах делегата вы настраиваете его поведение в соответствии с вашими требованиями.