Transparent webview: underlying layer sometimes not visible - objective-c

In my phonegap-based iPhone web-app I implemented a plugin that uses AVCaptureVideoPreviewLayer to take a photo. To do so, when the plugins' startCamera method is called, I set the background of the webview to be transparent and insert the video capture layer below the layer of the webview. This works as expected (most of the time).
But for some strange reason, when I execute startCamera for the first time (after a fresh app start), the video layer isn't visible. Instead, the webview displays a white background, although the background color is set to clearColor. For all subsequent executions, the video layer is visible.
This is what I'm doing to show the camera:
AVCaptureSession * session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetHigh;
AVCaptureVideoPreviewLayer * videoLayer =
[[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
videoLayer.frame = self.webView.bounds;
CALayer *webViewLayer = self.webView.layer;
[webViewLayer.superlayer insertSublayer:videoLayer below:webViewLayer];
// ... session setup excluded
[session startRunning];
[self.webView setBackgroundColor:[UIColor clearColor]];
[self.webView setOpaque:NO];
In stopCamera() I do the following:
if (session) {
[session stopRunning];
}
[self.webView setBackgroundColor:[UIColor blackColor]];
[self.webView setOpaque:NO];
if (videoLayer != nil) {
[videoLayer removeFromSuperlayer];
}
Any ideas why the camera layer isn't visible for the first time?

Solved it: The problem was, that setting the opacity flag of the webview to NO didn't have any effect when it was done in startCamera(). To fix it, I set the opacity of the webview earlier - just when it was created. A webview with no opacity doesn't mean that it is transparent though - you also need to set the background color to [UIColor clearColor] (this is what is done in startCamera(); in stopCamera() the background color is set back to [UIColor blackColor]).

Related

How to disable Preview screen when using UIImagePickerController Camera

In iOS7 the build-in camera app doesn't go into the preview screen after taking a picture, is there any way that the UIImagePicker can behave like that.
UIImagePickerController * imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashModeOff;
I know another solution is to create a custom camera using the AVFoundation class, but that is beyond my knowledge at this point and I really like the looks of the default camera.
Update
So after some more research I found out I could create my own shutter button and set it as a camera overlay. Here is what I did
UIButton *shutter = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[shutter addTarget:self action:#selector(shootPicture) forControlEvents:UIControlEventTouchUpInside];
[shutter setTitle:#"S" forState:UIControlStateNormal];
shutter.frame = CGRectMake(50, 50, 60, 60);
UIView *layoutView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
layoutView.opaque = NO;
layoutView.backgroundColor = [UIColor clearColor];
[layoutView addSubview:shutter];
For the 'shootPicture' method
- (void) shootPicture
{
[picker takePicture];
[self imagePickerController:self.camCtl didFinishPickingMediaWithInfo:nil];
}
If I just have the picker call 'takePicture' I will still get the preview, so instead I forced the picker to call didFinishPickingMediaWithInfo right after taking picture. The result is I don't see the preview screen HOWEVER I don't see the picture either. I know I put 'nil' in didFinishPickingMediaWithInfo because I don't know what to put in at this point. I also know it took a picture is in cache somewhere but I really have no idea how to get it.
Any idea would be greatly appreciated =)
This solution works for me:
self.pickerController.allowsEditing = false

UIActivityViewController messes the background on orientation change

I am having a native app, in which I have to show Share feature with UIActivityViewController. My app needs to support both orientations. When the share pops up and I change the device orientation, then the orientation for popup changes but the background screen remains its orientation and when I cancel it out then the background screen looks messy.
Please let me know how to fix this as my app is in release phase and I am stuck with this issue.
NSString *textToShare = #"your text";
NSArray *itemsToShare = #[textToShare];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
activityVC.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll];
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed){
IsAppLoadedFirstTime=false;
[infoImageabc1 removeFromSuperview];
[InfoLabel1 removeFromSuperview];
[ InfoLabel2 removeFromSuperview];
[InfoShare removeFromSuperview];
[self loadView];
}];
[self presentViewController:activityVC animated:YES completion:nil];
I can change the orientation as soon as the activity popup closes, but before the (when the popup is opened), then the UI is not in proper orientation say if after opening the popup I changed the orientation to Portrait, then my UI remains in Landscape mode, but as it includes text also, so UI looks bad.

UIImage content disappearing (and reappearing) when using drawLayer:inContext

I'm using the delegate method drawLayer:inContext to change the background opacity for a small box as it moves around the screen. The layer had a UIImage set as the content when it was initialized.
Every time drawLayer:inContext is called the image will either disappear or reappear (toggling back and forth) making for a stutter-y looking movement on screen.
I have the image data as a local ivar in the delegate class so that it doesn't need to reload every time.
I'm not sure what's causing this. Any ideas? Here's the code I'm using:
- (id)init
{
self = [super init];
if(self) {
UIImage *layerImage = [UIImage imageNamed:#"Hypno.png"];
image = layerImage.CGImage;
}
return self;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
float alpha = layer.position.y / layer.superlayer.bounds.size.height;
UIColor *reddish = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:alpha];
CGColorRef cgReddish = reddish.CGColor;
layer.backgroundColor = cgReddish;
[layer setContents:(id)image];
}
Don't use -drawLayer:inContext:. That method is for drawing into a CG context which will then become the layer's contents, using Core Graphics or UIKit methods. You don't want to change the layer's contents at all -- you want to set it to be your image, once, and then never touch it again.
Your image is appearing and disappearing, because sometimes the layer displays the image, and other times the layer displays what you drew into the context in -drawLayer:inContext: -- namely, nothing.
(Also: in order for -drawLayer:inContext: to be called, you must be calling [layer setNeedsDisplay], or you have the layer's needsDisplayOnBoundsChange turned on, or something similar. Don't do any of that.)
Instead, try using the CALayer layout machinery. For instance, in your layer's delegate:
- (void)layoutSublayersOfLayer:(CALayer *)layer
{
float alpha = layer.position.y / layer.superlayer.bounds.size.height;
UIColor *reddish = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:alpha];
CGColorRef cgReddish = reddish.CGColor;
layer.backgroundColor = cgReddish;
}
This will get called as part of the display process, anytime the layer or any of its superlayers have had their -setNeedsLayout method called. Often this happens automatically, but depending on exactly what causes the layer to move, you may need to do it manually. Try it and see.
(Alternatively: Since you already have code that changes the layer's position, why not change the layer's background color at the same time?)

