Custom UIProgressView in iOS7 not possible? - objective-c

I know this was already asked about a hundred times here, but I couldn´t find a suitable answer in the other questions.
My problem is the height of my UIProgressView. While everything worked as expected in iOS6, now in iOS7 nothing goes right.
I tried the following:
1.Setting the custom layout in the drawRect-Method:
Works like a charm in iOS6, but in iOS7 the progress is set to 100% from the beginning or the bar is very thin.
2.Setting the layout with the progressImage and trackImage property of the UIProgressView appearance
Also not working under iOS7. Here the bar progress is set to 100% from the beginning, too. Some people write that it should be possible this way, but I can not confirm that for iOS7.
3.Using initWithProgressStyle for initialization and then setting the frame of the progress view
Not working for me under iOS6 and iOS7. In iOS7 the bars are just very slim.
For me right now it is pretty frustrating because the bars are either at 100% or they are mega-slim. Can anyone give me a suggestion to reach the old layout of my progress views. I think it has to be possible because if I look at my Spotify app on the iPhone (iOS7 installed), the progress view looks like before.
Thank you very much!

Well, the problem is seams that iOS6 UIProgressView and iOS7 UIProgressView have different internal subviews structure. iOS6 progress view is a single view without child view (or some minor view), iOS7 progress view have few additional subview for drawing progress bar and background.
If you remove all subview of UIProgressView on iOS7 than you drawRect: method will work the same as before on iOS6, but you will be totally responsible about drawing your progress view content including progress bar and background.
- (id) initWithCoder: (NSCoder*)aDecoder
{
if(self=[super initWithCoder: aDecoder])
{
// Also you can setup height of your progress here
// self.frame = CGRectMake(0,0,100,yourHeight);
NSArray *subViews = self.subviews;
for(UIView *view in subViews)
{
[view removeFromSuperview];
}
}
return self;
}

I made kind of a workaround for this problem. I hope somebody can give a nice answer for a normal UIProgressView though.
I wrote a UIView subclass with round corners and a view inside of it which changes its size depending on the given progress. I only use colors for the background, but images would be possible too. Here´s the code:
#import "CustomProgressView.h"
#import <QuartzCore/QuartzCore.h>
#interface CustomProgressView ()
#property (nonatomic, retain) UIView *progressView;
#end
#implementation CustomProgressView
#synthesize progressColor,trackColor,progressView,progress;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.layer.cornerRadius = 5;
// clipsToBounds is important to stop the progressView from covering the original view and its round corners
self.clipsToBounds = YES;
self.progressView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, frame.size.height)];
[self addSubview:self.progressView];
}
return self;
}
-(void)setProgressColor:(UIColor *)theProgressColor {
self.progressView.backgroundColor = theProgressColor;
progressColor = theProgressColor;
}
-(void)setTrackColor:(UIColor *)theTrackColor {
self.backgroundColor = theTrackColor;
trackColor = theTrackColor;
}
-(void)setProgress:(float)theProgress {
progress = theProgress;
CGRect theFrame = self.progressView.frame;
theFrame.size.width = self.frame.size.width * theProgress;
self.progressView.frame = theFrame;
}
#end

I had a custom UIProgressView with it's own drawRect being updated from a background process.
In iOS6 all was working while in iOS7 the progressbar just did not update.
I have added layoutSublayersOfLayer right after the setProgress like this
[self.loadingProgress setProgress:pv.floatValue];
[self.loadingProgress layoutSublayersOfLayer:self.loadingProgress.layer];
and it worked like a charm.
I hope this helps someone.

Avoid a headache and use this excellent library:
YLProgressBar
Copy YLProgressBar.h and YLProgressBar.m from the YLProgressBar folder.
#import "YLProgressBar.h" in the file(s) you want to use the progress bar
Add your progress bar either by code or by xib
progressBar.type = YLProgressBarTypeRounded;
progressBar.progressTintColor = [UIColor greenColor];
progressBar.stripesOrientation = YLProgressBarStripesOrientationVertical;
progressBar.stripesDirection = YLProgressBarStripesDirectionLeft;
You have a nice, fully functional progress bar that supports width, height, modifications.

Related

