UISlider с ProgressView в сочетании - PullRequest
36 голосов
/ 21 декабря 2010

Существует ли способ производства UISlider с помощью ProgressView, созданный компанией Apple. Это используется многими потоковыми приложениями, например, родной QuickTimePlayer или YouTube. (Просто чтобы быть уверенным: меня интересует только визуализация)

Slider  with loader

ура Саймон

Ответы [ 8 ]

47 голосов
/ 02 января 2011

Вот простая версия того, что вы описываете.

alt text

Это "просто" в том смысле, что я не стал пытаться добавить затенение и другие тонкости. Но это легко построить, и вы можете настроить его, чтобы нарисовать более тонким способом, если хотите. Например, вы можете создать собственное изображение и использовать его как большой палец слайдера.

На самом деле это подкласс UISlider, лежащий поверх подкласса UIView (MyTherm), который рисует термометр, плюс две метки UILabel, которые рисуют числа.

Подкласс UISlider исключает встроенную дорожку, так что термометр позади нее просвечивает. Но большой палец (ручка) UISlider по-прежнему можно перетаскивать в обычном режиме, и вы можете установить его на собственное изображение, получить событие Value Changed, когда пользователь перетаскивает его, и так далее. Вот код для подкласса UISlider, который исключает собственную дорожку:

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

Термометр является экземпляром пользовательского подкласса UIView, MyTherm. Я создал его в перо, снял флажок с Opaque и дал цвет фона Clear Color. У него есть свойство value, поэтому он знает, сколько нужно заполнить термометром. Вот его drawRect: код:

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

Чтобы изменить значение термометра, измените значение value экземпляра MyTherm на число от 0 до 1 и попросите его перерисовать себя с помощью setNeedsDisplay.

20 голосов
/ 31 декабря 2010

Это выполнимо с использованием стандартных элементов управления.

В Интерфейсном Разработчике поместите ваш UISlider сразу поверх вашего UIProgressView и сделайте их одинакового размера.

На UISlider горизонтальная линия фона называется дорожкой,Хитрость заключается в том, чтобы сделать его невидимым.Мы делаем это с помощью прозрачного PNG и UISlider методов setMinimumTrackImage:forState: и setMaximumTrackImage:forState:.

В методе viewDidLoad вашего контроллера представления добавьте:

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

где self.slider относится к вашему UISlider.

Я проверил код в XCode, и это даст вам ползунок с независимым индикатором выполнения.

4 голосов
/ 31 марта 2016

Решение, подходящее моему дизайну:

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 голосов
/ 13 ноября 2012

Создать 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);

   }

Наслаждайтесь! Постскриптум У меня могут быть некоторые опечатки.

3 голосов
/ 27 декабря 2010

Идея 1: Вы можете легко использовать UISlider как вид прогресса, подклассифицируя его.Он реагирует на такие методы, как 'setValue: animated:', с помощью которых вы можете установить значение (то есть: прогресс) представления.

Единственным «ограничением», создающим то, что вы видите в своем примере, является панель буфера, который вы могли бы создать, «творчески» сделав скин для UISlider (потому что вы можете добавить к нему собственные скины), и, возможно, установить этот скин программным способом.это подкласс UIProgressView и создать UISlider внутри этого подкласса.Вы можете сделать скин UISlider прозрачным (без полосы, только видимая ручка) и наложить его на UIProgressView.

Вы можете использовать UIProgressView для предварительной загрузки (буферизации) и UISlider.для управления фильмом / индикации прогресса.

Кажется довольно простым: -)

Редактировать: , чтобы фактически ответить на ваш вопрос, нет никакого внутреннего способа, но это будетлегко выполнить с помощью предоставленных инструментов.

1 голос
/ 22 ноября 2013

Вы можете сделать такой трюк, как этот, это проще и понятнее.Просто вставьте приведенный ниже код в ваш подкласс 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;
    }
}
0 голосов
/ 06 декабря 2017

Вот решение в задаче C. https://github.com/abhimuralidharan/BufferSlider

Идея состоит в том, чтобы создать UIProgressview как свойство в подклассе UISlider и программно добавить необходимые ограничения.

#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 голосов
/ 11 мая 2014

Добавляя к решению Мэтта, обратите внимание, что в iOS 7.0 реализация trackRectForBounds: представляется невозможной. Вот мое решение этой проблемы:

В вашем подклассе UISlider сделайте следующее:

-(void)awakeFromNib
{
    [super awakeFromNib];

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

с imageWithColor в качестве этой функции:

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

Это правильно позаботится об этом надоедливом trackRectangle.

Я потратил слишком много времени на поиск решения этой проблемы, надеясь, что это сэкономит время другой бедной душе;)

...