applicationMusicPlayer volume notification

I am using an applicationMusicPlayer and when i try to change the volume appear the visual notification, as shown in the picture.
Here the code I am using:
[MPMusicPlayerController applicationMusicPlayer] setVolume:newVolune];
Anyone knows how to hide this notification?
I don't know where the docs says so, but if you add a MPVolumeView view to your app the system volume overlay goes away. Even if it is not visible:
- (void) viewDidLoad
{
[super viewDidLoad];
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame: CGRectZero];
[self.view addSubview: volumeView];
[volumeView release];
...
}
You can use the hardware volume buttons, the setVolume method or directly interact with the control (if visible) that the overlay doesn't show up.
For iOS6 I had to set an image with alpha 0 and non-zero size to the MPVolumeView's image fields in order to get the default volume change notification to disappear.
// hide the hardware volume slider
UIImage *thumb = [[UIImage alloc] initWithCIImage:[UIImage imageNamed:#"volumeHider"].CIImage scale:0.0 orientation:UIImageOrientationUp];
MPVolumeView *hwVolume = [[MPVolumeView alloc] initWithFrame:self.frame];
[hwVolume setUserInteractionEnabled:NO];
hwVolume.showsRouteButton = NO;
[hwVolume setVolumeThumbImage:thumb forState:UIControlStateNormal];
[hwVolume setMinimumVolumeSliderImage:thumb forState:UIControlStateNormal];
[hwVolume setMaximumVolumeSliderImage:thumb forState:UIControlStateNormal];
[self addSubview:hwVolume];
This made the MPVolumeView be "visible" on the screen, but invisible to the user.
I encountered the same issue recently. Instead of adding the MPVolumeView to current view controller's view, I add it to the application's window once at the start of the app:
CGRect rect = CGRectMake(-500, -500, 0, 0);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:rect];
[self.window addSubview:volumeView];
This works in both iOS 7 and 8.
Swift 3
You can hide the System MPVolumeView using
override func viewDidLoad() {
super.viewDidLoad()
let volumeView = MPVolumeView(frame: CGRect.zero)
self.view.addSubview(volumeView)
}
I had success with this in iOS 6. Although it wouldn't perform well. It caused quite a bit of lag when sliding the thumbImage. I did have to take out the last 2 lines of code in order for this to work.
[volumeView release];
...
For me, on iOS 7, none of above solutions worked. Here is how I did it:
_volume = [[MPVolumeView alloc] initWithFrame: CGRectMake(-100,-100,16,16)];
_volume.showsRouteButton = NO;
_volume.userInteractionEnabled = NO;
[self.view addSubview:_volume];
[_volume release];
That is, simply set MPVolumeView's frame to an off-screen location such as (-100,-100).

Phonegap-ipad app -Adjust Launch image acc to Orientation

I am trying to explore ipad dev using phonegap. The problem that i have now is,
I have four different launch images for different orientations. When the app is launched, the correct launch image is being shown for a moment. After this,phonegap tries to load a imageview with default.png and displays it till webview is fully loaded. The problem lies here.. The imageview is autorotated based on the current orientation. So if the current orientation is LandscapeLeft, imageview tries to rotate default.png before displaying it Which is not i wanted and that is why i have different launch images.So in effect, you will have a landscapeleft.png and then the auto-rotated default.png before i get to see the webview.
So i tried changing the phonegapdelegate like this (in applicationDidFinishLaunching)
UIImage* image=nil;
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight ){
NSLog(#"In default5");
image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Default5" ofType:#"png"]];
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft ){
NSLog(#"In default6");
image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Default6" ofType:#"png"]];
}
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown ){
NSLog(#"In default7");
image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Default7" ofType:#"png"]];
}
imageView = [[UIImageView alloc] initWithImage:image];
[image release];
It didn't work and upon debugging i found that the statusbarorientation is always portrait. That may be because phonegap tries to set portrait as the statusbarorientation in the same applicationDidFinishLaunching method(before loading this image view).
Can someone tell me how to load the image view with correct image?
USE THESE NAMES:
Default-LandscapeLeft-ipad.Png
Default-LandscapeRight-ipad.Png
Default-Portrait-ipad.Png
Default-PortraitUpsideDown-ipad.Png
More: http://www.weston-fl.com/blog/?p=840
applicationDidFinishLaunching is too early for the app to receive orientation change notifications from the os. Hence you cannot determine the orientation here.
So the best possible solution is to do it in a lifecycle stage which is capable of determining the current orientaion.In my case, webViewDidStartLoading