objective c - UISlider con ProgressView combinado
objective-c ios4 (8)
Añadiendo la solución de mate, tenga en cuenta que a partir de iOS 7.0, la implementación de trackRectForBounds: se hace imposible. Aquí está mi solución a este problema:
En su subclase UISlider, haga esto:
-(void)awakeFromNib
{
[super awakeFromNib];
UIImage* clearColorImage = [UIImage imageWithColor:[UIColor clearColor]];
[self setMinimumTrackImage:clearColorImage forState:UIControlStateNormal];
[self setMaximumTrackImage:clearColorImage forState:UIControlStateNormal];
}
con imageWithColor como esta función:
+ (UIImage*) imageWithColor:(UIColor*)color
{
return [UIImage imageWithColor:color andSize:CGSizeMake(1.0f, 1.0f)];
}
Eso se encargará adecuadamente de este molesto trackRectangle.
Pasé demasiado tiempo buscando una solución a este problema, aquí espero que ahorrará tiempo a otra pobre alma;).
¿Existe una forma de hacer apple-house para obtener un UISlider con un ProgressView? Esto es utilizado por muchas aplicaciones de transmisión, por ejemplo, nativo quicktimeplayer o youtube. (Solo para estar seguro: solo estoy interesado en la visualización)
anima a Simon
Aquí hay una versión simple de lo que describes.
Es "simple" en el sentido de que no me molesté en intentar agregar el sombreado y otras sutilezas. Pero es fácil de construir y puedes modificarlo para dibujar de una manera más sutil si quieres. Por ejemplo, podría hacer su propia imagen y usarla como el control deslizante.
Esta es en realidad una subclase UISlider que se encuentra en la parte superior de una subclase UIView (MyTherm) que dibuja el termómetro, más dos UILabels que dibujan los números.
La subclase UISlider elimina la pista incorporada, de modo que se ve el termómetro detrás de ella. Pero el pulgar (control) del UISlider aún se puede arrastrar de la manera normal, y puede establecerlo en una imagen personalizada, obtener el evento Value Changed cuando el usuario lo arrastra, y así sucesivamente. Aquí está el código para la subclase UISlider que elimina su propia pista:
- (CGRect)trackRectForBounds:(CGRect)bounds {
CGRect result = [super trackRectForBounds:bounds];
result.size.height = 0;
return result;
}
El termómetro es una instancia de una subclase UIView personalizada, MyTherm. Lo instancia en la punta y desactivé su opaco y le di un color de fondo de color claro. Tiene una propiedad de value
por lo que sabe cuánto llenar el termómetro. Aquí está su drawRect:
código:
- (void)drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] set];
CGFloat ins = 2.0;
CGRect r = CGRectInset(self.bounds, ins, ins);
CGFloat radius = r.size.height / 2.0;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, CGRectGetMaxX(r) - radius, ins);
CGPathAddArc(path, NULL, radius+ins, radius+ins, radius, -M_PI/2.0, M_PI/2.0, true);
CGPathAddArc(path, NULL, CGRectGetMaxX(r) - radius, radius+ins, radius, M_PI/2.0, -M_PI/2.0, true);
CGPathCloseSubpath(path);
CGContextAddPath(c, path);
CGContextSetLineWidth(c, 2);
CGContextStrokePath(c);
CGContextAddPath(c, path);
CGContextClip(c);
CGContextFillRect(c, CGRectMake(r.origin.x, r.origin.y, r.size.width * self.value, r.size.height));
}
Para cambiar el valor del termómetro, cambie el valor de la instancia MyTherm a un número entre 0 y 1, y dígale que setNeedsDisplay
a dibujar con setNeedsDisplay
.
Crea un UISlider:
// 1
// Make the slider as a public propriety so you can access it
playerSlider = [[UISlider alloc] init];
[playerSlider setContinuous:YES];
[playerSlider setHighlighted:YES];
// remove the slider filling default blue color
[playerSlider setMaximumTrackTintColor:[UIColor clearColor]];
[playerSlider setMinimumTrackTintColor:[UIColor clearColor]];
// Chose your frame
playerSlider.frame = CGRectMake(--- , -- , yourSliderWith , ----);
// 2
// create a UIView that u can access and make it the shadow of your slider
shadowSlider = [[UIView alloc] init];
shadowSlider.backgroundColor = [UIColor lightTextColor];
shadowSlider.frame = CGRectMake(playerSlider.frame.origin.x , playerSlider.frame.origin.y , playerSlider.frame.size.width , playerSlider.frame.origin.size.height);
shadowSlider.layer.cornerRadius = 4;
shadowSlider.layer.masksToBounds = YES;
[playerSlider addSubview:shadowSlider];
[playerSlider sendSubviewToBack:shadowSlider];
// 3
// Add a timer Update your slider and shadow slider programatically
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES];
-(void)updateSlider {
// Update the slider about the music time
playerSlider.value = audioPlayer.currentTime; // based on ur case
playerSlider.maximumValue = audioPlayer.duration;
float smartWidth = 0.0;
smartWidth = (yourSliderFullWidth * audioPlayer.duration ) / 100;
shadowSlider.frame = CGRectMake( shadowSlider.frame.origin.x , shadowSlider.frame.origin.y , smartWidth , shadowSlider.frame.size.height);
}
¡Disfrutar! PD: podría tener algunos errores tipográficos.
Esto es posible usando los controles estándar.
En Interface Builder coloque su UISlider
inmediatamente sobre su UIProgressView
y UIProgressView
del mismo tamaño.
En un UISlider
la línea horizontal de fondo se llama pista, el truco es hacerla invisible. Hacemos esto con un PNG transparente y los métodos de setMinimumTrackImage:forState:
y setMaximumTrackImage:forState:
En el método viewDidLoad
de su controlador de vista, agregue:
[self.slider setMinimumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
donde self.slider
refiere a su UISlider
.
He probado el código en Xcode, y esto le dará un control deslizante con una barra de progreso independiente.
Puedes hacer un truco como este, es más fácil y comprensivo. Solo inserte el código de abajo en su subclase UISlider.
- (void)layoutSubviews
{
[super layoutSubviews];
if (_availableDurationImageView == nil) {
// step 1
// get max length that our "availableDurationImageView" will show
UIView *maxTrackView = [self.subviews objectAtIndex:self.subviews.count - 3];
UIImageView *maxTrackImageView = [maxTrackView.subviews objectAtIndex:0];
_maxLength = maxTrackImageView.width;
// step 2
// get the right frame where our "availableDurationImageView" will place in superView
UIView *minTrackView = [self.subviews objectAtIndex:self.subviews.count - 2];
_availableDurationImageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"MediaSlider.bundle/4_jindu_huancun.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)]];
_availableDurationImageView.opaque = NO;
_availableDurationImageView.frame = minTrackView.frame;
[self insertSubview:_availableDurationImageView belowSubview:minTrackView];
}
}
- (void)setAvailableValue:(NSTimeInterval)availableValue
{
if (availableValue >=0 && availableValue <= 1) {
// use "maxLength" and percentage to set our "availableDurationImageView" ''s length
_availableDurationImageView.width = _maxLength * availableValue;
}
}
Solución que se adapta a mi diseño:
class SliderBuffering:UISlider {
let bufferProgress = UIProgressView(progressViewStyle: .Default)
override init (frame : CGRect) {
super.init(frame : frame)
}
convenience init () {
self.init(frame:CGRect.zero)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
self.minimumTrackTintColor = UIColor.clearColor()
self.maximumTrackTintColor = UIColor.clearColor()
bufferProgress.backgroundColor = UIColor.clearColor()
bufferProgress.userInteractionEnabled = false
bufferProgress.progress = 0.0
bufferProgress.progressTintColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.5)
bufferProgress.trackTintColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
self.addSubview(bufferProgress)
}
}
Aquí hay una solución en Objective C. https://github.com/abhimuralidharan/BufferSlider
La idea es crear una vista UIProgress como una propiedad en la subclase UISlider y agregar las restricciones requeridas de forma programática.
#import <UIKit/UIKit.h> //.h file
@interface BufferSlider : UISlider
@property(strong,nonatomic) UIProgressView *bufferProgress;
@end
#import "BufferSlider.h" //.m file
@implementation BufferSlider
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
-(void)setup {
self.bufferProgress = [[UIProgressView alloc] initWithFrame:self.bounds];
self.minimumTrackTintColor = [UIColor redColor];
self.maximumTrackTintColor = [UIColor clearColor];
self.value = 0.2;
self.bufferProgress.backgroundColor = [UIColor clearColor];
self.bufferProgress.userInteractionEnabled = NO;
self.bufferProgress.progress = 0.7;
self.bufferProgress.progressTintColor = [[UIColor blueColor] colorWithAlphaComponent:0.5];
self.bufferProgress.trackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:2];
[self addSubview:self.bufferProgress];
[self setThumbImage:[UIImage imageNamed:@"redThumb"] forState:UIControlStateNormal];
self.bufferProgress.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0.75]; // edit the constant value based on the thumb image
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:self.bufferProgress attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
[self addConstraints:@[left,right,centerY]];
[self sendSubviewToBack:self.bufferProgress];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setup];
}
return self;
}
@end
Idea 1: podría usar fácilmente el UISlider como una vista de progreso al crear una subclasificación. Responde a métodos como ''setValue: animado:'' con el que puede establecer el valor (es decir, el progreso) de la vista.
Su única "restricción" que crea lo que ve en su ejemplo es la barra de búfer, que puede crear desollando "creativamente" el UISlider (porque puede agregarle máscaras personalizadas), y tal vez establecer ese skin programáticamente.
Idea 2: Otra opción (más fácil) es subclase UIProgressView y crear un UISlider dentro de esa subclase. Puede desollar el UISlider para tener una máscara transparente (sin barra, solo la perilla visible) y colocarla sobre UIProgressView.
Puede utilizar UIProgressView para precargar (almacenamiento en búfer) y UISlider para control de película / indicación de progreso.
Parece bastante fácil :-)
Editar: para responder realmente a su pregunta, no hay una forma interna, pero sería fácil de lograr con las herramientas dadas.