Added whitespace in UIWebview - removing UIWebView whitespace in iOS7 & iOS8

Im loading local html files, since iOS7 there is added white space on top in the UIWebView.(I cant post an image as i do not have enough points.)
image can be seen here- snap shot from iPhone simulator, uiwebview surrounded by black frame, the html content is grey, but there is white added above it
I have tried to adjust the zoom using
[webView stringByEvaluatingJavaScriptFromString:#"document. body.style.zoom = 5.0;"];
webView.scalesPageToFit = NO;
credit to: Srikar Appal
I also set tried to remove white spacing:
NSString *padding = #"document.body.style.margin='0';document.body.style.padding = '0'";
[webView stringByEvaluatingJavaScriptFromString:padding];
credit to: thenextmillionaire
still no luck. In the desktop chrome browser there is no whitespace. The html files are Google Swiffy files - containing html and JSON.
edit: updated Image
Try self.automaticallyAdjustsScrollViewInsets = NO; in ViewDidLoad.
ios 7 add 64px automatically for scroll view. (status bar and nav bar)
This problem only affects the UIWebView if it is the first subview of the parent view. One alternative way to work around this problem is to add another non-visible empty view to the parent view as the first view. In Interface Builder add a zero size subview and use the Editor->Arrange->Send to Back menu command.
If you're not using Interface Builder, but instead are subclassing the UIWebView, then it can be done by creating a UIView instance variable called scrollFixView and overriding the following methods:
- (void)didMoveToSuperview
{
[super didMoveToSuperview];
if ([self superview].subviews.firstObject == self) {
_scrollFixView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
_scrollFixView.hidden = YES;
[[self superview] insertSubview:_scrollFixView belowSubview:self];
}
}
- (void)removeFromSuperview
{
if (_scrollFixView) {
[_scrollFixView removeFromSuperview];
_scrollFixView = nil;
}
[super removeFromSuperview];
}
I had the same problem so I tried a few things:-)
This worked for me, but correct me please if there is a better way.
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
if(self.navigationController.navigationBar.translucent == YES)
{
_webView.scrollView.contentOffset = CGPointMake(_webView.frame.origin.x, _webView.frame.origin.y - 54);
}
}
So basically you need to :
1) Add the UIWebView delegate method - webViewDidFinishLoad:
2) Then I setup an if statement to check if the translucent option is active.
The last one you only need to do of course if you give the user the option within your app.
The number after the _webView.frame.origin.y is just for my app. It may differ for you.
I solved this problem by simply setting a constraint on the WebView, setting the top space between it and the View top to 0, causing the NavBar to overlap the whitespace.
One alternative to Jeff Kranenburg's method is to subclass and override the UIWebView subclasses' UIScrollViewDelegate method scrollViewDidScroll:. This is only appropriate if scrolling is turned off for your subclass.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ([[self superclass] instancesRespondToSelector:_cmd]) {
[super scrollViewDidScroll:scrollView];
}
[self fixUpScrollViewContentOffset];
}
- (void)fixUpScrollViewContentOffset
{
if (!CGPointEqualToPoint(self.scrollView.contentOffset, CGPointZero)) {
self.scrollView.contentOffset = CGPointZero;
}
}
I already got it .
here my logic code, When the application open the website you must get the size of your webview then set it on height
here my code
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) webpage.getLayoutParams();
p.height = webpage.getHeight();
// check if how long you need to set your height for webpage then set it :)
Log.e(" webpage.getHeight()", String.valueOf(webpage.getHeight()));
webpage.setLayoutParams(p);
Hope you will take my code and my answer to :) works on any devices even tabs too :)

How can I set Background image on MyScene in ios7

