I want to add a label to the slider's thumb which should show the value of the slider and changes too when thumbs is being dragged towards right side. Is it possible??
Any comments or suggestion would be appreciated.
I want to add a label to the slider's thumb which should show the value of the slider and changes too when thumbs is being dragged towards right side. Is it possible??
Any comments or suggestion would be appreciated.
You could do something similar to this example which draws text directly to your thumb image. It's a rough example so you will need to change it to make sense for your project.
- (IBAction)sliderValueChanged:(id)sender {
UISlider *aSlider = (UISlider *)sender;
NSString *strForThumbImage =
[NSString stringWithFormat:@"%.0f", aSlider.value * 100]
UIImage *thumbImage = [self addText:self.thumbImage
text:strForThumbImage];
[aSlider setThumbImage:thumbImage forState:aSlider.state];
}
//Add text to UIImage
-(UIImage *)addText:(UIImage *)img text:(NSString *)text1{
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate( NULL,
w,
h,
8,
4 * w,
colorSpace,
kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
char* text= (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSelectFont(context, "Arial",12, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
CGContextShowTextAtPoint(context,3,8,text, strlen(text));
CGImageRef imgCombined = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *retImage = [UIImage imageWithCGImage:imgCombined];
CGImageRelease(imgCombined);
return retImage;
}
I grab the thumb image from the slider (UIImageView) and add my label to it. Nice and clean.
UIImageView *handleView = [slider.subviews lastObject];
UILabel *label = [[UILabel alloc] initWithFrame:handleView.bounds];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
[handleView addSubview:label];
self.sliderLabel = label;
Then you change the label.text whenever you need to.
Note: the subview order of UISlider could change in the future, however it's unlikely that the thumb would no longer be the topmost view, as it will always be the main point of interaction in a slider.
Swift 3 -- More detailed example (link your slider in IB)
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var slider: UISlider!
var sliderLabel: UILabel?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let handleView = slider.subviews.last as? UIImageView {
let label = UILabel(frame: handleView.bounds)
label.backgroundColor = .clear
label.textAlignment = .center
handleView.addSubview(label)
self.sliderLabel = label
//set label font, size, color, etc.
label.text = "!!"
}
}
}
Add a UISlider
and a UILabel
in Interface Builder. Create IBOutlets to access them in code and add a IBAction to respond to changes of the slider value.
Then in your code write:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.slider addSubview:self.label];
[self valueChanged:self.slider];
}
- (IBAction)valueChanged:(id)sender {
self.label.center = CGPointMake(self.slider.value*self.slider.bounds.size.width, 40);
self.label.text = [NSString stringWithFormat:@"%0.2f", self.slider.value];
}
EDIT: To create the slider and label with code add this:
-(void)loadView {
[super loadView];
self.slider = [[[UISlider alloc] initWithFrame:CGRectMake(50, 150, 200, 30)] autorelease];
self.label = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 30)] autorelease];
[self.label setBackgroundColor:[UIColor clearColor]];
[self.slider addTarget:self action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:self.slider];
}
You can access the rect for the slider's thumb image view with -thumbRectForBounds:trackRect:value:]
, so if you add a UILabel
subview you can align it relative to the thumb image view in -layoutSubviews
using this returned rect.
However, if you'd like to use Autolayout to align your label with the thumb image then you need access to the thumb's UIImageView
directly. I'm not keen on spelunking the subviews of UIKit
kit components generally, but I think you can use details of the public API to search for the image view in a future-proofed way:
- (UIImageView*) thumbImageView {
__block UIImageView *imageView = nil;
[self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIImageView *candidate, NSUInteger idx, BOOL *stop)
{
if ([candidate isKindOfClass:[UIImageView class]] && candidate.image ==
[self thumbImageForState:UIControlStateNormal])
{
imageView = candidate;
*stop = YES;
}
}];
return imageView;
}
The API provides the ability to set a UIImage
for the thumb, so you can use this as a test to ensure that you aren't getting some other image view. This is even safer if you are explicitly setting a thumb image yourself (since it's not impossible that the slider might be changed to draw the thumb image in future...). Also, the thumb image view is currently the last subview (not guaranteed going forward), so I'm doing a reverse enumeration here to hopefully get it as faster as possible whilst not making assumptions about its index.
NB: I had to create my thumb label lazily, since UISlider
's subviews seem to be so.
A simple implementation of a custom class in Swift 3.2. This is working nicely for me.
class ThumbTextSlider: UISlider {
var thumbTextLabel: UILabel = UILabel()
private var thumbFrame: CGRect {
return thumbRect(forBounds: bounds, trackRect: trackRect(forBounds: bounds), value: value)
}
override func layoutSubviews() {
super.layoutSubviews()
thumbTextLabel.frame = thumbFrame
thumbTextLabel.text = Double(value).roundTo(places: 1).description
}
override func awakeFromNib() {
super.awakeFromNib()
addSubview(thumbTextLabel)
thumbTextLabel.textAlignment = .center
thumbTextLabel.layer.zPosition = layer.zPosition + 1
}
}
I hope it helps :)
- (IBAction)valueChangedSlider:(id)sender {
handleView = [_slider.subviews lastObject];
label = [[UILabel alloc] initWithFrame:handleView.bounds];
label = (UILabel*)[handleView viewWithTag:1000];
if (label==nil) {
label = [[UILabel alloc] initWithFrame:handleView.bounds];
label.tag = 1000;
[label setFont:[UIFont systemFontOfSize:12]];
label.textColor = [UIColor redColor];
label.backgroundColor = [UIColor clearColor];
label.textAlignment = NSTextAlignmentCenter;
[handleView addSubview:label];
}
label.text = [NSString stringWithFormat:@"%0.2f", self.slider.value];
}
make this nice and easy.. first off this is the final result
and now, code:
UILabel *sl = [UILabel new];
[v addSubview:sl];
[sl constraintHeightEqualTo:12 widthTo:26];
UIImageView *handleView = [slider.subviews lastObject];
[self.view constraintVerticalSpacingSubviewsFromBottomView:s toTopView:sl constant:10];
[self.view constraintCenterXOfView:sl equalToView:handleView];
[sl setText:@"100%"];
[sl setFont:[UIFont systemFontOfSize:10]];
self.sliderLabel = sl;
the above methods are used from an NSLayoutConstraint
category i use (coming soon)
- (id)constraintHeightEqualTo:(CGFloat)height widthTo:(CGFloat)width
{
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
[self constraintHeightEqualTo:height];
[self constraintWidthEqualTo:width];
return self;
}
- (id)constraintVerticalSpacingSubviewsFromBottomView:(UIView *)fromView toTopView:(UIView *)toView constant:(CGFloat)constant
{
NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:fromView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:toView
attribute:NSLayoutAttributeBottom
multiplier:1
constant:constant];
[self addConstraint:cn];
return self;
}
- (id)constraintCenterXOfView:(UIView *)fromView equalToView:(UIView *)toView constant:(CGFloat)constant
{
NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:fromView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:toView
attribute:NSLayoutAttributeCenterX
multiplier:1 constant:constant];
[self addConstraint:cn];
return self;
}
Well, I subclassed the UISlider and override the methods of NSControl. You just need to change your class into storyboard
I label can be add above thumb as per requirement.
class CustomSlider: UISlider {
let label = UILabel()
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let track = super.beginTracking(touch, with: event)
label.text = "\(Int(self.value))"
label.frame = CGRect.init(x: self.thumbCenterX, y: -10, width: 20, height: 20)
self.addSubview(label)
return track
}
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let track = super.continueTracking(touch, with: event)
label.frame = CGRect.init(x: self.thumbCenterX - 5 , y: 6, width: 30, height: 20)
label.text = "\(Int(self.value))"
return track
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
super.endTracking(touch, with: event)
label.removeFromSuperview()
}}
extension UISlider {
var thumbCenterX: CGFloat {
let trackRect = self.trackRect(forBounds: frame)
let thumbRect = self.thumbRect(forBounds: bounds, trackRect: bounds, value: value)
return thumbRect.midX
}}