Display UIProgressView with percentage in iOS - ios

How can I display a UIProgressView with a percentage?

As Vlad mentioned you can have a method which updates the value of progressView and its associated label. Call the following method when any update happens.
- (void)updateProgress
{
CGFloat stepSize = 0.1f;
[self.progressView setProgress:self.progressView.progress+stepSize];
self.progressLabel.text = [NSString stringWithFormat:#"Completed : %.0f",self.progressView.progress*100];
}

The progress indicator control does not offer the option of also displaying progress percent.
In order to achieve this, one solution would be to add a label positioned below / above your progress bar, and at each step when you refresh the progress on your progress indicator view, you also update the string value in on your label to display the percentage loaded.

There is one widget already available in iOS SDK - UIProgressView
Where you can set and get its property: progress
Hope this may help you.

Related

Xcode 8 - Some buttons border removed

I just updated my Xcode ver from 7.3 to 8.0 and some buttons borders disappeared.
The code looks fine, so I really don't know what happened to the layers.
btw - in some other controllers I can see the layers borders.
self.button.layer.borderColor = borderColor.CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = CGRectGetHeight(self.button.frame) / 2;
before: (The image is only for example - the borders looks different at real time)
now:
The reason is that XCode 8 introduces a new way to zoom in Storyboards.
Before XCode 8, in the view controller life cycle, frames were not known in viewDidLoad (or in properties didSet). You had to wait until viewDidLayoutSubviews (which is when Autolayout had finished applying the constraints to determine the frames of every subview in the main view.
But bounds were accessible before that: they were just set to the size of the IBOutlet in the storyboard.
In XCode 8, things are different : due to their new zooming system, even the boundsare not correct before ViewDidLayoutSubviews (they may exist but with dummy values like 1000 x 1000).
In conclusion :
you can use such things as cornerRadius in viewDidLoad or in the IBOutlet
didSet, as long as you use a fixed value
if you need to define your cornerRadius based on bounds, then do so in viewDidLayoutSubviews, or use NSLayoutConstraints (their value is fixed and known from Autolayout)
if you need to use cornerRadius in views (like UITableViewCell or UICollectionViewCell subclasses), then you can either do so in layoutSubviews (but then you need to give either a fixed value or a NSLayoutConstraint constant to cornerRadius), or in awakeFromNib(in that case, just add self.layoutIfNeeded before doing anything frame- or boounds-related, in order to force the cell to recalculate its subviews' frame).
I think problem in it:
CGRectGetHeight(self.button.frame) / 2;
When you set corner i think height button don't have value or value to larger border will don't show. You can try change it to
self.button.layer.cornerRadius = 15;
If work, I think you can check your logic and set it when height button get right value.
Try this and check:
#import <QuartzCore/QuartzCore.h>
self.button.layer.borderColor = [UIColor whiteColor].CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = 5; // Change this value on your requirement
self.button.clipsToBounds = YES;
To force view frame to be calculated, you can try with layoutIfNeeded.
For example for a label in a UITableViewCell :
override func awakeFromNib() {
super.awakeFromNib()
self.layoutIfNeeded()
self.qualityIndexLabel.makeRound()
}
use dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.button.layer.borderColor = borderColor.CGColor;
self.button.layer.borderWidth = 2;
self.button.layer.cornerRadius = CGRectGetHeight(self.button.frame) / 2; });
the RoundedRect is deprecated use UIButtonTypeSystem instead.
see https://developer.apple.com/reference/uikit/uibutton?language=objc for more information.

How to show buffered data on UISlider using MpMoviePlayerController in iOS?

I am using MPMoviePlayerController to play audio and I want to show the buffered data on slider like this ...
I want to show the buffer data like red section in slider. I have tried to google it. But I didn't get any solution for it.
and How to make slider customize?
Thanks in advance...
Yes We can Show stream data using MPMoviePlayerController by its playableDuration. I am explaining all these steps involved me to make this custom_slider for my customize player...
(You Can direct read step 4 if you only interested in programming part)
These are the steps:
Step 1: (First Design part) i done it using standard Controls...
In Interface Builder place your UISlider immediately on top of your UIProgressView and make them the same size.
On a UISlider the background horizontal line is called the track, the trick is to make it invisible. We do this with a transparent PNG and the UISlider methods setMinimumTrackImage:forState: and setMaximumTrackImage:forState:.
In the viewDidLoad method of your view controller add:
[ProgressSlider setMinimumTrackImage:minImage forState:UIControlStateNormal];
[ProgressSlider setMaximumTrackImage:transparentImage forState:UIControlStateNormal];
[progressBar setTrackImage:maxImage];
[progressBar setProgressImage:streamImage];
where ProgressSlider refers to your UISlider and progressBar to your UIProgressView.
and you can make transparent image programmatically like this.
UIGraphicsBeginImageContextWithOptions((CGSize){512,5}, NO, 0.0f);
UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
you can change the size of it according to your progress view track image height width... I use {512,5} you can use {1,1} for default slider and progress view.
Reference taken form this answer https://stackoverflow.com/a/4570100/3933302
Step 2:
Now I tried to set the track and progress image of UIProgressView. But it was not showing the track and progress image. then i found this solution...to use this library available in github. https://gist.github.com/JohnEstropia/9482567
Now I changed occurrences of UIProgressView to JEProgressView, including those in NIBs and storyboards.
Basically, you'd need to force assigning the images directly to the UIProgressView's children UIImageViews.
The subclass is needed to override layoutSubviews, where you adjust the heights of the imageViews according to the image sizes.
Reference taken from this Answer https://stackoverflow.com/a/22322367/3933302
Step 3:
But now the question is from which will you make the image for slider and progressView. This is explained in this tutorial and You can download the psd also.
http://www.raywenderlich.com/32167/photoshop-tutorial-for-developers-creating-a-custom-uislider
Step 4:
Now come to programming part..
by using the playable duration it is possible to show stream data..(which was my biggest problem)
Using MPMovieLoadStatePlayable we can get when The buffer has enough data that playback can begin, but it may run out of data before playback finishes.
https://developer.apple.com/library/ios/documentation/MediaPlayer/Reference/MPMoviePlayerController_Class/index.html#//apple_ref/c/tdef/MPMovieLoadState
Now in your PlayAudio method...place this code..
-(void) playAudio:(NSURL *) url {
.............
streamTimer= [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(loadStateChange) userInfo:nil repeats:YES];
..........
}
and here is the definition of loadStateChange
-(void)loadStateChange
{
if(self.moviePlayer.loadState == MPMovieLoadStatePlayable){
[self.moviePlayer play];
slideTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(updateProgressUI)
userInfo:nil
repeats:YES];
[streamTimer invalidate];
}
else if(self.downloadList)
//if you are playing local file then it will show track with full red color
progressBar.progress= appDel.moviePlayerController.moviePlayer.duration;
}
and here is the definition of updateProgressUI
- (void)updateProgressUI{
if(self.moviePlayer.duration == self.moviePlayer.playableDuration){
// all done
[slideTimer invalidate];
}
progressBar.progress = self.moviePlayer.playableDuration/self.moviePlayer.duration ;
}
I hope this fully customize slider will help you lot in making custom player...I explained all my work in steps.....Thanks ....
You cannot do this with MPMoviePlayerController.
However if you switch to AVPlayer then you can use AVPlayerItem.loadedTimeRanges. It contains all information you need for visualization in your custom control.
There are number of questions that have been asked on that topic, for example:
AVPlayer streaming progress
According the documentation of MPMoviePlayerController (available here) you can use the playableDuration property to retrieve the duration that has been loaded by the player.
You would then have to subclass UISlider to draw the red part of your control in the drawRect: method.
As for AVPlayer you would call loadedTimeRanges (documentation here) on the AVPlayerItem representing your content. That would give you an array of (as of iOS 8) a single CMTimeRange representing the part of your media that has been buffered. I would advise using [NSArray firstObject] when retrieving the time range to protect your code against a possibly empty array.

