iOS 7 UIRefreshControl tintColor не працює для початкового оновлення


75

Я намагаюся встановити tintColor на моєму UIRefreshControl (побудований на iOS 7). Я ввімкнув оновлення для tableViewController в раскадровці, а потім у своєму viewDidLoadметоді ViewController я зробив наступне:

[self.refreshControl setTintColor:[UIColor redColor]];

Отже, коли я натискаю на оновлення, колір елемента керування оновленням справді є червоним:

червоний

Я хочу, щоб моє подання автоматично оновлювалось, коли воно з’являється, тому я зробив:

- (void)viewDidAppear:(BOOL)animated{
    [self.refreshControl beginRefreshing];
}

Він не показував прядки, згідно з https://stackoverflow.com/a/16250679/1809736 , я додав

[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:NO];

змусити показати це. Це показує, але тепер повернуто до стандартного кольору:

введіть тут опис зображення

Якщо я спробую вручну потягнути для оновлення, він червоний.

Я спробував побудувати його на iOS6, і він працює як слід, так це помилка iOS7?

PS: це не проблема з тренажером, я спробував побудувати його на пристрої, та сама помилка.

PPS: Я створив приклад проекту, чи можете ви сказати мені, чи є у вас однакова помилка або проблема в моєму коді? Ось посилання: http://d.pr/f/pGrV

Дуже дякую !


6
UIRefreshControl - це баггі під iOS7. Я пропоную скористатися відкритим кодом або жити з помилками поки. Не забудьте відкрити звіт про помилку
Лео Натан

5
Це майже так, ніби у них закінчився час з iOS7. Є помилки і з ними UISearchViewController. Сподіваємось, майбутнє оновлення це виправить.
James

8
IOS 8 все ще має цю помилку ... дивно ...
Макістадор

2
Також iOS9. Хтось знайшов рішення?
Орен

5
Те саме на iOS 11 :(
Pranoy C

Відповіді:


54

Гей, просто натрапив на саме це питання.

Цікаво, що я виправив свій код, встановивши спочатку contentOffset, а потім викликавши beginRefreshing

if(self.tableView.contentOffset.y == 0){
    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
    [self.refreshControl beginRefreshing];
}

Можливо, ви захочете анімувати цей процес:

[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished) {
    [self.refreshControl beginRefreshing];
}];

Сподіваюся, це вам допоможе.

W


це іноді не спрацьовує, оскільки сенс у зміщенні таблиці полягає в тому, що в ньому є певний простір для компенсації, але лише після того, як ви зателефонуєте beginRefreshing ... якщо ви змістите його раніше, він не буде мати великого компенсації!
newton_guima

2
Працює за рекламою. Це дивно. Дякую :)
Влад Шпрейс

1
Дуже важливо викликати "beginRefreshing" після встановлення contentOffset! (принаймні на ios8)
Макістадор

1
Я затримався на цьому деякий час, але виявляється, я використовував [myTableView setContentOffset ... animated: ТАК]. Це не працювало для мене. Встановіть зміщення безпосередньо і замість цього використовуйте блок анімації UIView, як зазначено вище.
Рік Робертс,

Порядок дзвінків справді важливий. Дивна проблема, що заслуговує на коментар "// ??? ***" у документації до коду.
SayeedHussain

26

SWIFT РІШЕННЯ! Вставте такий код у viewDidLoad:

self.refreshControl.tintColor = UIColor.orangeColor()
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height)
self.refreshControl.beginRefreshing()

Свіфт 3.1

self.refreshControl.tintColor = UIColor.orange
self.tableView.contentOffset = CGPoint(x:0, y:-self.refreshControl.frame.size.height)
self.refreshControl.beginRefreshing()

1
Дякую, це вирішує деякі проблеми для мене при завантаженні з viewDidLoad. При кожному першому використанні контролер оновлення мав неправильну висоту та неправильний колір.
Роб

8

Відповідь @ william-george спрямувала мене у правильному напрямку, але давала дивні проблеми з анімацією авторозкладки.

Отже, ось версія, яка мені працювала:

- (void)programaticallyRefresh {
    // Hack necessary to keep UIRefreshControl's tintColor
    [self.scrollView setContentOffset:CGPointMake(0, -1.0f) animated:NO];
    [self.scrollView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
    [self.refreshControl beginRefreshing];
    [self refresh];
}

-refresh- метод, прив'язаний до UIRefreshControl.


6

Додайте розширення для UIResfreshControl.

extension UIRefreshControl {
    func beginRefreshingManually() {
        self.tintColor = UIColor.white
        if let scrollView = superview as? UIScrollView {
            scrollView.setContentOffset(CGPoint(x: 0, y:scrollView.contentOffset.y - frame.height), animated: false)
        }
        beginRefreshing()
    }
}

Порівняно з іншими рішеннями, це те, яке працювало і виглядало краще впровадженим. :) Спасибі Сефа і чудовий фокус.
Бруно Рейс Портела