When I am setting a background image on a SKScene. I have written the code below:
#import "JTEDMyScene.h"
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#interface MyScene()
#property BOOL isContentCreated;
#end
#implementation MyScene
-(void) didMoveToView:(SKView *)view
{
if(!self.isContentCreated)
{
self.isContentCreated = YES;
[self createSceneContent];
}
}
-(void)createSceneContent
{
[self addChild:[self createBackground]];
}
-(SKSpriteNode *)createBackground
{
SKSpriteNode *backgroundSprite;
SKTexture *textureImage;
if (IS_IPAD) {
textureImage = [SKTexture textureWithImageNamed:#"home_ipad1.jpg"];
backgroundSprite = [SKSpriteNode spriteNodeWithTexture:textureImage];
}
backgroundSprite.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
return backgroundSprite;
}
Device orientation modes are only Landscape left and landscape right. My image size is width = 1024 and height= 768 and 264 dpi. But the image is not showing fully a portion of image is showing.
Maq has the right idea. I think what he's saying is, the problem lies in your view controller .m file, instead of in your Scene. Instead of creating your SKView and SKScene and presenting the SKScene from within the viewDidLoad method of your VC, put that code in the viewWillLayoutSubviews method instead. Something along the lines of this:
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
SKScene * scene = [YourScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
Apparently, viewWillLayoutSubviews gets called later than viewDidLoad. When viewDidLoad is called, the view hasn't even been added to the view hierarchy yet.
Ray Wenderlich's Sprite Kit Tutorial for Beginners quotes this answer from SO as to why this happens.
Try to present and create MyScene in viewWillLayoutSubviews - if you haven't done it already.
It may work if you just rename viewDidLoad to viewWillLayoutSubviews and rename the super call too.
I started a blank project and copy-pasted your code into it and it works fine. I know you said you set your device orientation, but did you do that in your project settings? That's the only problem I can think of. Select your project, general tab, and under Deployment Info, there's a "Devices" drop-down box. Select iPad and make sure "Landscape Left" and "Landscape Right" are the only two checked. My guess is that the project thinks it's supposed to be starting in portrait mode, so it's stretching your 768-tall image vertically to 1024 at start; then when your app determines that it's in landscape orientation, it just rotates that stretched image accordingly, which would result in the image being cut off.
yes, to control and resize background image (in my case) correspond to device orientation, you have to use -(void)viewWillLayoutSubviews
but don't forget, it will start from first scene by default, so you need to use some "sceneNumber" selector in this function to point to actual scene

Prevent shutter animation from appearing full screen when using cameraOverlayView [duplicate]

I have a transparent view with a rectangle drawn onto it using CoreGraphics.
When the camera launches the custom overlay view is above the shutter animation.
What you see is the standard camera shutter with the custom rectangle above it.
How do I get it to go in the right place, underneath the shutter animation? I've looked at other sample code but it's for OS 3.1 and doesn't seem to do anything differently.
Here's my code:
-(IBAction)cameraButton{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerCameraDeviceRear]){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
//Add the OverlayView with the custom Rectangle
CGRect overlayFrame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
OverlayView *overlayView = [[OverlayView alloc]initWithFrame:overlayFrame];
picker.cameraOverlayView = overlayView;
[overlayView release];
[self presentModalViewController:picker animated:YES];
[picker release];
}
}
On the iPad this problem doesn't exist, and the overlay view is behind the shutter animation by default. But on the iPhone, the overlay appears at front.
I've found a solution that worked for me.
You have to set your overlay view as a subview in this method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (!viewController)
return;
UIView* controllerViewHolder = viewController.view;
UIView* controllerCameraView = [[controllerViewHolder subviews] objectAtIndex:0];
UIView* controllerPreview = [[controllerCameraView subviews] objectAtIndex:0];
[controllerCameraView insertSubview:self.overlayView aboveSubview:controllerPreview];
}
Hope it helps
Original source:
http://www.alexcurylo.com/blog/2009/06/18/uiimagepickercontroller-in-3-0/
You may not do anything else other than what you're already doing; if iOS decides to put your overlay view over the shutter, you'll just have to live with it (unless you want to risk getting rejected from the app store).
As an imperfect workaround, you could start your overlay with alpha=0 and then set alpha to 1 a second or two later. But there is no set time period that the shutter appears for before 'opening' (I think it depends on how long it takes to initialize the camera hardware), so sometimes your interface might not appear until late and sometimes might appear too early.
As of 4.3.3, the shutter animation is broken because elements are displayed on top, and then snap underneath when the animation starts. I've filed this as a Radar: http://openradar.appspot.com/radar?id=1204401
I answered a similar question here. What worked for me (in iOS 6) was setting the cameraOverlayView in navigationController:willShowViewController:animated.
- (void) navigationController:(UINavigationController*) navigationController willShowViewController:(UIViewController*) viewController animated:(BOOL) animated {
self.imagePickerController.cameraOverlayView = ...; // your camera overlay view
}