Adding another picker to UISlider

I am trying to create a UISlider that has two pickers.I already have a UISlider which is working and functioning correctly.
Is there a way where I can add a picker to the UISlider that I already have or do I need to scrap everything that I have and programatically code it so that it has two pickers?
I would like the slider to have a minimum picker and a maximum picker. Im not sure if it is possible to add another picker to the slider i already have.
Here is the code i have for my current uislider.
- (IBAction)slider:(id)sender {
UISlider *slide = (UISlider *)sender;
CGFloat value = slide.value;
NSUInteger index = value * (priceDelegate.values.count - 1);
NSString *priceString = priceDelegate.values[index];
[self.tf_price setText:priceString];
_appDelegate.int_minPriceV = index;
}
If some one could help me I would be really grateful, thank you.
If it's a range slider you want then you're out of luck with the standard UISlider as it does not provide this kind of functionality.
You can subclass UISlider and do your own thing but we can all agree that that's somewhat a tedious job.
You can try these instead:
link1: https://github.com/muZZkat/NMRangeSlider
link2A: https://github.com/buildmobile/iosrangeslider
OR...
link2B: https://www.cocoacontrols.com/controls/rangeslider
If you're feeling a bit adventurous then follow this tutorial:
http://www.sitepoint.com/wicked-ios-range-slider-part-one/