4

Жодна з цих відповідей не працює для мене правильно на iOS8, найближчою є відповідь @ jpsim, але це все одно залишило непривабливий елемент керування чорним оновленням під час затухання анімації (воно перехрещується між чорним і під час анімації ).

Рішення, яке працювало для мене, було поставити це відразу після створення елемента керування оновлення в моєму viewDidLoad:

self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl.tintColor = [UIColor whiteColor];
...
self.refreshControlHeight = self.refreshControl.frame.size.height;
[self.tableView setContentOffset:CGPointMake(0, -1) animated:NO];
[self.tableView setContentOffset:CGPointMake(0, 0) animated:NO];

Потім програмно показати UIRefreshControl:

[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControlHeight) animated:YES];
[self.refreshControl beginRefreshing];

Мені довелося зберігати висоту елемента керування оновленням, оскільки, хоча він був встановлений для першого виклику, наступні дзвінки мали б висоту 0.


1
Дякую, не могли б ви просвітити мене тим фактом, що це працює лише з -1? Я не люблю магічні цифри ...
Рік ван дер Лінде,

Це не магічне число, він просто змінює зміщений вміст на незначну суму, а потім змінює його назад.
Еран Голдін,

3

Рішення для проблеми tintColor: додайте це в viewDidLoad

[self.refreshControl setTintColor:[UIColor whiteColor]];
[self.refreshControl tintColorDidChange];

Тепер у вас є білий індикатор при дзвінку beginRefresh вручну.


3

SWIFT:

Я використовую Swift та> iOS8. Більшість описаних обхідних шляхів для мене не працювали. Ось як я це почав працювати:

In viewDidLoad:

customRefreshControl.tintColor = UIColor.clearColor()

Далі не повинно бути всередині viewDidLoad. Я поміщаю його в додаткову функцію, яка викликається кожен раз, коли я оновлюю tableView:

private func startRefreshControlAnimation() {

    self.tableView.setContentOffset(CGPointMake(0, -self.customRefreshControl.frame.size.height), animated: true)

    CATransaction.begin()
    self.customRefreshControl.beginRefreshing()
    CATransaction.commit()

}

3

Я поєднав деякі попередні відповіді. Це працює для мене на iOS 9 та Swift 2:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let contentOffset = self.tableView.contentOffset.y
    UIView.animateWithDuration(0, delay: 0, options: .BeginFromCurrentState, animations: {
        print(self.tableView.contentOffset.y)
            self.tableView.setContentOffset(CGPointMake(0, -self.refreshControl.frame.size.height), animated: false)
        }, completion: { finished in
            self.refreshControl.beginRefreshing()
            self.tableView.setContentOffset(CGPointMake(0, contentOffset/2-self.refreshControl.frame.size.height), animated: true)
            self.refresh() // Code that refresh table data
    })        
}

2

Я розробляю для iOS за допомогою Xamarin (C #) і натрапив на ту ж проблему.

Я встановив забарвлення проблему, шляхом установки AttributedTitleз RefreshControl:

private CGPoint originalOffset;
...
public override void ViewDidLoad ()
{
     base.ViewDidLoad ();
     ...
     originalOffset = TableView.ContentOffset; // Store the original offset of the table view
     RefreshControl = new UIRefreshControl (){ TintColor = UIColor.Red };
     RefreshControl.ValueChanged += ((s,e) => { Update (this, EventArgs.Empty); });
     // Hack so the TintColor of the RefreshControl will be properly set
     RefreshControl.AttributedTitle = new NSAttributedString ("Fetching data");
}

Мій метод оновлення виглядає так:

private async void Update(object sender, EventArgs args)
{
     try {
          TableView.UserInteractionEnabled = false;
          // I find -100 to be a big enough offset
          TableView.SetContentOffset (new CGPoint (0, -100), true);
          RefreshControl.BeginRefreshing ();
          ... // Fetch data & update table source 
          TableView.ReloadData ();
      } catch(Exception) {
          // Respond to exception
      } finally {
          // Put the offset back to the original
          TableView.SetContentOffset (originalOffset, true);
          RefreshControl.EndRefreshing ();
          TableView.UserInteractionEnabled = true;
      }
}

Одного разу ViewDidAppearя телефонуюUpdate програмно. До встановлення атрибутивного заголовка мій спінер був би чорним. Тепер він має належний червоний колір.

Варто зауважити, що цей `` хак / виправлення '' також має другу помилку. Під час першого оновлення ви помітите, що AttributedTitleвоно не відображається. Оновлення другого (, третього, четвертого, ...) часу відображатиме заголовок належним чином. Але якщо ви не хочете заголовка, ви просто ініціалізуєте його порожнім рядком, і це не є для вас великою проблемою.

Сподіваюся, це може бути корисним для інших.


1

цей хак дуже працює

var refreshWasProgramBeginning: Bool = false

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if !refreshWasProgramBeginning {
        UIView.animate(withDuration: 0.25, animations: {
            self.tableView.contentOffset = CGPoint.init(x: 0, y: -self.refreshControl.frame.height)
        }) { (_) in
            self.refreshControl.beginRefreshing()
            self.refreshWasProgramBeginning = true
        }
    }
}

