web-dev-qa-db-ja.com

ProgressViewを組み合わせたUISlider

ProgressViewでUISliderを取得するアップル独自の方法はありますか?これは、多くのストリーミングアプリケーションで使用されます。ネイティブのquicktimeplayerまたはyoutube。 (念のため:私は興味のあるビジュアライゼーションにのみ参加しています)

Slider with loader

乾杯サイモン

38
endo.anaconda

ここにあなたが説明しているものの簡単なバージョンがあります。

alt text

シェーディングやその他の微妙な要素を追加する手間を省いたという意味では「シンプル」です。ただし、作成は簡単で、必要に応じて微調整して微妙な方法で描画できます。たとえば、独自の画像を作成し、それをスライダーのつまみとして使用できます。

これは実際には、温度計を描画するUIViewサブクラス(MyTherm)の上にあるUISliderサブクラスと、数値を描画する2つのUILabelsです。

UISliderサブクラスは組み込みのトラックを削除するため、背後の温度計が透けて見えます。ただし、UISliderのつまみ(つまみ)は通常の方法で引き続きドラッグでき、カスタムイメージに設定したり、ユーザーがドラッグしたときにValue Changedイベントを取得したりできます。次に、独自のトラックを削除するUISliderサブクラスのコードを示します。

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

温度計は、カスタムUIViewサブクラスMyThermのインスタンスです。ペン先にインスタンス化し、不透明度をオフにして、背景色をクリアカラーにしました。それは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));
}

温度計の値を変更するには、MyThermインスタンスのvalueを0から1までの数値に変更し、setNeedsDisplayで再描画するように指示します。

47
matt

これは、標準のコントロールを使用して実行できます。

Interface BuilderでUISliderUIProgressViewのすぐ上に配置し、同じサイズにします。

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.sliderUISliderを指します。

Xcodeでコードをテストしました。これにより、独立した進行状況バーを備えたスライダーが表示されます。

20
Sam Doshi

私のデザインに合ったソリューション:

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

5
Vitalka

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

   }

楽しい!追伸タイプミスがあるかもしれません。

4
Emile Khattar

アイデア1: UISliderをサブクラス化することにより、進行状況ビューとして簡単に使用できます。ビューの値(進行状況)を設定できる「setValue:animated:」などのメソッドに応答します。

例に表示されるものを作成する唯一の「制限」はバッファバーで、UISliderに「創造的に」スキニングすることで作成でき(カスタムスキンを追加できるため)、おそらくそのスキンをプログラムで設定できます。

Idea 2:別の(簡単な)オプションは、UIProgressViewをサブクラス化し、そのサブクラス内にUISliderを作成することです。 UISliderにスキンを適用してシースルースキン(バーはなく、ノブだけが表示されている)にして、UIProgressViewの上に配置できます。

プリロード(バッファリング)にはUIProgressViewを使用し、ムービーコントロール/進行状況の表示にはUISliderを使用できます。

かなり簡単に見える:-)

編集:実際にあなたの質問に答えるために、社内での方法はありませんが、与えられたツールで簡単に達成できます。

3
Jake

あなたはこのようにいくつかのトリックを行うことができます、それはより簡単で理解しやすいです。 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;
    }
}
1
John

これはObjective Cのソリューションです。https://github.com/abhimuralidharan/BufferSlider

アイデアは、UISliderサブクラスのプロパティとしてUIProgressviewを作成し、必要な制約をプログラムで追加することです。

#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

Mattのソリューションを追加すると、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が適切に処理されます。

私はこの問題の解決策を探すのにあまりにも多くの時間を費やしました、これが別の貧しい魂に時間を節約することを望んでいます;).

0
CyberDandy