Camera Shutter shows up in front of custom UIView?

I have a custom UIView that I have created to display my custom buttons and toolBar. When I first called for it to show, the bar is on top of the Shutter (which is good). But after the camera is loaded, the shutter comes in front of it, then opens.
If you look at the native camera.app, it doesn't do this. The toolbar stays there the whole time. Here is my code:
// .h
UIImagePickerController *theCamera;
#property (nonatomic, retain) UIImagePickerController *theCamera;
// .m
theCamera = [[UIImagePickerController alloc] init];
theCamera.delegate = self;
theCamera.sourceType = UIImagePickerControllerSourceTypeCamera;
theCamera.showsCameraControls = NO;
theCamera.toolbar.alpha = 0;
theCamera.navigationBarHidden = YES;
theCamera.toolbarHidden = YES;
theCamera.wantsFullScreenLayout = YES;
theCamera.cameraViewTransform = CGAffineTransformMakeScale(1.25, 1.25);
UIImageView *tabBarBack = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tab_bar_back.png"]];
tabBarBack.frame = CGRectMake(0, 422, 320, 58);
[customView addSubview:tabBarBack];
theCamera.cameraOverlayView = customView;
[self presentModalViewController:theCamera animated:YES];
Obviously there are more buttons I add to the customView, but you get the concept.
Subscribe to:
AVCaptureSessionDidStartRunningNotification
This is when the iris open animation begins. If you add a cameraOverlayView during this time, it will be properly covered up by the iris. It is posted at the same time as that PL… private notification. This is a documented approach that does not risk app rejection.
AFAIK there is no direct way to do this. If you use cameraOverlay, you will get shutter for the complete screen.
How ever there are some alternate methods (playing around with the view hierarchy) that will help you in making your preview screen as parent view. I am not sure if this approach is correct as per app store guidelines.
have a look at Hide/Show iPhone Camera Iris/Shutter animation for better understanding on how to achieve this.
On iOS 6+, if you've added your controller as the delegate for the UIImagePickerController, this code should ensure that the shutter stays behind your cameraOverlayView:
- (void) navigationController:(UINavigationController*) navigationController willShowViewController:(UIViewController*) viewController animated:(BOOL) animated {
self.imagePickerController.cameraOverlayView = ...; // your camera overlay view
}
I haven't tested on versions of iOS prior to iOS 6 though.

UISplitViewController: remove divider line

