iOS 构建自定义评级控制问题
iOS building custom rating control issue
我知道那里有很多第 3 方解决方案,但我决定自己构建一个以完全控制动画并学习新知识。
似乎大部分时间都是通过子类化 UIControl 和跟踪触摸来实现的,但我使用了不同的方法。我用图像创建系统按钮。这样我就可以免费在印刷机上获得漂亮的高亮动画。无论如何,在您非常快地按下它之前,它工作得很好。这是正在发生的事情的动图。
有时候,如果你做得太快,一颗满星就会卡住。我将尝试解释这个动画背后发生的事情。由于满星和空星有不同的颜色,每次我变满或空时我都会改变按钮的色调。您看到的动画是一个单独的 UIImageView,它被添加到动画块开始之前按钮的顶部,并在完成块中被删除。我相信有时在清空时不会触发星星动画并且不会在完成块中删除图像。但是我无法在代码中发现这个错误。
我添加了一些调试代码以查看是否甚至触发了使星空的块。似乎是这样,甚至调用了完成块。
2015-04-23 13:00:00.416 RERatingControl[24011:787202]
Touch number: 5
2015-04-23 13:00:00.416 RERatingControl[24011:787202]
removing a star at index: 4
2015-04-23 13:00:00.693 RERatingControl[24011:787202] star removed
星级索引是从零开始的,所以第 5 颗星应该被删除,但事实并非如此。
完整项目在 github。它很小。如果有人能帮我解决这个问题,我将不胜感激。哦,如果您愿意,请随时使用此代码:-)
UPDATE. 有人建议我在这里 post 一些逻辑代码。没马上做,觉得太麻烦了
按键动作方法:
- (void)buttonPressed:(id)sender {
static int touchNumber = 0;
NSLog(@"\nTouch number: %d", touchNumber);
touchNumber++;
if (self.isUpdating) {
return;
}
self.updating = YES;
NSInteger index = [self.stars indexOfObject:sender];
__block NSTimeInterval delay = 0;
[self.stars enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
REStarButton *btn = (REStarButton*)obj;
if (idx <= index) {
if (!btn.isFull) {
NSLog(@"\nadding a star at index: %ld", (long)idx);
[btn makeFullWithDelay:delay];
delay += animationDelay;
}
} else {
if (btn.isFull) {
NSLog(@"\nremoving a star at index: %ld", (long)idx);
[btn makeEmptyWithDelay:0];
}
}
}];
if ([self.delegate respondsToSelector:@selector(ratingDidChangeTo:)]) {
[self.delegate ratingDidChangeTo:index + 1];
}
self.updating = NO;
}
清空满星方法:
- (void)makeEmptyWithDelay:(NSTimeInterval)delay {
// if (!self.isFull) {
// return;
// }
self.full = NO;
UIImageView *fullStar = [[UIImageView alloc] initWithImage:self.starImageFull];
[self addSubview:fullStar];
CGFloat xOffset = CGRectGetMidX(self.bounds) - CGRectGetMidX(fullStar.bounds);
CGFloat yOffset = CGRectGetMidY(self.bounds) - CGRectGetMidY(fullStar.bounds);
fullStar.frame = CGRectOffset(fullStar.frame, xOffset, yOffset);
[self setImage:self.starImageEmpty forState:UIControlStateNormal];
[self setTintColor:self.superview.tintColor];
[UIView animateWithDuration:animationDuration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^{
//fullStar.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
fullStar.transform = CGAffineTransformMakeTranslation(0, 10);
fullStar.alpha = 0;
} completion:^(BOOL finished) {
[fullStar removeFromSuperview];
NSLog(@"star removed");
}];
空星补满方法:
}
- (void)makeFullWithDelay:(NSTimeInterval)delay {
// if (self.isFull) {
// return;
// }
self.full = YES;
UIImageView *fullStar = [[UIImageView alloc] initWithImage:self.starImageFull];
CGFloat xOffset = CGRectGetMidX(self.bounds) - CGRectGetMidX(fullStar.bounds);
CGFloat yOffset = CGRectGetMidY(self.bounds) - CGRectGetMidY(fullStar.bounds);
fullStar.frame = CGRectOffset(fullStar.frame, xOffset, yOffset);
fullStar.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
[self addSubview:fullStar];
[UIView animateKeyframesWithDuration:animationDuration delay:delay options:0 animations:^{
CGFloat ratio = 0.35;
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:ratio animations:^{
fullStar.transform = CGAffineTransformMakeScale(animationScaleRatio, animationScaleRatio);
}];
[UIView addKeyframeWithRelativeStartTime:ratio relativeDuration:1 - ratio animations:^{
fullStar.transform = CGAffineTransformIdentity;
}];
} completion:^(BOOL finished) {
[self setImage:self.starImageFull forState:UIControlStateNormal];
[self setTintColor:self.fullTintColor];
[fullStar removeFromSuperview];
}];
}
啊,我已经设法找到了我的错误背后的原因,现在它完美运行了!
我用View Debugging看是不是动画的UIImageView卡在了按钮上,或者按钮本身的图片设置不正确。我惊讶地发现是按钮图像导致了问题。然后我再次查看代码,意识到我在延迟后更改了完成块中的按钮图像,而不管它的状态是否已经改变。 makeFullWithDelay 的简单修复:解决了我的问题。
} completion:^(BOOL finished) {
if (self.isFull) {
[self setImage:self.starImageFull forState:UIControlStateNormal];
[self setTintColor:self.fullTintColor];
}
[fullStar removeFromSuperview];
}];
昨天我用了整个晚上的时间试图找到答案,在我 posted 之后,问题的答案自然而然地出现了。我想,将您的问题告诉人们确实有助于更加关注您的逻辑。感谢大家:-)
我应该删除 post 还是它对以后的人有帮助?
我知道那里有很多第 3 方解决方案,但我决定自己构建一个以完全控制动画并学习新知识。
似乎大部分时间都是通过子类化 UIControl 和跟踪触摸来实现的,但我使用了不同的方法。我用图像创建系统按钮。这样我就可以免费在印刷机上获得漂亮的高亮动画。无论如何,在您非常快地按下它之前,它工作得很好。这是正在发生的事情的动图。
有时候,如果你做得太快,一颗满星就会卡住。我将尝试解释这个动画背后发生的事情。由于满星和空星有不同的颜色,每次我变满或空时我都会改变按钮的色调。您看到的动画是一个单独的 UIImageView,它被添加到动画块开始之前按钮的顶部,并在完成块中被删除。我相信有时在清空时不会触发星星动画并且不会在完成块中删除图像。但是我无法在代码中发现这个错误。
我添加了一些调试代码以查看是否甚至触发了使星空的块。似乎是这样,甚至调用了完成块。
2015-04-23 13:00:00.416 RERatingControl[24011:787202]
Touch number: 5
2015-04-23 13:00:00.416 RERatingControl[24011:787202]
removing a star at index: 4
2015-04-23 13:00:00.693 RERatingControl[24011:787202] star removed
星级索引是从零开始的,所以第 5 颗星应该被删除,但事实并非如此。
完整项目在 github。它很小。如果有人能帮我解决这个问题,我将不胜感激。哦,如果您愿意,请随时使用此代码:-)
UPDATE. 有人建议我在这里 post 一些逻辑代码。没马上做,觉得太麻烦了
按键动作方法:
- (void)buttonPressed:(id)sender {
static int touchNumber = 0;
NSLog(@"\nTouch number: %d", touchNumber);
touchNumber++;
if (self.isUpdating) {
return;
}
self.updating = YES;
NSInteger index = [self.stars indexOfObject:sender];
__block NSTimeInterval delay = 0;
[self.stars enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
REStarButton *btn = (REStarButton*)obj;
if (idx <= index) {
if (!btn.isFull) {
NSLog(@"\nadding a star at index: %ld", (long)idx);
[btn makeFullWithDelay:delay];
delay += animationDelay;
}
} else {
if (btn.isFull) {
NSLog(@"\nremoving a star at index: %ld", (long)idx);
[btn makeEmptyWithDelay:0];
}
}
}];
if ([self.delegate respondsToSelector:@selector(ratingDidChangeTo:)]) {
[self.delegate ratingDidChangeTo:index + 1];
}
self.updating = NO;
}
清空满星方法:
- (void)makeEmptyWithDelay:(NSTimeInterval)delay {
// if (!self.isFull) {
// return;
// }
self.full = NO;
UIImageView *fullStar = [[UIImageView alloc] initWithImage:self.starImageFull];
[self addSubview:fullStar];
CGFloat xOffset = CGRectGetMidX(self.bounds) - CGRectGetMidX(fullStar.bounds);
CGFloat yOffset = CGRectGetMidY(self.bounds) - CGRectGetMidY(fullStar.bounds);
fullStar.frame = CGRectOffset(fullStar.frame, xOffset, yOffset);
[self setImage:self.starImageEmpty forState:UIControlStateNormal];
[self setTintColor:self.superview.tintColor];
[UIView animateWithDuration:animationDuration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^{
//fullStar.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
fullStar.transform = CGAffineTransformMakeTranslation(0, 10);
fullStar.alpha = 0;
} completion:^(BOOL finished) {
[fullStar removeFromSuperview];
NSLog(@"star removed");
}];
空星补满方法:
}
- (void)makeFullWithDelay:(NSTimeInterval)delay {
// if (self.isFull) {
// return;
// }
self.full = YES;
UIImageView *fullStar = [[UIImageView alloc] initWithImage:self.starImageFull];
CGFloat xOffset = CGRectGetMidX(self.bounds) - CGRectGetMidX(fullStar.bounds);
CGFloat yOffset = CGRectGetMidY(self.bounds) - CGRectGetMidY(fullStar.bounds);
fullStar.frame = CGRectOffset(fullStar.frame, xOffset, yOffset);
fullStar.transform = CGAffineTransformMakeScale(0.01f, 0.01f);
[self addSubview:fullStar];
[UIView animateKeyframesWithDuration:animationDuration delay:delay options:0 animations:^{
CGFloat ratio = 0.35;
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:ratio animations:^{
fullStar.transform = CGAffineTransformMakeScale(animationScaleRatio, animationScaleRatio);
}];
[UIView addKeyframeWithRelativeStartTime:ratio relativeDuration:1 - ratio animations:^{
fullStar.transform = CGAffineTransformIdentity;
}];
} completion:^(BOOL finished) {
[self setImage:self.starImageFull forState:UIControlStateNormal];
[self setTintColor:self.fullTintColor];
[fullStar removeFromSuperview];
}];
}
啊,我已经设法找到了我的错误背后的原因,现在它完美运行了!
我用View Debugging看是不是动画的UIImageView卡在了按钮上,或者按钮本身的图片设置不正确。我惊讶地发现是按钮图像导致了问题。然后我再次查看代码,意识到我在延迟后更改了完成块中的按钮图像,而不管它的状态是否已经改变。 makeFullWithDelay 的简单修复:解决了我的问题。
} completion:^(BOOL finished) {
if (self.isFull) {
[self setImage:self.starImageFull forState:UIControlStateNormal];
[self setTintColor:self.fullTintColor];
}
[fullStar removeFromSuperview];
}];
昨天我用了整个晚上的时间试图找到答案,在我 posted 之后,问题的答案自然而然地出现了。我想,将您的问题告诉人们确实有助于更加关注您的逻辑。感谢大家:-)
我应该删除 post 还是它对以后的人有帮助?