Высокая загрузка процессора за счет круговой анимации с градиентом

При использовании следующего кода SwiftUI потребление ресурсов ЦП моим приложением достигает 55 %, когда приложение работает в XCode (симуляторе) с M1.

На настоящем iPhone загрузка процессора достигает 52%.

К вашему сведению: CircleProgess обновляется каждые 0,1 секунды.

Circle()
    .trim(from: 0.0, to: circleProgress)
    .stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
    .fill(Color.pink.gradient)
    .rotationEffect(Angle(degrees: 270.0))
    .animation(.default, value: circleProgress)
    .frame(width: 100, height: 100)

Я обнаружил, что высокая загрузка ЦП вызвана не только, но и главным образом строкой Color.pink.gradient.

Если я использую тот же код, но с Color.pink вместо Color.pink.gradient, загрузка ЦП в симуляторе XCode составит около 15%. На реальном устройстве, например. iPhone 12: загрузка процессора все еще до 35%

Вот воспроизводимый пример

struct ContentView: View {
    @ObservedObject var someTimer = SomeTimer()
    
    var body: some View {
        AnimatedCircle(circleProgress: $someTimer.circleProgess, size: 100)
        AnimatedCircle(circleProgress: $someTimer.circleProgess, size: 400)
        
        Spacer()
        
        Button(action: someTimer.start, label: {
            Text("Start animation")
        })
        
        Spacer()
    }
}


class SomeTimer : ObservableObject {
    @Published var circleProgess = 1.0
    
    func start() {
        circleProgess = 1.0
        Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) {_ in
            self.circleProgess -= 0.001
        }
    }
}

struct AnimatedCircle: View {
    @Binding var circleProgress : Double
    var size : Int
    
    var body: some View {
        Circle()
            .trim(from: 0.0, to: CGFloat(circleProgress))
            .stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
            .fill(Color.pink.gradient)
            //.fill(Color.pink)
            .rotationEffect(Angle(degrees: 270.0))
            .animation(.default, value: CGFloat(circleProgress))
            .frame(width: CGFloat(size), height: CGFloat(size))
    }
}

Существует огромная разница в потреблении процессора при запуске AnimatedCircle() с .fill(Color.pink.gradient) или с .fill(Color.pink)

Есть идеи, как я могу использовать эту анимацию с Color.pink.gradient и при этом поддерживать загрузку процессора намного ниже 55%?
Спасибо

«Я обнаружил, что высокая загрузка ЦП вызвана главным образом линией Color.pink.gradient». Как вы это узнали? Я очень сомневаюсь, что проблема именно в этом. Пожалуйста, покажите минимально воспроизводимый пример, включая то, как вы обновляете circleProgess, чтобы другие люди могли самостоятельно выяснить, в чем проблема, а не просто предполагать, что вы правы.

Sweeper 13.07.2024 12:43

Спасибо @Sweeper. Я добавил минимальный пример того, как это вообще реализовано в моем приложении. В реальном приложении кругПрогресс НЕ рассчитывается в самом таймере и останавливается через 1 минуту. Это всего лишь пример

LetsBeHappy 13.07.2024 13:47

Переключите ObservedObject на StateObject. StateObject предназначен для инициализации, а ObservedObject — для передачи.

lorem ipsum 13.07.2024 13:59

Спасибо @loremipsum, я изменил его на StateObject, но загрузка процессора все еще составляет около 50%.

LetsBeHappy 13.07.2024 15:09
Animista - анимация на ходу!
Animista - анимация на ходу!
Если вы веб-дизайнер или разработчик, вы знаете, что добавление анимации на ваш сайт может помочь сделать его более привлекательным и динамичным....
Повысьте уровень своего сайта с помощью анимации CSS и JavaScript: Пошаговое руководство
Повысьте уровень своего сайта с помощью анимации CSS и JavaScript: Пошаговое руководство
Если вы хотите добавить визуальный интерес к своему сайту, то внедрение анимации с помощью CSS и JavaScript может стать отличным способом сделать это....
0
4
134
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используя ваш пример Timer, я обнаружил, что приложение использовало около 47% ресурсов ЦП при работе на симуляторе iPhone 15 с iOS 17.5.

Он использует меньше процессора, если вы сначала закрашиваете круг, а затем применяете обрезанную фигуру в качестве маски:

Circle()
    .fill(Color.pink.gradient)
    .frame(width: CGFloat(size), height: CGFloat(size))
    .mask {
        Circle()
            .inset(by: 10) // half the line width
            .trim(from: 0.0, to: CGFloat(circleProgress))
            .stroke(style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
            .rotationEffect(Angle(degrees: 270.0))
            .animation(.default, value: CGFloat(circleProgress))
    }

В моем тесте в симуляторе использовалось всего около 8% ЦП.

СПАСИБО @Бензи Низ. Вы сделали мой день :-). Теперь приложение не потребляет даже 8% процессора. Я хотел бы оценить ваш ответ, но после вашей помощи моя репутация ниже процента процессора, на котором работает мое приложение :-D Но есть ли объяснение, почему круг в моем исходном примере работает так плохо по сравнению с вашим подходом?

LetsBeHappy 13.07.2024 14:15

@LetsBeHappy Рад, что смог помочь. Я предполагаю, что в исходной реализации градиент пересчитывался при каждом изменении, и это могло немного нагружать процессор. Кстати, даже с низкой репутацией вы сможете принять ответ, нажав галочку, если вы довольны тем, что это решает проблему. Однако вам, возможно, придется немного подождать, прежде чем это позволит вам.

Benzy Neez 13.07.2024 14:19

Я принял ваш ответ. Не знал, что смогу ;-). Теперь я проверил приложение на своем реальном устройстве iPhone 12, и ваше решение лучше, но процессор в XCode все равно отображается до 26%.

LetsBeHappy 13.07.2024 14:24

@LetsBeHappy Вы используете отладочную сборку на реальном устройстве? Попробуйте изменить его на сборку Release (это можно сделать, отредактировав схему). Пс. Спасибо, что приняли ответ!

Benzy Neez 13.07.2024 14:40

Да, я запускал приложение с отладочной сборкой, но релизная сборка не особо помогла :-(

LetsBeHappy 13.07.2024 14:58

Другие вопросы по теме