Objective C UISlider 仅更改最小轨迹图像

Posted

技术标签:

【中文标题】Objective C UISlider 仅更改最小轨迹图像【英文标题】:Objactive C UISlider changing minimum track image only 【发布时间】:2019-10-31 13:02:31 【问题描述】:

我正在尝试使用带有 CAGradientLayer 的图像来设置滑块的MinimumTrackImage,比如说使用蓝色和红色。

发生的情况是,整个轨道获得渐变颜色,它以红色开始,向右滑动拇指显示蓝色。 我希望颜色从红色开始到蓝色直到拇指,并随着拇指的移动而“伸展”。

有什么想法吗?我虽然关于设置slider.maximumValue = slider...width 并在我听滑块值更改时更改渐变图像,但它不起作用

【问题讨论】:

【参考方案1】:

我认为您尝试设置最小轨道图像不会成功。

选项是一个完全自定义的滑块...

将最小轨道图像设置为清晰图像,在滑块后面添加带有渐变图像的imageView,拉伸imageView的框架以匹配拇指移动。

这是一个例子:

和代码(只是一个起点......将其包装到子类中会更好):


SliderTestViewController.h

//
//  SliderTestViewController.h
//
//  Created by Don Mag on 10/31/19.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SliderTestViewController : UIViewController

@end

NS_ASSUME_NONNULL_END

SliderTestViewController.m

//
//  SliderTestViewController.m
//
//  Created by Don Mag on 10/31/19.
//

#import "SliderTestViewController.h"
#import "UIImage+Utils.h"

@interface SliderTestViewController ()

@property (strong, nonatomic) UIImageView *theFakeSliderTrackImageView;
@property (strong, nonatomic) UISlider *theSlider;
@property (strong, nonatomic) NSLayoutConstraint *imgWidthConstraint;

@end

@implementation SliderTestViewController

- (void)viewDidLoad 
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    // instantiate a slider
    _theSlider = [UISlider new];

    // instantiate an image view to use as our custom / fake "left side" of the slider track
    _theFakeSliderTrackImageView = [UIImageView new];

    // we want the image to stretch
    _theFakeSliderTrackImageView.contentMode = UIViewContentModeScaleToFill;

    // create a horizontal gradient image to use for our "left side" of the slider track
    // the image will be stretched... using a width of 128 seems reasonable
    UIImage *gradImg = [UIImage gradientImageWithSize:CGSizeMake(128.0, 4.0) startColor:[UIColor blueColor] endColor:[UIColor redColor] startPoint:CGPointMake(0.0, 0.0) endPoint:CGPointMake(1.0, 0.0)];

    // set the gradient image to our image view
    _theFakeSliderTrackImageView.image = gradImg;

    // create a clear image to use for the slider's min track image
    UIImage *clearImg = [UIImage imageWithColor:[UIColor clearColor] size:CGSizeMake(1.0, 1.0)];

    // set min track image to clear image
    [_theSlider setMinimumTrackImage:clearImg forState:UIControlStateNormal];

    // set max track image if desired
    //  [_theSlider setMaximumTrackImage:anImage forState:UIControlStateNormal];

    _theFakeSliderTrackImageView.translatesAutoresizingMaskIntoConstraints = NO;
    _theSlider.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview:_theFakeSliderTrackImageView];
    [self.view addSubview:_theSlider];

    [NSLayoutConstraint activateConstraints:@[

        // constrain the slider centerY with 20-pts leading / trailing
        [_theSlider.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [_theSlider.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
        [_theSlider.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0],

        // constrain image view centerY to slider centerY
        [_theFakeSliderTrackImageView.centerYAnchor constraintEqualToAnchor:_theSlider.centerYAnchor constant:0.0],
        // constrain image view leading to slider leading
        [_theFakeSliderTrackImageView.leadingAnchor constraintEqualToAnchor:_theSlider.leadingAnchor constant:0.0],
        // image view height to 5-pts (adjust as desired)
        [_theFakeSliderTrackImageView.heightAnchor constraintEqualToConstant:5.0],

    ]];

    // init imageView width constraint to 0.0
    _imgWidthConstraint = [_theFakeSliderTrackImageView.widthAnchor constraintEqualToConstant:0.0];
    _imgWidthConstraint.active = YES;

    [_theSlider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];



- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];
    [self updateSliderGradientImage];


- (void)updateSliderGradientImage 
    // set "fake track" imageView width to origin.x of thumb rect (plus 2 for good measure)
    CGRect trackRect = [_theSlider trackRectForBounds:_theSlider.bounds];
    CGRect thumbRect = [_theSlider thumbRectForBounds:_theSlider.bounds trackRect:trackRect value:_theSlider.value];
    _imgWidthConstraint.constant = thumbRect.origin.x + 2;


- (void)sliderChanged:(id)sender 
    [self updateSliderGradientImage];


@end

UIImage+Utils.h

//
//  UIImage+Utils.h
//
//  Created by Don Mag on 10/31/19.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIImage (Utils)

+ (nullable UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
+ (nullable UIImage *)gradientImageWithSize:(CGSize)size startColor:(UIColor *)startColor endColor:(UIColor *)endColor startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;

@end

NS_ASSUME_NONNULL_END

UIImage+Utils.m

//
//  UIImage+Utils.m
//
//  Created by Don Mag on 10/31/19.
//

#import "UIImage+Utils.h"

@implementation UIImage (Utils)

+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size 

    if (!color || size.height < 1 || size.width < 1)
        return nil;

    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];

    UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) 
        [color setFill];
        [context fillRect:renderer.format.bounds];
    ];

    return image;



+ (UIImage *)gradientImageWithSize:(CGSize)size startColor:(UIColor *)startColor endColor:(UIColor *)endColor startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint 

    if (!startColor || !endColor)
        return nil;

    CFArrayRef colors = (__bridge CFArrayRef) [NSArray arrayWithObjects:
                                               (id)startColor.CGColor,
                                               (id)endColor.CGColor,
                                               nil];

    CGGradientRef g = CGGradientCreateWithColors(nil, colors, nil);

    startPoint.x *= size.width;
    startPoint.y *= size.height;
    endPoint.x *= size.width;
    endPoint.y *= size.height;

    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];

    UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) 
        CGContextDrawLinearGradient(rendererContext.CGContext, g, startPoint, endPoint, kCGGradientDrawsAfterEndLocation);
    ];

    return gradientImage;



@end

【讨论】:

以上是关于Objective C UISlider 仅更改最小轨迹图像的主要内容,如果未能解决你的问题,请参考以下文章

在 Objective C 中为 UISlider 创建没有情节提要的 Outlet 和 Action

Objective C / iPhone - 如何将 UISlider 绑定到代码

如何在 Objective-C 中的 UISlider 上添加标记? [关闭]

Objective-c,AVPlayer 中的 UISlider 无法正常工作,在洗涤器之后

目标 C - 如何使用按钮单击操作更改 UIslider 值

根据 UISlider 值不断更新标签