1

Я працюю з Xamarin C # (iOS 10) і виявив, що поєднання всіх цих відповідей і допомогло мені.

У моєму ViewDidLoadя маю наступне:

    RefreshControl = new UIRefreshControl();
    RefreshControl.TintColor = UIColor.White;
    RefreshControl.ValueChanged += OnRefresh;
    RefreshControl.BackgroundColor = UIColor.Clear;

А пізніше я програмно називаю анімацію оновлення в моєму ViewDidAppearнаступним:

    BeginInvokeOnMainThread(() =>
    {
        UIView.Animate(0, 0.2, UIViewAnimationOptions.BeginFromCurrentState, () =>
        {
            TableView.SetContentOffset(new CGPoint(0, TableView.ContentOffset.Y - RefreshControl.Frame.Size.Height), true);
            RefreshControl.AttributedTitle = new NSAttributedString("");
        },
        () =>
        {
            RefreshControl.BeginRefreshing();
        });
    });

Зверніть увагу, що налаштування атрибутивного заголовка та блоку анімації були частинами, яких мені не вистачало RefreshControl щоб я набув білого кольору.

Дякую усім, хто сприяв цьому питанню.


1

Це помилка, яка виникає під час виклику beginRefreshing()елемента керування оновленням відразу після встановлення його tintColorвластивості (або виклику з нього viewDidLoad()(докладніше тут ). Однак є просте обхідне рішення, обертаючи beginRefreshing()виклик усередині deferоператора (Swift 4):

override func viewDidLoad() {
    super.viewDidLoad()
    refreshControl.tintColor = .red
    defer {
        refreshControl.beginRefreshing()
    }
}

0

Спробуйте встановити tintColor вашого UIRefreshControl у viewWillAppear.


0

я знайшов трохи навколо, сподіваюся, це працює для вас

 [_TBL setContentOffset:CGPointMake(0,_TBL.contentOffset.y-_refreshControl.frame.size.height) animated:YES];
[_refreshControl performSelector:@selector(beginRefreshing) withObject:nil afterDelay:0.25];
[self getLatestUpdates];

0

Я створив категорію UIRefreshControl + beginRefreshing яка виправляє цю проблему.

Коротше, це виправляє проблему з tintColor та вручну tableView коригує contentOffset, щоб переконатися, що елемент керування оновленням видно. Будь ласка, спробуй :)


0

Коли я встановлюю

tableView.refreshControl = refreshControl 

кілька разів, коли refreshControl є іншим екземпляром кожного разу, у мене виникала проблема, коли колір керування оновленням завжди був чорним, а встановлення кольору відтінку на інше значення не допомагало.

Так що я встановив tableView.refreshControl = refreshControl лише один раз, і коли мені потрібно його приховати, я встановлюю альфа-значення, більше деталей у цій темі:

Як мені "приховати" UIRefreshControl?


0

Використання UIView.animateмені не працювало на Swift 4.

Ось що я в підсумку використав

extension UIRefreshControl {
    func beginRefreshingManually(with scrollView: UIScrollView, isFirstTime: Bool) {
        if self.isRefreshing { return }

        // Workaround: If we call setContentOffset on the first time that the screen loads
        // we get a black refreshControl with the wrong size.
        // We could just set the scrollView.contentOffset everytime, but it does not animate the scrolling.
        // So for every other time, we call the setContentOffset animated.
        if isFirstTime {
            scrollView.contentOffset = CGPoint(x: 0, y: -self.frame.size.height)
        } else {
            scrollView.setContentOffset(CGPoint(x: 0, y: -self.frame.size.height), animated: true)
        }
        self.beginRefreshing()
    }
}

0

Встановіть вручну зміщення вмісту для вашого tableView / scrollView перед початком обертання:

tableView.setContentOffset(CGPoint(x: 0, y: tableView.contentOffset.y - (refreshControl.frame.size.height)), animated: true)
refreshControl.beginRefreshing()
......

-2

Примусити setTintColor запускатися в основному потоці. (Основний потік оновлює інтерфейс користувача).

[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
    [self.refreshControl setTintColor:[UIColor redColor]];
    [self.refreshControl beginRefreshing];
}];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.