Ich habe bereits ungefähr 5 UIScrollView
in meiner App, die alle mehrere .xib
Dateien laden . Wir wollen jetzt a verwenden UIRefreshControl
. Sie sind für die Verwendung mit UITableViewControllern (gemäß UIRefreshControl-Klassenreferenz) erstellt. Ich möchte nicht wiederholen, wie alle 5 UIScrollView
funktionieren. Ich habe bereits versucht, das UIRefreshControl
in meinem zu verwenden UIScrollView
, und es funktioniert wie erwartet, bis auf ein paar Dinge.
Kurz nachdem sich das Aktualisierungsbild in den Loader verwandelt hat,
UIScrollView
springt das Bild um etwa 10 Pixel nach unten, was nur dann nicht der Fall ist, wenn ich sehr vorsichtig bin, das BildUIScrollview
sehr langsam nach unten zu ziehen .Als ich nach unten scrollen und den Reload initiieren, dann lassen Sie die gehen von
UIScrollView
derUIScrollView
ich die los wo ich sie loslasse. Nach dem NachladenUIScrollView
springt das Gerät ohne Animation nach oben.
Hier ist mein Code:
-(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];
}
Gibt es eine Möglichkeit, eine Menge Zeit zu sparen und eine zu verwenden UIRefreshControl
in a zu verwenden UIScrollView
?
Dankeschön!!!
quelle
attributedTitle
beim ersten Herunterziehen zum Aktualisieren an der falschen Stelle angezeigt wird, es sei denn, ich habeattributedTitle
beim ersten Erstellen des Aktualisierungssteuerelements explizit die Initiale festgelegt (z. B. "Zum Aktualisieren ziehen"). Also ein paar Fragen: 1. Initialisieren Sie dasattributedTitle
während dieser ersten Erstellung auf irgendetwas? Auch 2. Verwenden Sie das automatische Layout? 3. Machst du noch etwas mit irgendwelchenUIScrollViewDelegate
Methoden?Antworten:
Seit iOS 10 verfügt UIScrollView bereits über eine refreshControl-Eigenschaft . Dieses refreshControl wird angezeigt, wenn Sie ein UIRefereshControl erstellen und dieser Eigenschaft zuweisen.
Es gibt keine Notwendigkeit , UIRefereshControl als Subview mehr hinzuzufügen.
func configureRefreshControl () { // Add the refresh control to your UIScrollView object. myScrollingView.refreshControl = UIRefreshControl() myScrollingView.refreshControl?.addTarget(self, action: #selector(handleRefreshControl), for: .valueChanged) } @objc func handleRefreshControl() { // Update your content… // Dismiss the refresh control. DispatchQueue.main.async { self.myScrollingView.refreshControl?.endRefreshing() } }
Code und Zitat von https://developer.apple.com/documentation/uikit/uirefreshcontrol
quelle
Ich muss
UIRefreshControl
mit einem arbeitenUIScrollView
:- (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"); }); }); }
Die Datenaktualisierung muss in einem separaten Thread durchgeführt werden, da sonst der Hauptthread (mit dem die Benutzeroberfläche die Benutzeroberfläche aktualisiert) gesperrt wird. Während der Haupt-Thread mit dem Aktualisieren der Daten beschäftigt ist, ist die Benutzeroberfläche ebenfalls gesperrt oder eingefroren, und Sie sehen nie die glatten Animationen oder den Spinner.
EDIT: ok, ich mache das gleiche wie OP und habe jetzt Text hinzugefügt (dh "Zum Aktualisieren ziehen") und es muss wieder auf den Haupt-Thread zurückgegriffen werden, um diesen Text zu aktualisieren.
Antwort aktualisiert.
quelle
endRefreshing
in einen Hauptwarteschlangenblock stellen wollen , da es sich um eine UI-Methode handelt.In einigen Situationen können Sie die contentSize nicht festlegen (möglicherweise mithilfe des automatischen Layouts?), Oder die Höhe der contentSize ist kleiner oder gleich der Höhe der UIScrollView. In diesen Fällen funktioniert das UIRefreshControl nicht, da das UIScrollView nicht abprallt.
Um dies zu beheben, setzen Sie die Eigenschaft alwaysBounceVertical auf TRUE .
quelle
scrollView.bounces = true
!Falls und wenn Sie Glück haben , zu unterstützen iOS 10+ sind, können Sie jetzt einfach das Set
refreshControl
derUIScrollView
. Dies funktioniert auf die gleiche Art und Weise wie die zuvor bestehendenrefreshControl
aufUITableView
.quelle
So machen Sie das in C # / Monotouch. Ich kann nirgendwo Beispiele für C # finden, also hier ist es .. Danke 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 (); }); }); }
quelle
webView.ScrollView.AddSubview (refresh);
Für das Thema Springen die Antwort von Tim Norman löst .
Hier ist die schnelle Version, wenn Sie swift2 verwenden:
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) } } } }
quelle
Wie es in Swift 3 geht:
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() }
quelle
Ich habe die
UIRefreshControl
Arbeit im Inneren richtig gemachtUIScrollView
. Ich habe geerbtUIScrollView
, das Ändern von contentInset blockiert und den contentOffset-Setter überschrieben: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) } } } }
quelle
Überschreiben Sie contentInset für das Jumping-Problem nur vor iOS 9. Ich habe nur versucht, ein Sprungproblem zu vermeiden:
let scrollView = UIScrollView() let refresh = UIRefreshControl() // scrollView.refreshControl = UIRefreshControl() this will cause the jump issue refresh.addTarget(self, action: #selector(handleRefreshControl), for: .valueChanged) scrollView.alwaysBounceVertical = true //just add refreshControl and send it to back will avoid jump issue scrollView.addSubview(refresh) scrollView.sendSubviewToBack(refresh)
funktioniert unter iOS 9 10 11 und so weiter, und ich hoffe, dass sie (Apple) das Problem nur beheben.
quelle
Ab iOS 10 verfügt eine UIScrollView über eine refreshControl-Eigenschaft, die Sie auf ein UIRefreshControl festlegen können. Wie immer müssen Sie den Rahmen des Steuerelements nicht verwalten. Konfigurieren Sie einfach das Steuerelement, legen Sie die Zielaktion für das valueChanged-Ereignis fest und weisen Sie es der Eigenschaft zu.
Unabhängig davon, ob Sie eine einfache Bildlaufansicht, eine Tabellenansicht oder eine Sammlungsansicht verwenden, sind die Schritte zum Erstellen eines Aktualisierungssteuerelements dieselben.
if #available(iOS 10.0, *) { let refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh") refreshControl.addTarget(self, action: #selector(refreshOptions(sender:)), for: .valueChanged) scrollView.refreshControl = refreshControl } @objc private func refreshOptions(sender: UIRefreshControl) { // Perform actions to refresh the content // ... // and then dismiss the control sender.endRefreshing() }
quelle
Sie können einfach eine Instanz des Aktualisierungssteuerelements erstellen und oben in der Bildlaufansicht hinzufügen. Anschließend passen Sie in den Delegate-Methoden das Verhalten an Ihre Anforderungen an.
quelle