2013-02-16 2 views
66

У меня уже есть 5 UIScrollView в моем приложении, которое загружает несколько файлов .xib. Теперь мы хотим использовать UIRefreshControl. Они построены для использования с UITableViewControllers (по ссылке класса UIRefreshControl). Я не хочу повторять, как работают все 5 UIScrollView. Я уже пытался использовать UIRefreshControl в моих UIScrollView, и он работает как ожидалось, за исключением нескольких вещей.Могу ли я использовать UIRefreshControl в UIScrollView?

  1. Сразу после обновления изображения превращается в загрузчик, то UIScrollView спрыгивает около 10 пикселей, что только не бывает, когда я очень осторожно, чтобы перетащить UIScrollview вниз очень медленно.

  2. Когда я прокручиваю вниз и запускаю перезагрузку, отпустите 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?

Thank you !!!

+1

+1 за открытие, что вы даже можете сделать это. Но у меня проблемы с воспроизведением любого симптома. Я замечаю совершенно другую проблему, что 'attribitedTitle' появляется в неподходящем месте при первом отключении, чтобы обновить, если я явно не установил начальный' attributedTitle' (например, что-то вроде «Pull to refresh»), когда я впервые создаю обновление контроль. Итак, пара вопросов: 1. Вы инициализируете 'attributedTitle' что-либо во время этого первоначального создания? Кроме того, 2. Используете ли вы автоматический макет? 3. Вы делаете что-либо еще с помощью каких-либо методов 'UIScrollViewDelegate'? – Rob

ответ

86

Я получил 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, и теперь я добавил к нему некоторый текст (т. Е. «Pull to Refresh»), и ему нужно вернуться в основной поток, чтобы обновить этот текст.

Обновленный ответ.

+3

Возможно, вы захотите поместить ваш 'endRefreshing' в блок главной очереди, поскольку это метод пользовательского интерфейса. –

+0

Я так и думал, и мое первое сообщение включало извлечение основного потока, но это не вызывает никаких ошибок или сбоев. – Padin215

+0

Это решение работает для меня. Тем не менее, на мой взгляд, на экране работает все, что у меня есть. Есть ли способ добраться до моего представления? – Salx

-1

Вы можете просто создать экземпляр элемента управления обновлением и добавить его в верхней части прокрутки. то в методах делегатов вы настраиваете свое поведение на свои требования.

+0

Если вы прочитали мой вопрос, это то, что я сделал. Вы делаете это по-другому? – KKendall

9

Вот как вы это делаете в 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(); 
     }); 
    }); 
} 
+0

Большое спасибо. Прекрасно работает! Я использовал его в WebView следующим образом: 'webView.ScrollView.AddSubview (refresh);' –

34

Добавление к выше ответов, в некоторых ситуациях вы не можете установить contentSize (с помощью автоматической раскладки возможно?) Или высота contentSize составляет меньше или равна высоте в UIScrollView. В этих случаях UIRefreshControl не будет работать, потому что UIScrollView не будет отскакивать.

Чтобы исправить это установить свойство alwaysBounceVertical в ИСТИНА.

+1

Я столкнулся с такой же проблемой, следуя приведенному выше ответу. Однако, когда я сохранял alwaysBounceVertical до TRUE, он работал хорошо. Спасибо друг. – Noundla

+0

спасибо. Я думал, что я единственный, у кого есть эта проблема. – MetaSnarf

+0

Не работал для меня. – mythicalcoder

1

I производства UIRefreshControl исправно работает внутри UIScrollView.Я унаследовал UIScrollView, блокированное изменение contentInset и перекрытую contentOffset сеттер:

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) 
      } 
     } 
    } 
} 
+1

Это решение казалось перспективным сначала, но у него был (необъяснимый?) Побочный эффект, что мой просмотр прокрутки не ответил на взаимодействие пользователя в течение нескольких секунд после загрузки представления. – fwielstra

2

Для выпуска конкура, Tim Norman's answer решает ее.

Вот быстрая версия, если вы используете 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) 
      } 
     } 
    } 
} 
9

Если и когда вы достаточно удачливы, чтобы быть поддержкой IOS 10+, теперь вы можете просто установить refreshControl в UIScrollView. Это работает так же, как ранее существовавший refreshControl на UITableView.

1

Как это сделать в 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() 
} 
Смежные вопросы