Swift - Как изменить цвет NSMutableAttributedString UIButton после его установки

У меня есть 2 UIButtons, а их titles и colors изначально установлены с помощью NSMutableAttributedString. Текст 2 строки текста

У меня кастомный UISegmentedControl и при переключении сегмента нужно менять только цвет кнопок. То, как я это делаю сейчас, меняет цвета, но когда это происходит, происходит уродливое мерцание, потому что фактический текст снова устанавливается. Мне нужен плавный переход только для цветов

var selectedSegmentIndex = 0 {
    didSet {

        layoutIfNeeded()
        UIView.animate(withDuration: 0.1) {
            self.setTextForFollowersButton()
            self.setTextForFollowingButton()
            self.layoutIfNeeded()
        }
    }
}

Как изменить только цвет кнопки NSMutableAttributedString?

Код кнопки:

var numOfFollowers = 0 {
    didSet {
        setTextForFollowersButton()
    }
}
var numOfFollowing = 0 {
    didSet {
        setTextForFollowingButton()
    }
}

lazy var followersButton: UIButton = {
    let button = UIButton.init(type: .system)
    // ...
    return button
}()

lazy var followingButton: UIButton = {
    let button = UIButton.init(type: .system)
    //...
    return button
}()

func setTextForFollowersButton() {

    let button = self.followersButton
    let buttonText = "Following\n\(String(numOfFollowing))" as NSString
    // other code for 2 lines of text

    var color = UIColor.blue

    if selectedSegmentIndex == 0 {
        color = UIColor.blue
    } else {
        color = UIColor.gray
    }

    let attrString1 = NSMutableAttributedString(string: substring1,
                                                attributes: [NSMutableAttributedString.Key.font:
                                                    UIFont.boldSystemFont(ofSize: 16),
                                                             NSMutableAttributedString.Key.foregroundColor: color])

    let attrString2 = NSMutableAttributedString(string: substring2,
                                                attributes: [NSMutableAttributedString.Key.font:
                                                    UIFont.boldSystemFont(ofSize: 14),
                                                             NSMutableAttributedString.Key.foregroundColor: color])

    attrString1.append(attrString2)
    button.setAttributedTitle(attrString1, for: [])
}

func setTextForFollowingButton() {

    let button = self.followingButton

    let buttonText = "Following\n\(String(numOfFollowing))" as NSString
    // other code for 2 lines of text

    var color = UIColor.blue

    if selectedSegmentIndex == 0 {
        color = UIColor.gray
    } else {
        color = UIColor.blue
    }

    let attrString1 = NSMutableAttributedString(string: substring1,
                                                attributes: [NSMutableAttributedString.Key.font:
                                                    UIFont.boldSystemFont(ofSize: 16),
                                                             NSMutableAttributedString.Key.foregroundColor: color])

    let attrString2 = NSMutableAttributedString(string: substring2,
                                                attributes: [NSMutableAttributedString.Key.font:
                                                    UIFont.boldSystemFont(ofSize: 14),
                                                             NSMutableAttributedString.Key.foregroundColor: color])

    attrString1.append(attrString2)
    button.setAttributedTitle(attrString1, for: [])
}

person Lance Samaria    schedule 13.01.2020    source источник
comment
Вы пытались вставить UIView.animate внутрь DispatchQueue.main.async {}, чтобы сделать переход плавным?   -  person Lew Winczynski    schedule 13.01.2020
comment
@LewWinczynski спасибо, ваш ответ сработал. Пожалуйста, опубликуйте его, чтобы я мог принять его. Мне пришлось изменить время на 0,05, чтобы оно тоже выглядело лучше.   -  person Lance Samaria    schedule 13.01.2020
comment
Рад слышать! Хорошо, опубликую. :)   -  person Lew Winczynski    schedule 13.01.2020


Ответы (2)


Вы должны вставить функцию UIView.animate внутри DispatchQueue.main.async {}, чтобы сделать плавный переход. Всегда рекомендуется выполнять любую анимацию пользовательского интерфейса асинхронно в основном потоке.

person Lew Winczynski    schedule 13.01.2020

Другой способ сделать это для плавного перехода без мигания — использовать UIView.performWithoutAnimation:

DispatchQueue.main.async {
    self.layoutIfNeeded()
    UIView.performWithoutAnimation {

        self.setTextForFollowersButton()
        self.setTextForFollowingButton()

        self.layoutIfNeeded()
    }
}
person Lance Samaria    schedule 13.01.2020
comment
@LewWinczynski вот еще один способ сделать это без анимации - person Lance Samaria; 13.01.2020