I have managed to ensure that the iPhone doesn't auto-lock using:
[[ UIApplication sharedApplication ] setIdleTimerDisabled: YES ];
But how do I make the screen dim after a certain amount of time?
Thanks...
EDIT:
Think I've found a solution myself:
Use this method in your view controller to dim by adding a black view with 50% alpha. Make sure to set userInteractionEnabled = NO to pass events to underlying views.
- (IBAction)dim:(id)sender {
UIView *dimView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
dimView.backgroundColor = [UIColor blackColor];
dimView.alpha = 0.5f;
dimView.userInteractionEnabled = NO;
[self.view addSubview:dimView];
}
or, could risk it (but Apple may reject on submission):
[(id)[UIApplication sharedApplication] setBacklightLevel:1.0f];
That's a private API and shouldn't be used though...
As of iOS 5 there is a public API in the UIScreen class. It has a brightness property that can be set. For those instances where you may want to go dimmer than the actual backlight allows, there is a wantsSoftwareDimming property that will automatically place a translucent layer that will give the appearance of being more dim than can be done in hardware. This is very similar to the method you came up with with the translucent UIView. It should be noted that using your solution or the software dimming API should not be used with many animations since you will pay a performance penalty with all the alpha blending.
See UIScreen Class Reference
in iOS 7 and later:
yourViewController.view.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
Related
I've been searching all over the internet over the past couple of days to no avail. Unfortunately, the apple documentation about this specific issue is vague and no sample code is available (at least thats what I found out). What seems to be the issue you may ask...
I'm trying to set a uiview's layer as the contents of the material that is used to render an iPhone model's screen (Yep, trippy :P ). The iPhone's screen's UV mapping is set from 0 to 1 so that no issue persists in mapping the texture/layer onto the texels.
So, instead of getting this layer to appear rendered on the iPhone, same as left image, Instead, I get this rendered onto the iPhone like right image
Correct Render Incorrect Render
Also note, that when I set a breakpoint and debug the actual iPhone node and view it in Xcode, a completely different render is shown and the layer gets half-fixed when I continue execution:
Now then... HOW do I fix this issue??? I've tried playing with the diffuse's contents transform matrix but nothing gets fixed. I've also tried resizing the UIView to 256x256 (since the UV seems to be 256x256 as shown in blender - the 3d modelling package), but that doesn't fix anything.
Here is the code for the layer:
UIView *screen = [[UIView alloc] initWithFrame:self.view.bounds];
screen.backgroundColor = [UIColor redColor];
UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screen.bounds.size.width, 60)];
temp.backgroundColor = [UIColor colorWithRed:0 green:(112.f/255.f) blue:(235.f/255.f) alpha:1];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectInset(temp.bounds, 40, 0)];
label.frame = CGRectOffset(label.frame, 40, 0);
label.textColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
label.text = #"Select Track";
label.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:30];
label.minimumScaleFactor = 0.001;
label.adjustsFontSizeToFitWidth = YES;
label.lineBreakMode = NSLineBreakByClipping;
[temp addSubview:label];
UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, temp.bounds.size.height - 2, temp.bounds.size.width, 2)];
separator.backgroundColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
[temp addSubview:separator];
[screen addSubview:temp];
screen.layer.contentsGravity = kCAGravityCenter;
Edit
What's even weirder is that if I capture a UIImage of the view using:
- (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
and use that as the diffuse's content... everything works out perfectly fine?! It's really weird and frustrating since the image's size is exactly the same as the uiview's...
Edit 2
I ended up just using an image of the view as the texture, which makes things much more static than I needed. I won't set this as the answer because I'll still be waiting for a correct fix to this issue even if it in a long time. So, if you have an answer and this topic has been opened for a long time, please bump it if you can. The documentation on this section is just so poor.
New post on an old thread, but this day-in-age, it's possible to set the UIView itself as SCNMaterialProperty (diffuse) contents. Intention to support this feature is communicated directly from SceneKit engineering at Apple, though the documentation has not yet been updated to reflect it.
To tied back to the original post, do not set a UIView.layer as material property contents; instead set contents to the UIView itself.
[Update: according to Lance's comment below, support for views may be getting worse rather than getting better.]
The SceneKit docs pretty strongly suggest that, while there are cases where you can use animated CALayers as material content, that doesn't include UIView layers:
SceneKit cannot use a layer that is already being displayed elsewhere (for example, the backing layer of a UIView object).
That suggests that if you want to make animated content for your material, you're better off with either Core Animation used entirely on its own or SpriteKit.
I have a custom tab bar that was optimized for the iphone 5.
UINavigationBar *myBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[self.view addSubview:myBar];
When it on the iphone 6, part of it is cut off of course because it only goes to 320 pixels.
How do i fix this? Is there a way to check which iphone its being ran on, and then run the pixel specified code? I plan on putting a background image on this navbar later so it must be centered.
In general it is a bad idea to hard code dimensions like this. This will break if you rotate, or if viewed on a screen with a different size than the original iPhone screen.
Many of these controls have a default size that you can use to your advantage. Instead of handing it a frame, consider just modifying the frame it gives you:
UINavigationBar *myBar = [[UINavigationBar alloc] init];
CGRect navBarFrame = myBar.frame;
navBarFrame.size.height // returns the right size for the current OS
navBarFrame.size.width = self.view.frame.size.width;
myBar.frame = navBarFrame;
This type of defensive coding is helpful in keeping your app laid out properly under many conditions, including when you embed this control into a parent view controller, or viewed on tomorrows larger-screened iOS devices.
All this said, are you sure you don't want a UIToolbar? Typically you don't ever create your own UINavigationBar, as that class is just used in UINavigationController for you.
UINavigationBar *myBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 50)];
[self.view addSubview:myBar];
may be this help you.
Compare the two screenshots:
Done on iOS 7.0 simulator
And the one done on iOS 7.0.3 iPhone 4S:
Same code here and there and same stuff! Any idea why the translucency is gone on the real device?
I have this code to simulate it (I know it's probably awkward and not right but that's how it is):
topMenuView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.origin.x, 0, self.view.frame.size.width, TOP_BAR_ORIG_HEIGHT)];
topMenuView.clipsToBounds = YES;
UIToolbar *topMenuViewBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, -4, self.view.frame.size.width, TOP_BAR_ORIG_HEIGHT + 4)];
topMenuViewBar.barStyle = UIBarStyleDefault;
topMenuViewBar.barTintColor = [BSFunctions getColorFromHex:#"1ea6ff"];
const CGFloat statusBarHeight = 20;
UIView *underlayView = [[UIView alloc] initWithFrame:CGRectMake(0, -statusBarHeight, topMenuViewBar.frame.size.width, topMenuViewBar.frame.size.height + statusBarHeight)];
[underlayView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
[underlayView setBackgroundColor:[BSFunctions getColorFromHex:#"1ea6ff"]];
[underlayView setAlpha:0.36f];
[topMenuViewBar insertSubview:underlayView atIndex:1];
UIView *underlayView2 = [[UIView alloc] initWithFrame:CGRectMake(0, -statusBarHeight, topMenuViewBar.frame.size.width, topMenuViewBar.frame.size.height + statusBarHeight)];
[underlayView2 setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
[underlayView2 setBackgroundColor:[BSFunctions getColorFromHex:#"0291ff"]];
[underlayView2 setAlpha:0.36f];
[topMenuViewBar insertSubview:underlayView2 atIndex:2];
[topMenuView addSubview:topMenuViewBar];
[self.view addSubview:topMenuView];
The main point is it used to work before on the device! But after iOS 7.0.3 came out it changed. I'm noticing the same behavior in Facebook and Fitocracy iOS apps.
UPDATE
On Xcode 5.0.1 with iOS 7.0.3 simulator we have this (which is different from the first image on iOS 7.0 simulator as you can see):
OK, so after having played around with the colours a bit more, I managed to get a similar sort of appearance with the blur!
Previously, I was setting a barTintColor on the navigation bar appearance which had the following values:
R:17
G:63
B:95
A:1
This was fine in iOS < 7.0.3, and the output color in the nav bar (with the blur effect) was actually:
R:62
G:89
B:109
Since iOS 7.0.3, the barTintColor seems to take into account the alpha value of the color we set. This meant that the nav bar was actually outputting a solid color 17,63,95, and there was no blur effect.
The key to getting the blur effect back is setting an alpha < 1 in the barTintColor.
After lots of guess work and trying different RGB values, I managed to get the exact same RGB output from the nav (and tab) bar, using the following RGBA:
R:4.5
G:61.6
B:98
A:0.65
It does not look like there's a magic ratio to apply to the previous color to obtain the new one.
Anyway I've actually rejected the binary that got approved this afternoon, and have re-submitted with these new values so that user's don't get an ugly app :)
Hope this helps.
I'm writing a UI for iPad and part of that UI needs progress bars for certain parts. However, I'm finding that configuring the UIProgressView is proving difficult. One of the requirements is that the endpoints of the progress view be square, however, I am unable to configure this via the layer's corner radius property:
fProgressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
fProgressView.layer.borderColor = [UIColor whiteColor].CGColor;
fProgressView.progress = 0.5f;
fProgressView.progressImage = nil;
fProgressView.trackImage = nil;
fProgressView.trackTintColor = self.fPatientListPanelColor;
fProgressView.progressTintColor = [UIColor whiteColor];
[fProgressView.layer setCornerRadius:1.0f];
[self.view addSubView:fProgressView]
I find I am also unable to control the height of it. Any thoughts on how to overcome these issues?
There is apparently no way to do this, so I ended up rolling my own version.
I have implemented a custom split view controller which — in principle — works quite well.
There is, however one aspect that does not work was expected and that is the resize-animation of the toolbar on iOS prior to version 5.1 — if present:
After subclassing UIToolbar to override its layoutSubviews method, animating changes to the width of my main-content area causes the toolbar-items to move as expected. The background of the toolbar — however — does not animate as expected.
Instead, its width changes to the new value immediately, causing the background to be shown while increasing the width.
Here are what I deem the relevant parts of the code I use — all pretty standard stuff, as little magic/hackery as possible:
// From the implementation of my Split Layout View Class:
- (void)setAuxiliaryViewHidden:(BOOL)hide animated:(BOOL)animated completion:(void (^)(BOOL isFinished))completion
{
auxiliaryViewHidden_ = hide;
if (!animated)
{
[self layoutSubviews];
if (completion)
completion(YES);
return;
}
// I've tried it with and without UIViewAnimationOptionsLayoutSubviews -- didn't change anything...
UIViewAnimationOptions easedRelayoutStartingFromCurrentState = UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:M_1_PI delay:0.0 options:easedRelayoutStartingFromCurrentState animations:^{
[self layoutSubviews];
} completion:completion];
}
- (void)layoutSubviews
{
[super layoutSubviews];
// tedious layout work to calculate the frames for the main- and auxiliary-content views
self.mainContentView.frame = mainContentFrame; // <= This currently has the toolbar, but...
self.auxiliaryContentView.frame = auxiliaryContentFrame; // ...this one could contain one, as well.
}
// The complete implementation of my UIToolbar class:
#implementation AnimatableToolbar
static CGFloat sThresholdSelectorMargin = 30.;
- (void)layoutSubviews
{
[super layoutSubviews];
// walk the subviews looking for the views that represent toolbar items
for (UIView *subview in self.subviews)
{
NSString *className = NSStringFromClass([subview class]);
if (![className hasPrefix:#"UIToolbar"]) // not a toolbar item view
continue;
if (![subview isKindOfClass:[UIControl class]]) // some other private class we don't want to f**k around with…
continue;
CGRect frame = [subview frame];
BOOL isLeftmostItem = frame.origin.x <= sThresholdSelectorMargin;
if (isLeftmostItem)
{
subview.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
continue;
}
BOOL isRightmostItem = (CGRectGetMaxX(self.bounds) - CGRectGetMaxX(frame)) <= sThresholdSelectorMargin;
if (!isRightmostItem)
{
subview.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
continue;
}
subview.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
}
}
#end
I’ve set the class of the toolbar in InterfaceBuilder and I know for a fact, that this code gets called and, like I said, on iOS 5.1 everything works just fine.
I have to support iOS starting version 4.2, though…
Any help/hints as to what I’m missing are greatly appreciated.
As far as I can see, your approach can only work on iOS SDK > 5. Indeed, iOS SDK 5 introduced the possibility of manipulating the UIToolbar background in an explicit way (see setBackgroundImage:forToolbarPosition:barMetrics and relative getter method).
In iOS SDK 4, an UIToolbar object has no _UIToolbarBackground subview, so you cannot move it around in your layoutSubviews implementation. To verify this, add a trace like this:
for (UIView *subview in self.subviews)
{
NSLog(#"FOUND SUBVIEW: %#", [subview description]);
run the code on both iOS 4 and 5 and you will see what I mean.
All in all, the solution to your problem lays in handling the background in two different ways under iOS 4 and iOS 5. Specifically, on iOS 4 you might give the following approach a try:
add a subview to your custom UIToolbar that acts as a background view:
[toolbar insertSubview:backgroundView atIndex:0];
set:
toolbar.backgroundColor = [UIColor clearColor];
so that the UIToolbar background color does not interfere;
in your layoutSubviews method animate around this background subview together with the others, like you are doing;
Of course, nothing prevents you from using this same background subview also for iOS 5, only thing you should beware is that at step 1, the subview should be inserted at index 1 (i.e, on top of the existing background).
Hope that this helps.
Since I think this is going to be useful for someone else, I’ll just drop my solution here for reference:
Per sergio’s suggestion, I inserted an additional UIImageView into the view hierarchy. But since I wanted this to work with the default toolbar styling, I needed to jump trough a few hoops:
The image needed to be dynamically generated whenever the tintColor changed.
On iOS 5.0.x the toolbar background is an additional view.
To resolve this I ended up…
Implementing +load to set a static BOOL on whether I need to do anything. (Parses -[UIDevice systemVersion] for version prior to 5.1).
Adding a (lazily loaded) property for the image view stretchableBackground. The view will be nilif my static flag is NO. Otherwise the view will be created having twice the width of [UIScreen mainScreen], offset to the left by half that width and resizable in height and right margin and inserted into the toolbar at index 0.
Overriding setTintColor:. Whenever this happens, I call through to super and __updateBackground.
Implemented a method __updateBackground that:
When the toolbar responds to backgroundImageForToolbarPosition:barMetrics: get the first subview that is not our stretchableBackground. Use the contents property of that view’s layer to populate the stretchableBackground’s image property and return.
If the toolbar doesn’t respond to that selector,
use CGBitmapContextCreate() to obtain a 32bit RGBA CGContextRef that is one pixel wide and as high as the toolbar multiplied by the screen’s scale. (Use kCGImageAlphaPremultipliedLast to work with the device RGB color space…)
Translate the CTM by that height and scale it by scale/-scale to transition from UIKit to CG-Coordinates and draw the view’s layer into that context. (If you fail to do this, your image will always be transparent blank…)
Create a UIImage from that context and set it as the stretchableBackground’s image.
Notice that this fix for iOS 5.0.x will not work as expected when using different background images for portrait and landscape or images that do not scale — although that can be tweaked by configuring the image view differently…