我可以在 UIScrollView 中使用 UIRefreshControl 吗?

我有大约5个 UIScrollView的已经在我的应用程序,所有加载多个 .xib文件。我们现在想使用 UIRefreshControl。构建它们是为了与 UITableViewController 一起使用(每个 UIRefreshControl 类引用)。我不想重做如何全部5 UIScrollView的工作。我已经尝试过在我的 UIScrollView中使用 UIRefreshControl,除了一些东西,它的工作方式和预期的一样。

  1. 就在刷新图像变成加载程序之后,UIScrollView跳下大约10像素,只有当我非常小心地非常缓慢地拖动 UIScrollview时才不会发生这种情况。

  2. 当我向下滚动并开始重新加载,然后放开 UIScrollViewUIScrollView停留在我让它去的地方。完成重新加载后,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

谢谢! ! !

44237 次浏览

您可以简单地创建刷新控件的实例并将其添加到滚动视图的顶部。然后,在委托方法中根据需求调整其行为。

我有一个 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");
});
});
}

需要在一个单独的线程上执行数据更新,否则将锁定主线程(用户界面用来更新用户界面)。因此,当主线程忙于更新数据时,UI 也会被锁定或冻结,你永远看不到平滑的动画或微调器。

编辑: 好的,我正在做同样的事情作为 OP,我现在已经添加了一些文本到它(即,“拉刷新”) ,它确实需要回到主线程来更新该文本。

最新答案。

Here is how you do this in C# / Monotouch. I cant find any samples for C# anywhere, so here it is.. Thanks 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 ();
});
});
}

添加到上述答案,在某些情况下,您不能设置 contentSize (也许使用自动布局?)ContentSize 的高度小于或等于 UIScrollView 的高度。在这些情况下,UIRefreshControl 将无法工作,因为 UIScrollView 不会反弹。

要修复此问题,请将属性 总是弹起垂直设置为 没错

我让 UIRefreshControlUIScrollView内部正常工作。我继承了 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)
}
}
}
}

对于跳跃问题,蒂姆 · 诺曼的回答解决了它。

如果你使用的是 Swift 2,这里有一个迅速的版本:

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

如果你有幸支持 iOS10 + ,你现在可以简单地设置 UIScrollViewrefreshControl。这与 UITableView上以前存在的 refreshControl的工作方式相同。

如何在 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()
}

对于跳转问题,覆盖 contentInset 只能在 iOS9之前解决。 我只是尝试了一种方法来避免跳跃的问题:

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)

可以在 iOS91011等操作系统上运行,我希望他们(苹果)能够解决这个问题。

由于 IOS10 UIScrollView 已经 具有 refshControl 属性。当您创建 UIRefereshControl 并将其分配给此属性时,将出现此刷新控件。

还有 不用了可以添加 UIRefereshControl 作为子视图。

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()
}
}

UIRefreshControl 对象是附加到任何 UIScrollView 对象的标准控件

代码和引用 https://developer.apple.com/documentation/uikit/uirefreshcontrol

从 iOS10开始,UIScrollView 具有一个可以设置为 UIRefreshControl 的 refshControl 属性。一如既往,您不需要管理控件的框架。只需配置控件,为 valueChanged 事件设置 target-action 并将其分配给属性。

无论您使用的是普通滚动视图、表视图还是集合视图,创建刷新控件的步骤都是相同的。

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()
}