UIScrollview 动画取决于内容偏移
Posted
技术标签:
【中文标题】UIScrollview 动画取决于内容偏移【英文标题】:UIScrollview animation depending on content offset 【发布时间】:2014-10-02 10:32:52 【问题描述】:我正在使用水平 UIScrollView,并且我想要根据内容偏移的 x 值进行背景颜色转换。
示例: UIScrollView 的宽度为 640px。当内容偏移量等于 0px 时,背景颜色必须为红色。当内容偏移为 320 px 时,背景必须为黄色。但最重要的是,当 UIScrollview 在 0px 和 320px 之间时,背景颜色必须在红色和黄色之间。
提示:当您从搜索中向左滑动时,ios 的 twitter 应用程序具有相同的动画。导航上的标签稍微消失了。
【问题讨论】:
【参考方案1】:您需要根据偏移百分比创建颜色。
在这种颜色之间创建转换的最简单方法是使用 HSB 颜色空间。
另外,这不是动画。 “动画”效果由滚动视图提供给您。您只需要在每次滚动视图更改时设置颜色即可。
在委托方法中你可以做这样的事情。
修改以提高灵活性
// this just calculates the percentages now and passes it off to another method.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
// vertical
CGFloat maximumVerticalOffset = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
CGFloat currentVerticalOffset = scrollView.contentOffset.y;
// horizontal
CGFloat maximumHorizontalOffset = scrollView.contentSize.width - CGRectGetWidth(scrollView.frame);
CGFloat currentHorizontalOffset = scrollView.contentOffset.x;
// percentages
CGFloat percentageHorizontalOffset = currentHorizontalOffset / maximumHorizontalOffset;
CGFloat percentageVerticalOffset = currentVerticalOffset / maximumVerticalOffset;
[self scrollView:scrollView didScrollToPercentageOffset:CGPointMake(percentageHorizontalOffset, percentageVerticalOffset)];
// this just gets the percentage offset.
// 0,0 = no scroll
// 1,1 = maximum scroll
- (void)scrollView:(UIScrollView *)scrollView didScrollToPercentageOffset:(CGPoint)percentageOffset
UIColor *HSBColor = [self HSBColorForOffsetPercentage:percentageOffset.x];
UIColor *RGBColor = [self RGBColorForOffsetPercentage:percentageOffset.x];
// HSB color just using Hue
- (UIColor *)HSBColorForOffsetPercentage:(CGFloat)percentage
CGFloat minColorHue = 0.0;
CGFloat maxColorHue = 0.2; // this is a guess for the yellow hue.
CGFloat actualHue = (maxColorHue - minColorHue) * percentage + minColorHue;
// change these values to get the colours you want.
// I find reducing the saturation to 0.8 ish gives nicer colours.
return [UIColor colorWithHue:actualHue saturation:1.0 brightness:1.0 alpha:1.0];
// RGB color using all R, G, B values
- (UIColor *)RGBColorForOffsetPercentage:(CGFloat)percentage
// RGB 1, 0, 0 = red
CGFloat minColorRed = 1.0;
CGFloat minColorGreen = 0.0;
CGFloat minColorBlue = 0.0;
// RGB 1, 1, 0 = yellow
CGFloat maxColorRed = 1.0;
CGFloat maxColorGreen = 1.0;
CGFloat maxColorBlue = 0.0;
// if you have specific beginning and end RGB values then set these to min and max respectively.
// it should even work if the min value is greater than the max value.
CGFloat actualRed = (maxColorRed - minColorRed) * percentage + minColorRed;
CGFloat actualGreen = (maxColorGreen - minColorGreen) * percentage + minColorGreen;
CGFloat actualBlue = (maxColorBlue - minColorBlue) * percentage + minColorBlue;
return [UIColor colorWithRed:actualRed green:actualGreen blue:actualBlue alpha:1.0];
我不知道 RGB 方法在中间值上的表现如何。它可能会在中间变成棕色等等......但你可以玩。
这应该让您了解如何使用滚动视图为 ANYTHING 设置动画以作为控制它的一种方式。
使用这种方法,您可以控制不透明度、大小、旋转、字体大小等...您甚至可以组合多种事物(就像我对 RGB 所做的那样)。
【讨论】:
@Maarten1909 是的,但是用 RGB 制作变换颜色要困难得多。让我改一下…… @Maarten1909 好的,要写博客了。我太喜欢它了:D 谢谢!在计算实际红色的部分有一个小错误,您应该使用“百分比”而不是“百分比偏移”。 @Maarten1909 写了博客。 oliverfoggin.com/controlling-animations-with-a-uiscrollview 从 iOS 11 开始,当 scrollView 绑定到布局指南时,您还应该将scrollView.adjustedContentInset
值添加到最大尺寸。【参考方案2】:
受@Fogmeister 回答的启发,我迅速将这些部分拼凑在一起。
extension UIColor
static func color(between start: UIColor, and end: UIColor, percentage: CGFloat) -> UIColor
let startRGB = start.rgba
let stopRGB = end.rgba
let red: CGFloat = (stopRGB.red - startRGB.red) * percentage + startRGB.red
let green: CGFloat = (stopRGB.green - startRGB.green) * percentage + startRGB.green
let blue: CGFloat = (stopRGB.blue - startRGB.blue) * percentage + startRGB.blue
let alpha: CGFloat = (stopRGB.alpha - startRGB.alpha) * percentage + startRGB.alpha
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
现在你可以这样做了:
func scrollViewDidScroll(_ scrollView: UIScrollView)
let offset = scrollView.contentOffset.y
let scrolledDistance = offset + scrollView.contentInset.top
let progress = max(0, min(1, scrolledDistance / scrollView.contentSize.height))
someLabel.textColor = .color(between: .red, and: .green, percentage: progress)
警告:此实现将触发 swiftlints large_tuple 规则。但您可以禁用,只需在 disabled_rules 部分添加“-large_tuple”即可。
【讨论】:
【参考方案3】:在你的 scrollView 委托中尝试这样的事情:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
CGPoint a = self.mainScrollView.contentOffset;
if(a.x >= 320)
[UIView animateWithDuration:0.5 animations:^
[self.view setBackgroundColor:[UIColor redColor]];
];
else
[UIView animateWithDuration:0.5 animations:^
[self.view setBackgroundColor:[UIColor yellowColor]];
];
【讨论】:
为什么投反对票?即使上面的代码不完全符合问题中表达的特定需求,它确实暗示了提问者可以尝试让他的颜色逻辑工作。 不是我的反对票。但是......这不会产生提问者正在寻找的效果。如果 scrollView 的偏移量为 319,那么这将动画为黄色。它应该几乎完全是红色的。此外,这也不会在他正在寻找的红色和黄色效果之间提供一半。另外,这里也不需要动画。以上是关于UIScrollview 动画取决于内容偏移的主要内容,如果未能解决你的问题,请参考以下文章
如何检测用户何时尝试滑动“过去的 UIScrollView 内容偏移”?
支持 UITableView 的自定义 UIScrollView