2013-02-16 10 views
66

Ho circa 5 UIScrollView già nella mia app che caricano più file .xib. Ora vogliamo utilizzare uno UIRefreshControl. Sono costruiti per essere utilizzati con UITableViewControllers (per riferimento alla classe UIRefreshControl). Non voglio ripetere come funzionano tutti e 5 UIScrollView. Ho già provato a utilizzare lo UIRefreshControl nel mio UIScrollView e funziona come previsto, tranne alcune cose.Posso usare un UIRefreshControl in un UIScrollView?

  1. Subito dopo l'immagine di aggiornamento si trasforma nel caricatore, il UIScrollView salta giù circa 10 pixel, che solo non si verificano quando sono molto attento a trascinare il UIScrollview molto lentamente.

  2. Quando si scorre verso il basso e avviare la ricarica, quindi rilasciare il UIScrollView, il UIScrollView rimane dove ho lasciato andare. Al termine del caricamento, lo UIScrollView salta in alto senza animazione.

Ecco il mio codice:

-(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]; 
} 

C'è un modo per risparmiare un sacco di tempo e utilizzare un UIRefreshControl in un UIScrollView?

Grazie !!!

+1

+1 per scoprire che si può anche fare questo. Ma ho difficoltà a riprodurre entrambi i sintomi. Ho notato un problema completamente diverso che il 'attributoTitle' appare nel posto sbagliato la prima volta che faccio il pull down per aggiornare a meno che non imposti esplicitamente l'attributo' AttributoTitle' (ad es. A qualcosa come "Pull to refresh") quando creo l'aggiornamento controllo. Quindi, un paio di domande: 1. Stai inizializzando il 'attributoTitle 'a qualcosa durante questa creazione iniziale? Inoltre, 2. Stai usando il layout automatico? 3. Stai facendo qualcos'altro con i metodi 'UIScrollViewDelegate'? – Rob

risposta

86

ho avuto un UIRefreshControl di lavorare con un 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"); 
     }); 
    }); 
} 

necessità di fare l'aggiornamento dei dati in un thread separato o si blocca il thread principale (che l'interfaccia utente utilizza per aggiornare l'interfaccia utente). Quindi, mentre il thread principale è occupato ad aggiornare i dati, l'interfaccia utente è anche bloccata o bloccata e non si vedono mai le animazioni fluide o spinner.

EDIT: ok, sto facendo la stessa cosa di OP e ora ho aggiunto del testo (cioè "Pull to Refresh") e ha bisogno di tornare sul thread principale per aggiornarlo testo.

Risposta aggiornata.

+3

Probabilmente vorrete mettere il vostro 'endRefreshing' in un blocco di code principale, dato che si tratta di un metodo dell'interfaccia utente. –

+0

L'ho pensato anch'io e il mio primo post ha incluso il recupero del thread principale, ma questo non causa errori o arresti anomali. – Padin215

+0

Questa soluzione funziona per me. Tuttavia, lo spinner uirefreshcontrol è al di sopra di tutto a mio avviso. C'è un modo per arrivare a mostrarmi sotto la mia vista? – Salx

-1

È possibile semplicemente creare un'istanza del controllo di aggiornamento e aggiungerla nella parte superiore della vista di scorrimento. quindi, nei metodi delegati, adegui il suo comportamento alle tue esigenze.

+0

Se hai letto la mia domanda, è quello che ho fatto. Lo fai in un modo diverso? – KKendall

9

Ecco come si fa in C#/Monotouch. Non riesco a trovare alcun campione per C# ovunque, quindi eccolo .. Grazie 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

Grazie mille. Funziona alla grande! L'ho usato su una WebView come questa: 'webView.ScrollView.AddSubview (refresh);' –

34

aggiunta alle risposte di cui sopra, in alcune situazioni non è possibile impostare la contentSize (utilizzando il layout automatico forse?) O l'altezza del contentSize è minore o uguale all'altezza del UIScrollView. In questi casi, UIRefreshControl non funzionerà perché UIScrollView non rimbalzerà.

Per correggere questo impostare la proprietà alwaysBounceVertical a TRUE.

+1

Ho affrontato lo stesso problema seguendo la risposta di cui sopra. Tuttavia, quando ho mantenuto sempre il TrueCertical TRUE, ha funzionato bene. Grazie compagno. – Noundla

+0

Grazie. Pensavo di essere l'unico ad avere questo problema. – MetaSnarf

+0

Non ha funzionato per me. – mythicalcoder

1

Ho effettuato il lavoro UIRefreshControl correttamente all'interno di UIScrollView.Ho ereditato UIScrollView, bloccato cambio contentInset e overrided 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) 
      } 
     } 
    } 
} 
+1

Inizialmente questa soluzione sembrava promettente, ma aveva l'effetto collaterale (inspiegabile?) Che la mia vista di scorrimento non rispondeva all'interazione dell'utente per alcuni secondi dopo il caricamento della vista. – fwielstra

2

Per il rilascio di salto, Tim Norman's answer risolve.

ecco la versione rapida se si utilizza 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

Se e quando si ha la fortuna di essere di supporto iOS 10+, è ora possibile semplicemente impostare il refreshControl del UIScrollView. Funziona allo stesso modo del precedente refreshControl su UITableView.

1

Come fare a 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() 
}