Continuously Update Label Based on UISlider Value

I currently have a series of 5 UISliders that continuously update their respective labels to display what value the user is selecting in an hh:mm:ss format. I have the properties of each slider set to continuous and have their targets set to when the slider is changed (This example would be for just the first slider).
sliderOne.continuous=YES;
[sliderOne addTarget:self action:#selector(sliderOneChanged:) forControlEvents:UIControlEventTouchUpInside];
Each slider's individual label updates the time selected perfectly. Now however, I need to update another label underneath all of these sliders that continuously sums up the value of the sliders.
At the same time, I am also doing some conversions with the value of the slider using two segmented controllers -- a miles/kilometers segmented controller and various distances in another segmented controller. Each conversion results in a time in seconds that is then converted back into the hh:mm:ss format and displayed in the last label when the user selects which combo from the segment controller they want. I have all the math worked out for this, and the label will update correctly when changing segments, but not continuously.
How could I update a label to continuously show the sum of every UISlider as the user changes them?
For a continuous updating, use the UIControlEventValueChanged event along with the continuous property
sliderOne.continuous=YES;
[sliderOne addTarget:self action:#selector(sliderOneChanged:) forControlEvents:UIControlEventValueChanged];
Use KVO to get notified of changes in UISliders and update the UI accordingly. You want to wrap UI updates with dispatch_async to avoid locking the interface.
Using KVO-Notification-Manager it can be something like this (in viewDidLoad or similar):
id token1 = [slider1 addKVOBlockForKeyPath:#"value" options:NSKeyValueObservingOptionNew handler:^(NSString *keyPath, id object, NSDictionary *change) {
dispatch_async(dispatch_get_main_queue(), ^{
whateverSliderNeedsUpdate.value = /* your calculation result */;
});
}];
id token2 = [slider2 /* repeat for as many sliders as you want */];
...
It's important to remove the observers at some point.
- (void)dealloc {
[slider1 removeKVOBlockForToken:token1];
[slider2 ...];
}
If you feel adventurous you can try with ReactiveCocoa.
You could create a method that does all of your math and updates your UILabel with the result. For example:
- (void)updateSumLabel {
// this is obviously very simple
float num1 = [_sliderOne value];
float num2 = [_sliderTwo value];
float sum = num1 + num2;
[_sumLabel setText:[NSString stringWithFormat:#"#f",sum]];
}
The you can call updateSumLabel from any of your existing methods like sliderOneChanged. This is probably the most simple way todo this.

How to replace UISlider with UIProgressView playing MPMoviePlayerController?

I am having a hard time trying to replace UISlider on my app playing a invisible MPMoviePlayerController with UIProgressView.
UISlider is just create, very intuitive to change, Pretty much on the Update selector from MPMoviePlayerController I update its current status:
and previously I defined the min and max from the content of the MPMoviePlayerController:
-(void)UpdateTime:(NSTimer*)Timer
{
[self.sldProgress1 setValue:[[NSNumber numberWithDouble:playerSong.currentPlaybackTime] floatValue]];
}
UIProgressView doesn't provide similar approach, and I didn't find on the web a sample that matches what I am trying to do:
sldProgress2.maximumValue = [playerSong playableDuration];
sldProgress1.value = 0.0;
any suggestions?
UIProgressView doesn't have the concept of a user-settable max value - it's just 100.0. To make it work as you want, you'll have to do some math. Luckily, it's easy math:
CGFloat percentComplete = [playerSong.currentPlaybackTime floatValue] / [playerSong.playableDuration floatValue];
That will give you the percentage of the song that's complete, and you just update your UIProgressView to that number.
progressView.progress = percentComplete;
More or less - this code was mostly pseudo based on your question, but that's the idea.
You can keep using the UISlider and hide the thumbImage using this line:
[mySlider setThumbImage:[[UIImage alloc] init] forState:UIControlStateNormal];
This worked for me.

Resources