Как оживить увеличивающееся число в UILabel
У меня есть метка, показывающая число, и я хочу изменить ее на большее число, однако я хотел бы добавить немного бликов к ней.
Я бы хотел, чтобы число приращений увеличилось до большего числа с легкостью в кривой, поэтому оно ускоряется, а затем замедляется.
Этот ответ показывает, как сделать его приростом (второй ответ, а не принятый ответ), но я бы предпочел его оживить, поэтому я мог бы также увеличить его размер, а затем снова сжать, а также легкость кривой.
как сделать анимацию с запущенным счетом в iphone sdk
Любые идеи, как лучше всего это достичь?
Благодаря
Начальные/конечные номера будут введены пользователем, и я хочу, чтобы он увеличивал конечный номер за тот же промежуток времени. Поэтому, если у меня есть начало 10-го конца 100 или начало 10-го конца 1000, я хочу, чтобы он подсчитывал до конечного числа через 5 секунд.
Ответы
Ответ 1
Вы можете использовать флаг, чтобы увидеть, нужно ли ему идти вверх или вниз.
Вместо цикла for используйте цикл while.
Таким образом, вы создаете цикл, который продолжает двигаться, поэтому вам также нужно найти способ остановить его, т.е. нажатием кнопки.
Ответ 2
Я действительно сделал такой класс только для этого, как UICountingLabel:
http://github.com/dataxpress/UICountingLabel
Он позволяет вам указать, хотите ли вы, чтобы режим подсчета был линейным, облегчал, облегчил или облегчил ввод/выключение. Легкость ввода/вывода начинает медленно подсчитываться, ускоряется, а затем заканчивается медленно - все в любое время, которое вы укажете.
В настоящее время он не поддерживает установку фактического размера шрифта метки на основе текущего значения, хотя я могу добавить поддержку для этого, если это функция, которая используется по требованию. Большинство ярлыков в моих макетах не имеют большого количества возможностей для роста или сжатия, поэтому я не уверен, как вы хотите его использовать. Однако он ведет себя как обычный ярлык, поэтому вы можете изменить размер шрифта самостоятельно.
Ответ 3
Вы можете использовать GCD для переноса задержек на фоновый поток.
Вот пример анимации значений (от 1 до 100 за 10 секунд)
float animationPeriod = 10;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 1; i < 101; i ++) {
usleep(animationPeriod/100 * 1000000); // sleep in microseconds
dispatch_async(dispatch_get_main_queue(), ^{
yourLabel.text = [NSString stringWithFormat:@"%d", i];
});
}
});
Ответ 4
Здесь @malex отвечает в swift 3.
func incrementLabel(to endValue: Int) {
let duration: Double = 2.0 //seconds
DispatchQueue.global().async {
for i in 0 ..< (endValue + 1) {
let sleepTime = UInt32(duration/Double(endValue) * 1000000.0)
usleep(sleepTime)
DispatchQueue.main.async {
self.myLabel.text = "\(i)"
}
}
}
}
Однако я настоятельно рекомендую просто загрузить этот класс из GitHub и перетащить его в ваш проект, я прибегнул к его использованию, потому что время в моем коде, похоже, не корректируется должным образом для более низких/более высоких чисел счета. Этот класс отлично работает и выглядит очень хорошо. См. эту статью среды для справки.
Ответ 5
Вот как я это сделал:
- (void)setupAndStartCounter:(CGFloat)duration {
NSUInteger step = 3;//use your own logic here to define the step.
NSUInteger remainder = numberYouWantToCount%step;//for me it was 30
if (step < remainder) {
remainder = remainder%step;
}
self.aTimer = [self getTimer:[self getInvocation:@selector(animateLabel:increment:) arguments:[NSMutableArray arrayWithObjects:[NSNumber numberWithInteger:remainder], [NSNumber numberWithInteger:step], nil]] timeInterval:(duration * (step/(float) numberYouWantToCountTo)) willRepeat:YES];
[self addTimerToRunLoop:self.aTimer];
}
- (void)animateLabel:(NSNumber*)remainder increment:(NSNumber*)increment {
NSInteger finish = finalValue;
if ([self.aLabel.text integerValue] <= (finish) && ([self.aLabel.text integerValue] + [increment integerValue]<= (finish))) {
self.aLabel.text = [NSString stringWithFormat:@"%lu",(unsigned long)([self.aLabel.text integerValue] + [increment integerValue])];
}else{
self.aLabel.text = [NSString stringWithFormat:@"%lu",(unsigned long)([self.aLabel.text integerValue] + [remainder integerValue])];
[self.aTimer invalidate];
self.aTimer = nil;
}
}
#pragma mark -
#pragma mark Timer related Functions
- (NSTimer*)getTimer:(NSInvocation *)invocation timeInterval:(NSTimeInterval)timeInterval willRepeat:(BOOL)willRepeat
{
return [NSTimer timerWithTimeInterval:timeInterval invocation:invocation repeats:willRepeat];
}
- (NSInvocation*)getInvocation:(SEL)methodName arguments:(NSMutableArray*)arguments
{
NSMethodSignature *sig = [self methodSignatureForSelector:methodName];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setTarget:self];
[invocation setSelector:methodName];
if (arguments != nil)
{
id arg1 = [arguments objectAtIndex:0];
id arg2 = [arguments objectAtIndex:1];
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];
}
return invocation;
}
- (void)addTimerToRunLoop:(NSTimer*)timer
{
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
Ответ 6
Вы также можете проверить https://github.com/leszek-s/LSCategories
Он позволяет увеличивать/уменьшать число в UILabel с помощью одной строки кода следующим образом:
[self.label lsAnimateCounterWithStartValue:10 endValue:100 duration:5 completionBlock:nil];
Ответ 7
подробности
Xcode 9.2, swift 4
Решение
class LoadingProcess {
let minValue: Int
let maxValue: Int
var currentValue: Int
private let progressQueue = DispatchQueue(label: "ProgressView")
private let semaphore = DispatchSemaphore(value: 1)
init (minValue: Int, maxValue: Int) {
self.minValue = minValue
self.currentValue = minValue
self.maxValue = maxValue
}
private func delay(stepDelayUsec: useconds_t, completion: @escaping ()->()) {
usleep(stepDelayUsec)
DispatchQueue.main.async {
completion()
}
}
func simulateLoading(toValue: Int, step: Int = 1, stepDelayUsec: useconds_t? = 10_000,
valueChanged: @escaping (_ currentValue: Int)->(),
completion: ((_ currentValue: Int)->())? = nil) {
semaphore.wait()
progressQueue.sync {
if currentValue <= toValue && currentValue <= maxValue {
usleep(stepDelayUsec!)
DispatchQueue.main.async {
valueChanged(self.currentValue)
self.currentValue += step
self.semaphore.signal()
self.simulateLoading(toValue: toValue, step: step, stepDelayUsec: stepDelayUsec, valueChanged: valueChanged, completion: completion)
}
} else {
self.semaphore.signal()
completion?(currentValue)
}
}
}
func finish(step: Int = 1, stepDelayUsec: useconds_t? = 10_000,
valueChanged: @escaping (_ currentValue: Int)->(),
completion: ((_ currentValue: Int)->())? = nil) {
simulateLoading(toValue: maxValue, step: step, stepDelayUsec: stepDelayUsec, valueChanged: valueChanged, completion: completion)
}
}
использование
let loadingProcess = LoadingProcess(minValue: 0, maxValue: 100)
loadingProcess.simulateLoading(toValue: 80, valueChanged: { currentValue in
// Update views
})
DispatchQueue.global(qos: .background).async {
print("Start loading data")
sleep(5)
print("Data loaded")
loadingProcess.finish(valueChanged: { currentValue in
// Update views
}) { _ in
print("End")
}
}
Полный образец
Не забудьте добавить код решения здесь
import UIKit
class ViewController: UIViewController {
weak var counterLabel: UILabel!
weak var progressView: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 80).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -80).isActive = true
let label = UILabel()
label.textAlignment = .center
label.text = "0"
label.font = UIFont.systemFont(ofSize: 46)
stackView.addArrangedSubview(label)
counterLabel = label
let progressView = UIProgressView()
progressView.trackTintColor = .lightGray
progressView.progressTintColor = .blue
progressView.layer.cornerRadius = 4
progressView.clipsToBounds = true
progressView.heightAnchor.constraint(equalToConstant: 8).isActive = true
stackView.addArrangedSubview(progressView)
self.progressView = progressView
let button = UIButton()
button.setTitle("Start", for: .normal)
button.addTarget(self, action: #selector(startButtonTapped), for: .touchUpInside)
button.setTitleColor(.blue, for: .normal)
button.heightAnchor.constraint(equalToConstant: 30).isActive = true
stackView.addArrangedSubview(button)
}
@objc func startButtonTapped() {
sample()
}
private func setProcess(currentValue: Int) {
let value = 0.01 * Float(currentValue)
self.counterLabel?.text = "\(currentValue)"
self.progressView?.setProgress(value, animated: true)
print("\(currentValue)")
}
func sample() {
let loadingProcess = LoadingProcess(minValue: 0, maxValue: 100)
loadingProcess.simulateLoading(toValue: 80, valueChanged: { currentValue in
self.setProcess(currentValue: currentValue)
})
DispatchQueue.global(qos: .background).async {
print("Start loading data")
sleep(5)
print("Data loaded")
loadingProcess.finish(valueChanged: { currentValue in
self.setProcess(currentValue: currentValue)
}) { _ in
print("end")
}
}
}
}
Результаты
![enter image description here]()
Ответ 8
Swift 4 Code
let animationPeriod: Float = 1
DispatchQueue.global(qos: .default).async(execute: {
for i in 1..<10000)! {
usleep(useconds_t(animationPeriod / 10 * 10000)) // sleep in microseconds
DispatchQueue.main.async(execute: {
self.lblCounter.text = "\(i)"
})
}
})
Ответ 9
Код Swift 4:
let animationPeriod: Float = 1
DispatchQueue.global(qos: .default).async(execute: {
for i in 1..<Int(endValue) {
usleep(useconds_t(animationPeriod / 10 * 10000)) // sleep in microseconds
DispatchQueue.main.async(execute: {
self.lbl.text = "\(i+1)"
})
}
})