When using UISplitViewController on the iPad there's a black vertical divider line between the root and detail view. Is there any way to remove this line?
Thanks
Excellent answer by #bteapot. I tested this and it works, even gets rid of the line between master/detail nav bars.
You can do this in storyboard by adding the "gutterWidth" key path and the value 0 to the USplitViewController runtime attributes.
Actuly I have some modification to answer of (Dylan)'s answer
in the appDelegate we need to add image in spliteview controller rather then window
self.splitViewController.view.opaque = NO;
imgView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"FullNavBar.png"]];
[imgView setFrame:CGRectMake(0, 0, 1024, 44)];
[[self.splitViewController view] insertSubview:imgView atIndex:0];
[[self.splitViewController view] setBackgroundColor:[UIColor clearColor]];
here self is object of AppDelegate.
now Apply the answer of this thread : iPhoneOS SDK - Remove Corner Rounding from views (iPad problem) answer by (abs)
edit in above post's answer is
-(void) fixRoundedSplitViewCorner {
[self explode:[[UIApplication sharedApplication] keyWindow] level:0];
}
-(void) explode:(id)aView level:(int)level
{
if ([aView isKindOfClass:[UIImageView class]]) {
UIImageView* roundedCornerImage = (UIImageView*)aView;
roundedCornerImage.hidden = YES;
}
if (level < 2) {
for (UIView *subview in [aView subviews]) {
[self explode:subview level:(level + 1)];
}
}
imgView.hidden = FALSE;
}
** make imgView.hidden to FALSE
declare imgView to the AppDelegate.h file**
and dont forget to call this
-(void)didRotateFromInterfaceOrientation:
UIInterfaceOrientation)fromInterfaceOrientation
{
[yourAppDelegate performSelector:#selector(fixRoundedSplitViewCorner)
withObject:NULL afterDelay:0];
}
chintan adatiya answer covers only the corners and the navigation bar, but I found an trick how to cover the line between the Master and the Detail view.
It is not nice but it works like a charm.
First create an image which is 1 px wide and 704 pixels high.
In the didFinishLaunchingWithOptions add the following code:
UIView *coverView = [[UIView alloc] initWithFrame:CGRectMake(320, 44, 1, 704)];
[coverView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"divider_cover.png"]]];
[splitViewController.view addSubview:coverView];
And done.
When you want a background image which is continues create 3 images:
Master: width: 320, height: 704
Detail: width: 703, height: 704
Divider:width: 1, height: 704
First post here, hi everyone.
I discovered how to do it accidentally... when I tried to find why I had LOST the divider line. Here's how to hide it, if you're still interested:
1) In your Detail (right-side) view, make sure you have a subview that spans the whole view.
2) Offset this subview view to (-1, 0).
3) Make sure that the Detail View has its "Clip Subviews" option unchecked.
Voilà, enjoy.
You can mostly get rid of it by setting another image behind it in the main window's views. This is from the app delegate didFinishLaunchingWithOptions
// Add the split view controller's view to the window and display.
splitViewController.view.opaque = NO;
splitViewController.view.backgroundColor = [UIColor clearColor];
[window addSubview:splitViewController.view];
[window insertSubview:bgImageView belowSubview:splitViewController.view];
[window makeKeyAndVisible];
But it still leaves two visual artifacts at the top and the bottom that appear to be custom drawn by the splitviewcontroller.
Interestingly, In the app that I'm working on I want a black background color for both views in the UISplitViewController. I'd like to change the color of the divider line to white (so that you can see it). Making both background colors black is one way to get rid of (make invisible) the dividing line but that's probably not a solution for most people.
Tested on iOS10 (probably will work on iOS9 too).
splitviewController.view.backgroundColor = UIColor.white
it removes divider. Apparently divider is just a gap between master and detail container.
I looked around for a while, and came to the conclusion that theres no way to do this, other than to create your own custom split view.
Try the MGSplitViewController by Matt Gammell
http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad
I may be late here, but I DO have a solution that works. It even works for the iOS 8+ splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; and seamlessly slides in and out when you press the Full Screen toggle button.
Here is the trick :
first Subclass UISplitViewController.m
In the header add the follwing :
#property (strong, nonatomic) UIView *fakeNavBarBGView;
In the viewDidLoad method add the following code :
CGFloat fakeNavBarWidth = 321; // It is important to have it span the width of the master view + 1 because it will not move when the split view slides it's subviews (master and detail)
CGFloat navbarHeight = self.navigationController.navigationBar.frame.size.height + 20;
self.fakeNavBarBGView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, fakeNavBarWidth, navbarHeight)];
self.fakeNavBarBGView.backgroundColor = [UIColor redColor];
// Add Fake navbar to back of view
[self.view insertSubview:self.fakeNavBarBGView atIndex:0];
// SplitView Controller
UISplitViewController *splitViewController = self;
DetailViewController *detailVC = [navigationController.viewControllers lastObject];
detailVC.fakeNavBarSubView = self.fakeNavBarBGView;
detailVC.SVView = self.view;
In the DetailViewController.h add the following :
#property (strong, nonatomic) UIView *SVView;
#property (strong, nonatomic) UIView *fakeNavBarSubView;
Now here is the final trick : in the DetailViewController.m, add the following in the viewDidLoad method (called every time you click the Master table) :
[self.SVView sendSubviewToBack:self.fakeNavBarSubView];
[self.SVView bringSubviewToFront:self.view];
Run it and watch the magic ;-)
Private API (can cause App Store rejection):
[splitViewController setValue:#0.0 forKey:#"gutterWidth"];
I did this accidentally by setting the backgroundColor property of the first viewController's view - possibly to clearColor, I don't remember now.
UIManager.put("SplitPaneDivider.draggingColor", new Color(255, 255, 255, 0));