UISlider con ProgressView combinado

¿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)

Control deslizante con cargador

anima a Simon

    Aquí hay una versión simple de lo que describes.

    texto alternativo

    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 (mando) del UISlider todavía 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 .

    Esto es factible 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.

    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 progtwigtically [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.

    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) } } 

    Idea 1: podría usar fácilmente el UISlider como una vista de progreso subclasificándolo. 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 podría 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.

    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; } } 

    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;).

    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  //.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