it-swarm.com.de

UISlider mit ProgressView kombiniert

Gibt es einen in Apple-Haus hergestellten Weg, um einen UISlider mit einer Fortschrittsansicht zu erhalten? Dies wird von vielen Streaming-Anwendungen verwendet, z. nativer Quicktimeplayer oder youtube. (Nur um sicher zu gehen: ich bin nur an der Visualisierung interessiert)

Slider with loader

prost, Simon

36
endo.anaconda

Hier ist eine einfache Version dessen, was Sie beschreiben.

alt text

Es ist "einfach" in dem Sinne, dass ich mich nicht bemüht habe, die Schattierung und andere Feinheiten hinzuzufügen. Es ist jedoch einfach zu konstruieren und Sie können es optimieren, um auf subtilere Weise zu zeichnen, wenn Sie möchten. Sie können beispielsweise ein eigenes Bild erstellen und es als Daumen des Schiebereglers verwenden.

Dies ist eine UISlider-Unterklasse, die auf einer UIView-Unterklasse (MyTherm) liegt, die das Thermometer zeichnet, und zwei UILabels, die die Zahlen zeichnen. 

Die UISlider-Unterklasse beseitigt die eingebaute Spur, so dass das dahinterliegende Thermometer sichtbar ist. Der Daumen (Drehknopf) des UISliders kann jedoch weiterhin auf normale Weise gezogen werden. Sie können ein benutzerdefiniertes Bild festlegen, das Ereignis "Value Changed" abrufen, wenn der Benutzer es zieht, und so weiter. Hier ist der Code für die UISlider-Unterklasse, die ihre eigene Spur entfernt:

- (CGRect)trackRectForBounds:(CGRect)bounds {
    CGRect result = [super trackRectForBounds:bounds];
    result.size.height = 0;
    return result;
}

Das Thermometer ist eine Instanz der benutzerdefinierten UIView-Unterklasse MyTherm. Ich habe es in der Feder instanziiert, das Deckende deaktiviert und ihm eine Hintergrundfarbe von Clear Color gegeben. Es hat eine value-Eigenschaft, so dass es weiß, wie viel das Thermometer gefüllt wird. Hier ist der drawRect: Code:

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

Um den Thermometerwert zu ändern, ändern Sie die value der MyTherm-Instanz in eine Zahl zwischen 0 und 1 und fordern Sie sie auf, sich mit setNeedsDisplay neu zu zeichnen.

47
matt

Dies ist mit den Standardsteuerelementen möglich. 

Platzieren Sie im Interface Builder Ihre UISlider unmittelbar auf Ihrer UIProgressView und machen Sie sie gleich groß.

Bei einer UISlider wird die horizontale Hintergrundlinie als Spur bezeichnet. Der Trick besteht darin, sie unsichtbar zu machen. Wir machen dies mit einem transparenten PNG und den UISlider-Methoden setMinimumTrackImage:forState: und setMaximumTrackImage:forState:.

Fügen Sie in der viewDidLoad-Methode Ihres View-Controllers Folgendes hinzu:

[self.slider setMinimumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];
[self.slider setMaximumTrackImage:[UIImage imageNamed:@"transparent.png"] forState:UIControlStateNormal];

dabei bezieht sich self.slider auf Ihre UISlider.

Ich habe den Code in Xcode getestet, und Sie erhalten einen Schieberegler mit einem unabhängigen Fortschrittsbalken.

20
Sam Doshi

Erstellen Sie einen 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);

   }

Genießen! P.S. Ich könnte Tippfehler haben.

4
Emile Khattar

Lösung, die zu meinem Design passt:

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

 

4
Vitalka

Idee 1: Sie können den UISlider leicht als Fortschrittsansicht verwenden, indem Sie ihn unterteilen. Es reagiert auf Methoden wie 'setValue: animated:', mit denen Sie den Wert (dh Fortschritt) der Ansicht einstellen können.

Ihre einzige "Einschränkung" beim Erstellen des in Ihrem Beispiel gezeigten Beispiels ist die Pufferleiste, die Sie erstellen können, indem Sie den UISlider "kreativ" verkleiden (da Sie ihm benutzerdefinierte Skins hinzufügen können) und diese Skin möglicherweise programmgesteuert festlegen.

Idee 2: Eine weitere (einfachere) Option ist die Unterklasse UIProgressView und das Erstellen eines UISliders innerhalb dieser Unterklasse. Sie können den UISlider für einen durchsichtigen Skin (keine Leiste, nur den sichtbaren Knopf) mit Skin versehen und ihn über die UIProgressView legen.

Sie können den UIProgressView zum Vorladen (Pufferung) und den UISlider zur Anzeige der Filmsteuerungfortschritt verwenden.

Scheint ziemlich einfach :-)

/ - Bearbeiten: Um Ihre Frage tatsächlich zu beantworten, gibt es keinen internen Weg, aber es wäre leicht, mit den angegebenen Tools zu arbeiten.

2
Jake

Du kannst so einen Trick machen, es ist einfacher und verständnisvoller. Fügen Sie einfach den untenstehenden Code in Ihre UISlider-Unterklasse ein.

- (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;
    }
}
1
John

Hier ist eine Lösung in Objective C. https://github.com/abhimuralidharan/BufferSlider

Die Idee ist, einen UIProgressview als Eigenschaft in der UISlider-Unterklasse zu erstellen und die erforderlichen Einschränkungen programmgesteuert hinzuzufügen.

#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
0
abhi1992

Beachten Sie, dass ab matt 7.0 die Implementierung von trackRectForBounds: ab iOS 7.0 unmöglich ist. Hier ist meine Lösung für dieses Problem:

Führen Sie in Ihrer UISlider-Unterklasse Folgendes aus:

-(void)awakeFromNib
{
    [super awakeFromNib];

    UIImage* clearColorImage = [UIImage imageWithColor:[UIColor clearColor]];
    [self setMinimumTrackImage:clearColorImage forState:UIControlStateNormal];
    [self setMaximumTrackImage:clearColorImage forState:UIControlStateNormal];
}

mit imageWithColor als Funktion:

+ (UIImage*) imageWithColor:(UIColor*)color
{
    return [UIImage imageWithColor:color andSize:CGSizeMake(1.0f, 1.0f)];
}

Damit wird das nervige TrackRectangle richtig erledigt.

Ich habe zu viel Zeit damit verbracht, nach einer Lösung für dieses Problem zu suchen. Ich hoffe, das spart Zeit für eine andere arme Seele;).

0
CyberDandy