Pull to refresh

Comments 19

Вообще говоря UIRefreshControl предназначен только для работы в связке с UITableViewController. То, что он работает и при простом добавлении в иерархию UITableView – счастливое стечение обстоятельств. Например в iOS6/7 в такой конфигурации (просто subview UITableVIew) возникали проблемы с анимациями. А у вас не возникают?
Note: Because the refresh control is specifically designed for use in a table view that's managed by a table view controller, using it in a different context can result in undefined behavior.
Пока не возникали, по крайней мере в двух несвязанных приложениях ничего такого не было (сравнил с UITableViewController, анимация работает идентично)
обратите внимание на спиннер. Он тоже тормозит. Есть вероятность, что нечто сетевое или базаданное выполняется в UI треде, поэтому тормозит весь UI. Если это так — это проблема не UIRefreshControl.

Вообще можно github.com/samvermette/SVPullToRefresh. Он к UIScrollView цепляется.
Нет, дело именно в том, что UIRefreshControl неправильно инициализируется. Немного покопавшись в runtime легко убедиться, что UITableViewController при его инциализации дополнительно привязывает UIRefreshControl к UITableView – у таблицы вызывается приватный метод:

- (void)_setRefreshControl:(UIRefreshControl *)obj;

Впоследствии UITableView использует эту связь с UIRefreshControl – как раз для вычисления правильного contentInset при овер-скроллинге.
Точно, есть такой прыжок, действительно
Можно ведь делать UITableController, которому присваивать в качестве tableView вашу таблицу, а в качестве refreshControl собственно UIRefreshControl.
Часто нет возможности (или желания) наследовать свой контроллер от UITableViewController. Можно конечно создавать временный экземпляр UITableViewController – только для того, чтобы правильно инициализировать UIRefreshControl для своей таблицы. Или просто использовать приватные API, чтобы воспроизвести поведение UITableViewController при инициализации. О «радиусе кривизны» таких решений можно спорить – спасибо Apple за «классный» API.
Если поразмышлять, то при использовании UITableView не так много ситуаций когда UIViewController будет предпочтительнее UITableViewController (если все необходимые дополнительные элементы размещать на tableHeaderView и tableFooterView). Практически, если в каком-либо виде нужна UITableView, то изначально лучше использовать UITableViewController, и не придется думать о «радиусе кривизны»
Dreddik, насколько я понял, имел ввиду не наследование, а просто создание временного UITableViewController. Это фиксит проблему с «прыжком» из-за неправильной инициализации о которой Вы говорили ( omaksim )
К сожалению, конкретно в Swift не силен, но на Xamarin фикс выглядит так:

    [Register ("MyViewController")]
    partial class MyViewController
    {
        [Outlet]
        public UITableView myTableView { get; set; }

        // ...
    }

    public partial class MyViewController : UIViewController
    {
        public UIRefreshControl myRefreshControl { get; set; }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // ...

            this.myRefreshControl = new UIRefreshControl();
            this.myRefreshControl.AttributedTitle = new NSAttributedString("Обновляем...");
            this.myRefreshControl.AddTarget(this, new ObjCRuntime.Selector("RefreshSource"), UIControlEvent.ValueChanged);

            #region Fix the Jump problem
            UITableViewController tableViewController = new UITableViewController();
            tableViewController.TableView = this.myTableView;
            tableViewController.RefreshControl = this.myRefreshControl;
            #endregion

            #region Fix the unwanted first showing
            this.myRefreshControl.BeginRefreshing();
            this.myRefreshControl.EndRefreshing();
            #endregion

            // ...
        }

        [Export("RefreshSource")]
        private async void RefreshSource()
        {
            #region Edit source data
            await Task.Run(() =>
                {
                    Thread.Sleep(3000);
                });
            #endregion

            this.myTableView.ReloadData();
            this.myRefreshControl.EndRefreshing();
        }
    }
а еще счастливое стечение обстоятельств работает с UICollectionView
Было бы просто отлично, если бы каждый кто реализовывал infinite scrolling ещё и реализовал кнопочку по его отключению…
Если я все правильно понял, то у Вас вот здесь ошибка

let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestSwiftCell")
        
        cell.text = "\(text) \(indexPath.row)"
        cell.detailTextLabel.text = "Hi, \(indexPath.row)"
        cell.detailTextLabel.textColor = UIColor.purpleColor()
        
        return cell

Вы каждый раз создаете ячейку для таблицы, игнорируя механизм переиспользования ячеек UITableView. Из-за этого скролл talbeView может заметно подтормаживать, лучше поправить, а то наверняка новички, изучающие Swift, наткнутся на эту статью и потащут это к себе в проект.
Привожу корректный код:
       var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as? UITableViewCell;
        if  (!tableViewCell){
            tableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: CellReuseId);
            tableViewCell.detailTextLabel.textColor = UIColor.purpleColor()
        }
        tableViewCell.text = "\(text) \(indexPath.row)"
        tableViewCell.detailTextLabel.text = "Hi, \(indexPath.row)"
        return tableViewCell;

Где CellReuseId некая строка идентификатор
let CellReuseId = "Row";
блин, не верно.
там где идет обращение к свойствам tableViewCell нужно добавить!
т.е.
tableViewCell!.text =

вот ничерта не читаем этот свифт…
Попробовал разные варианты, но такой код так и не заработал, внутрь if не заходит. Посмотрел, что возвращает dequeueReusableCellWithIdentifier (возвращает nil), по идее должен работать такой код

       var cell = tableView.dequeueReusableCellWithIdentifier("MyTestSwiftCell") as UITableViewCell
        if  (cell == nil){
            cell.detailTextLabel.textColor = UIColor.purpleColor()
            cell.text = "\(text) \(indexPath.row)"
            cell.detailTextLabel.text = "Hi, \(indexPath.row)"
        }
        return  cell


Но dequeueReusableCellWithIdentifier никогда не возвращает nil, даже если делать custom ячейки. Чтобы заставить его работать, например, можно использовать такую проверку в случае с Subtitle (detailTextLabel.text по умолчанию содержит текст «Subtitle»)

if ( cell.detailTextLabel.text == "Subtitle" ) 

или, если добавляется картинка, то
if ( cell.imageView.image == nil )

Еще тут возникает трудность с pull to refresh, надо учесть, что ячейки при таком условии не будут обновлены, потому что будут использоваться уже созданные
ох, извините, я не указал. этот код работает для xib. в сторибоардах же, apple побеспокоилась и за нас (спасибо ей) и под капотом сделала часть кода, который мы раньше писали.
метод dequeueReusableCellWithIdentifier сам создает ячейку, если ее нет в кэше.
финальный вариант

       var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as? UITableViewCell;
         tableViewCell!.detailTextLabel.textColor = UIColor.purpleColor()
        tableViewCell!.text = "\(text) \(indexPath.row)"
        tableViewCell!.detailTextLabel.text = "Hi, \(indexPath.row)"
        return tableViewCell;

и все там должно перезагружаться, если нет — то Вы что-то напутали. залейте в гит проект, посмотрим :)
Да, в случае с сторибордами так и есть. Так же проверил этот код различными способами, и он, в итоге, ничем не отличается от более читаемого варианта
        var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as UITableViewCell
        tableViewCell.detailTextLabel.textColor = UIColor.purpleColor()
        tableViewCell.text = "\(text) \(indexPath.row)"
        tableViewCell.detailTextLabel.text = "Hi, \(indexPath.row)"
        return tableViewCell
А есть какое-либо стандартное решение сделать pull to refresh внизу таблицы?
Only those users with full accounts are able to leave comments. Log in, please.