将 UIImage 的 "Tick Marks" 添加到 UISlider
Adding UIImage's as "Tick Marks" to UISlider
事先总结一下我的问题:我试图根据仅了解 UISlider 的持续时间并有一系列循环时间来确定我可以在滑块上放置图像的位置,从而相应地放置图像。
我一直在阅读有关 UISlider 的 Apple 文档,似乎没有本地方法可以在基于浮点数组的 UISlider 上添加 "Tick marks"。 "Tick marks" 表示滑块上的线条,例如用于在洗涤器上放置广告的线条。这是一个可视化:
现在,我有一个充满浮点数的数组;浮点数,我将在其中根据 UISlider 的值删除刻度线。数组中浮点数的值每次都会不同。我想遍历我的 UISlider 的 .value 属性,相应地删除 UIImages。 UIImage 是我创建的小 png 资产的刻度线。我无法弄清楚的是循环遍历 UISlider 的 .value 属性 并根据 UISlider 的未来位置放置 UIImage 背后的逻辑。数组中浮点数的值每次都会不同,所以我不能静态放置它们。有谁知道从哪里开始?我对 Objective-C 编程还是有点陌生。
我知道可以利用检索滑块在屏幕上的起始 X 坐标,如下所示:
- (float)xPositionFromSliderValue:(UISlider *)aSlider;
{
float sliderRange = aSlider.frame.size.width - aSlider.currentThumbImage.size.width;
float sliderOrigin = aSlider.frame.origin.x + (aSlider.currentThumbImage.size.width / 2.0);
float sliderValueToPixels = (((aSlider.value-aSlider.minimumValue)/(aSlider.maximumValue-aSlider.minimumValue)) * sliderRange) + sliderOrigin);
return sliderValueToPixels;
}
也许我可以在 for 循环中添加一个计算来根据它放置图像。我只是不太确定从哪里开始...
我认为您在定位刻度线时会遇到麻烦。但是,如果你的 UISlider 的父视图是 "view",你添加一个这样的子视图:
[view addSubView:myTickView];
添加的子视图的位置由其框架 属性 决定,它在父视图坐标 space 中。
要删除视图,您可以这样做:
[myTickView removeFromSuperView];
您还可以遍历刻度视图并更改那里的帧,但这些更改将是动画的,因此如果您这样做,刻度将看起来像在滑动,除非您关闭动画。
提供了方法 trackRectForBounds 和 thumbRectForBounds 用于子类化 UISlider,但您可以直接调用它们,它们会预先获取您的刻度中心。
- (float)sliderThumbCenter:(UISlider *)slider forValue:(float)value{
CGRect trackRect = [slider trackRectForBounds:slider.bounds];
CGRect thumbRect = [slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value];
CGFloat centerThumb = CGRectGetMidX(thumbRect);
return centerThumb;
}
做一个自定义视图来绘制轨道可能比图像视图更容易,然后只需将滑块放在它上面并隐藏轨道。只需使滑块框架等于 TickView 的边界即可。真的,我认为 UISlider 子类会更好,但这有效!
@interface TickView : UIView
@property UIColor *tickColor;
@property int tickCount;
@property CGFloat tickHeight;
@property (weak) UISlider *slider;
@property float *ticks;
-(void)setTicks:(float *)ticks count:(int)tickCount;
@end
@implementation TickView{
__weak UISlider *_slider;
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.tickColor = [UIColor grayColor];
self.backgroundColor = [UIColor clearColor];
self.tickCount = 7;
self.ticks = malloc(sizeof(float) * self.tickCount);
self.tickHeight = 10;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, self.tickColor.CGColor);
CGContextBeginPath(context);
CGFloat centerY = rect.size.height / 2;
CGContextMoveToPoint(context, 0, centerY);
CGContextAddLineToPoint(context, rect.size.width, centerY);
CGFloat tickTop = centerY - self.tickHeight / 2;
CGFloat tickBottom = centerY + self.tickHeight / 2;
CGFloat tickX = 0;
if (self.slider) {
for (int i = 0; i < self.tickCount; i++) {
tickX = [self sliderThumbCenter:self.slider forValue:self.ticks[i]];
CGContextMoveToPoint(context, tickX, tickTop);
CGContextAddLineToPoint(context, tickX, tickBottom);
}
}
else{
CGFloat tickSpacing = rect.size.width / (self.tickCount - 1);
for (int i = 0; i < self.tickCount; i++) {
CGContextMoveToPoint(context, tickX, tickTop);
CGContextAddLineToPoint(context, tickX, tickBottom);
tickX += tickSpacing;
}
}
CGContextStrokePath(context);
}
-(void)setTicks:(float *)ticks count:(int)tickCount{
free(_ticks);
_ticks = malloc(sizeof(float) * tickCount);
memcpy(_ticks, ticks, sizeof(float) * tickCount);
_tickCount = tickCount;
[self setNeedsDisplay];
}
- (float)sliderThumbCenter:(UISlider *)slider forValue:(float)value{
CGRect trackRect = [slider trackRectForBounds:slider.bounds];
CGRect thumbRect = [slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value];
CGFloat centerThumb = CGRectGetMidX(thumbRect);
return centerThumb;
}
-(void)setSlider:(UISlider *)slider{
_slider = slider;
}
-(UISlider *)slider{
return _slider;
}
-(void)dealloc{
free(_ticks);
}
@end
事先总结一下我的问题:我试图根据仅了解 UISlider 的持续时间并有一系列循环时间来确定我可以在滑块上放置图像的位置,从而相应地放置图像。
我一直在阅读有关 UISlider 的 Apple 文档,似乎没有本地方法可以在基于浮点数组的 UISlider 上添加 "Tick marks"。 "Tick marks" 表示滑块上的线条,例如用于在洗涤器上放置广告的线条。这是一个可视化:
现在,我有一个充满浮点数的数组;浮点数,我将在其中根据 UISlider 的值删除刻度线。数组中浮点数的值每次都会不同。我想遍历我的 UISlider 的 .value 属性,相应地删除 UIImages。 UIImage 是我创建的小 png 资产的刻度线。我无法弄清楚的是循环遍历 UISlider 的 .value 属性 并根据 UISlider 的未来位置放置 UIImage 背后的逻辑。数组中浮点数的值每次都会不同,所以我不能静态放置它们。有谁知道从哪里开始?我对 Objective-C 编程还是有点陌生。
我知道可以利用检索滑块在屏幕上的起始 X 坐标,如下所示:
- (float)xPositionFromSliderValue:(UISlider *)aSlider;
{
float sliderRange = aSlider.frame.size.width - aSlider.currentThumbImage.size.width;
float sliderOrigin = aSlider.frame.origin.x + (aSlider.currentThumbImage.size.width / 2.0);
float sliderValueToPixels = (((aSlider.value-aSlider.minimumValue)/(aSlider.maximumValue-aSlider.minimumValue)) * sliderRange) + sliderOrigin);
return sliderValueToPixels;
}
也许我可以在 for 循环中添加一个计算来根据它放置图像。我只是不太确定从哪里开始...
我认为您在定位刻度线时会遇到麻烦。但是,如果你的 UISlider 的父视图是 "view",你添加一个这样的子视图:
[view addSubView:myTickView];
添加的子视图的位置由其框架 属性 决定,它在父视图坐标 space 中。 要删除视图,您可以这样做:
[myTickView removeFromSuperView];
您还可以遍历刻度视图并更改那里的帧,但这些更改将是动画的,因此如果您这样做,刻度将看起来像在滑动,除非您关闭动画。
提供了方法 trackRectForBounds 和 thumbRectForBounds 用于子类化 UISlider,但您可以直接调用它们,它们会预先获取您的刻度中心。
- (float)sliderThumbCenter:(UISlider *)slider forValue:(float)value{
CGRect trackRect = [slider trackRectForBounds:slider.bounds];
CGRect thumbRect = [slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value];
CGFloat centerThumb = CGRectGetMidX(thumbRect);
return centerThumb;
}
做一个自定义视图来绘制轨道可能比图像视图更容易,然后只需将滑块放在它上面并隐藏轨道。只需使滑块框架等于 TickView 的边界即可。真的,我认为 UISlider 子类会更好,但这有效!
@interface TickView : UIView
@property UIColor *tickColor;
@property int tickCount;
@property CGFloat tickHeight;
@property (weak) UISlider *slider;
@property float *ticks;
-(void)setTicks:(float *)ticks count:(int)tickCount;
@end
@implementation TickView{
__weak UISlider *_slider;
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.tickColor = [UIColor grayColor];
self.backgroundColor = [UIColor clearColor];
self.tickCount = 7;
self.ticks = malloc(sizeof(float) * self.tickCount);
self.tickHeight = 10;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, self.tickColor.CGColor);
CGContextBeginPath(context);
CGFloat centerY = rect.size.height / 2;
CGContextMoveToPoint(context, 0, centerY);
CGContextAddLineToPoint(context, rect.size.width, centerY);
CGFloat tickTop = centerY - self.tickHeight / 2;
CGFloat tickBottom = centerY + self.tickHeight / 2;
CGFloat tickX = 0;
if (self.slider) {
for (int i = 0; i < self.tickCount; i++) {
tickX = [self sliderThumbCenter:self.slider forValue:self.ticks[i]];
CGContextMoveToPoint(context, tickX, tickTop);
CGContextAddLineToPoint(context, tickX, tickBottom);
}
}
else{
CGFloat tickSpacing = rect.size.width / (self.tickCount - 1);
for (int i = 0; i < self.tickCount; i++) {
CGContextMoveToPoint(context, tickX, tickTop);
CGContextAddLineToPoint(context, tickX, tickBottom);
tickX += tickSpacing;
}
}
CGContextStrokePath(context);
}
-(void)setTicks:(float *)ticks count:(int)tickCount{
free(_ticks);
_ticks = malloc(sizeof(float) * tickCount);
memcpy(_ticks, ticks, sizeof(float) * tickCount);
_tickCount = tickCount;
[self setNeedsDisplay];
}
- (float)sliderThumbCenter:(UISlider *)slider forValue:(float)value{
CGRect trackRect = [slider trackRectForBounds:slider.bounds];
CGRect thumbRect = [slider thumbRectForBounds:slider.bounds trackRect:trackRect value:value];
CGFloat centerThumb = CGRectGetMidX(thumbRect);
return centerThumb;
}
-(void)setSlider:(UISlider *)slider{
_slider = slider;
}
-(UISlider *)slider{
return _slider;
}
-(void)dealloc{
free(_ticks);
}
@end