Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
I just read the iOS Human Interface Guidelines. In the chapter about Alerts, Action Sheets, and Modal Views (see here), I found this line :
The background appearance of an alert
is system-defined and cannot be
changed.
In my app I created my own UICustomAlert, inheriting from the UIAlertView class, whith following methods :
- (id)initWithImage:(UIImage *)image andButton:(UIButton *)button
{
if (self == [super init])
{
self.backgroundImage = image;
self.bigButton = button;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGSize imageSize = self.backgroundImage.size;
[self.backgroundImage drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
[self addSubview:bigButton];
}
- (void) show
{
[super show];
CGSize imageSize = self.backgroundImage.size;
self.bounds = CGRectMake(0, 0, imageSize.width, imageSize.height);
}
- (void)didAddSubview:(UIView *)subview
{
if ([subview isMemberOfClass:[UIImageView class]])
[subview removeFromSuperview];
}
I create my UICustomAlert this way :
UIAlertView *alert = [[UICustomAlert alloc] initWithImage:backgroundImage andButton:bigButton];
[alert show];
It permits me to show a UIAlert with a transparent background, and only one image (the backgroundImage).
But knowing what is written in iOS HIG, do you think Apple will reject the app ?
Thanks.
My gut feeling is that you're probably safe. There's nothing stopping you from implementing something like that from scratch. However I have had an app rejected for not following the HIG (they didn't like the way I worded an error message), so they are more than just "guidelines".
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm experimenting with different ways of displaying a UIView on the screen... I currently have this code, and think it should work to add a green UIView to the app's window, however, it doesn't:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"init");
self.backgroundColor = [UIColor greenColor];
self.alpha = 1;
}
return self;
}
+ (SMLoginView *)sharedView{
static dispatch_once_t onceToken;
static SMLoginView *sharedView;
dispatch_once(&onceToken, ^{
sharedView = [[self alloc]initWithFrame:[UIScreen mainScreen].bounds];
});
return sharedView;
}
+ (void)showLoginView{
[[self sharedView]show];
}
- (void)show{
NSLog(#"Show");
[[[[UIApplication sharedApplication] delegate] window] addSubview:self];
}
Insted, u can add it in the called method, because u are adding it in the shared class itself, thats wy it did't appeared.
try this
suppose u are calling this shared method in this "ViewController.m" class
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SMLoginView *sharedView = [SMLoginView sharedView]; //you always get a shared view handle that view in this class
[self.view addSubview:sharedView]; //add the shared view hear not in the shared class.
}
hope u got this :)
I use a UIImagePickerController (photoPicker) to take pictures with the camera, and edit those picture (allowEditing = YES). The user can switch between Camera and Library with a button in photoPicker.view, but I want to remove this button when photoPicker is in editing mode.
In photoLibrarySourceType the picker uses a push to show editing mode, so it works with this method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (navigationController == photoPicker) {
NSLog(#"navigation ");
if ([navigationController.viewControllers indexOfObject:viewController] == 1)
{
// If second UIViewController, set your overlay.
NSLog(#"editing");
}
}
}
But in cameraSourceType, there is no navigation between camera and editing mode.
I came up with a little hack and it works for me. Am still a little new so please optimize at will as i couldn't find another way to do it.
The basic idea is to create an invisible button over the default camera button that performs a method that calls [uiimagepickercontroller takePicture]
here is my sample code
#implementation myViewController
{
UIImagePickerController *myImagePickerController;
UIButton * fakeCameraButton;
}
- (IBAction)showImagePicker:(id)sender{
// accessible camera validations implied
myImagePickerController = [[UIImagePickerController alloc]init];
myImagePickerController.sourceType=UIImagePickerControllerSourceTypeCamera;
myImagePickerController.showsCameraControls = YES;
myImagePickerController.delegate=self;
myImagePickerController.allowsEditing=YES;
CGFloat myViewHeight = 100; // you play around with the positions to get your desired frame size. This worked for me
UIView * myView = [[UIView alloc] initWithFrame:CGRectMake(0, myImagePickerController.view.frame.size.height - myViewheight, picker.view.frame.size.width, myViewheight)];
fakeCameraButton = [[UIButton alloc] initWithFrame:CGRectMake(myView.frame.size.width / 2 - 30, myView.frame.size.height/2-15, 60, 60)];// position it over the default camera button
[fakeCameraButton addTarget:self action:#selector(cameraButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[fakeCameraButton setTitle:#"" forState:UIControlStateNormal];
[myView addSubview:fakeCameraButton];
myImagePickerController.cameraOverlayView = myView;
[self presentViewController:myImagePickerController animated:YES completion:nil];
}
-(void)cameraButtonPressed{
// Make sure you check if camera is ready before this method.
[myImagePickerController takePicture];
// you are in editing/preview mode here if allowsEditing = YES
// you can remove all your custom overlay views by
myImagePickerController.cameraOverlay = nil
}
Like i said before just make sure you check if camera is ready. You can find answers here on stackoverflow on how to do it.
This code may suck so editing or alternative solutions are welcomed.
I need dev buddy to help me learn more about ios dev and ask questions. anyone interested?
I've implemented the camera inside of my app with the default showsCameraControls = YES, and the issue I am having is when the user confirms that the image is a keeper, it dismisses the camera with [self.delegate didFinishWithCamera]. I would like to remain in the Camera view until the user is done taking photos. Without [self.delegate didFinishWithCamera], the app hangs after the user confirms they want to keep the photo and never returns back to the live camera feed. How do I remain in the camera view? Your help is appreciated!
#implementation PHFPhotoOverlayVC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.imagePickerController = [[UIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
}
return self;
}
- (void)setupImagePicker:(UIImagePickerControllerSourceType)sourceType
{
self.imagePickerController.sourceType = sourceType;
if (sourceType == UIImagePickerControllerSourceTypeCamera)
{
self.imagePickerController.mediaTypes =
[NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
self.imagePickerController.showsCameraControls = YES;
#if false
if ([[self.imagePickerController.cameraOverlayView subviews] count] == 0)
{
CGRect overlayViewFrame = self.imagePickerController.cameraOverlayView.frame;
CGRect newFrame = CGRectMake(0.0,
CGRectGetHeight(overlayViewFrame) -
self.view.frame.size.height - 10.0,
CGRectGetWidth(overlayViewFrame),
self.view.frame.size.height + 10.0);
self.view.frame = newFrame;
[self.imagePickerController.cameraOverlayView addSubview:self.view];
}
#endif
}
}
#pragma mark -
#pragma mark UIImagePickerControllerDelegate
- (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.imagePickerController.mediaTypes =
[NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
self.imagePickerController.showsCameraControls = YES;
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
if (self.delegate)
[self.delegate didTakePicture:image];
[self.delegate didFinishWithCamera];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self.delegate didFinishWithCamera];
}
#end
In order to achieve this, you will have to implement your own method for taking a picture, since this default button causes the view to dismiss itself.
Obviously, you can do this by setting showsCameraControls=NO, but then you'd have to recreate all the other functionality that you still want.
I've never done this, but it should be possible to leave showsCameraControls=YES and use the cameraOverlayView to simply layer an identical "Take Picture" button over the existing one. If you do that, you just need to have that button call the method -takePicture from the instance of your UIImagePickerViewController.
Hopefully that's enough, feel free to comment and ask for any clarification.
You're going to need to implement a custom camera - check out Apple's SquareCam example
You'll be using AVFoundation and will be able to implement any kind of custom behavior when a photo is taken (including just staying on that camera page) - you'll even have to save it to the Photo Library yourself (the SquareCam example shows you how to do this). This also means that if you need the crop/resize controls, you'll have to create them yourself, as well as a picker view (grid gallery view) if you want the user to be able to review their photos after taking them.
It's probably around intermediate level stuff - took me a few days to implement, but if your app is in any way focused on photos, this is definitely the way to go. Gives you complete control of the camera UI and behavior.
Oh, and yeah you'll have to implement the flash button, shutter button, shutter effect, tap to focus, and anything else yourself too. AVFoundation basically gives you a straight pipe to the camera lens (figuratively).
This question already has answers here:
When to use -retainCount?
(11 answers)
Closed 9 years ago.
Here is my code.
- (void)viewDidLoad{
[super viewDidLoad];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 240, 280)];
[view setTag:101];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 220, 260)];
[view setBackgroundColor:[UIColor redColor]];
[view addSubview:imgView];
[self.view addSubview:view];
[self getimageFromView:view];
[view release];
[imgView release];
[self getimageFromView];
}
-(void)getimageFromView:(UIView *)view{
for (UIView *view123 in [view subviews]) {
if ([view123 isKindOfClass:[UIImageView class]]) {
UIImageView *imgView = (UIImageView *)view123;
imgView.image = [UIImage imageNamed:#"img.png"];
NSLog(#"retain cnt 1 = %d",[imgView retainCount]);
}
}
}
-(void)getimageFromView{
for (UIView *view in [self.view subviews]) {
if (view.tag == 101) {
for (UIView *view123 in [view subviews]) {
if ([view123 isKindOfClass:[UIImageView class]]) {
UIImageView *imgView = (UIImageView *)view123;
imgView.image = [UIImage imageNamed:#"img.png"];
NSLog(#"retain cnt 2 = %d",[imgView retainCount]);
}
}
}
}
}
nslog look like following
retain cnt 1 = 3
retain cnt 2 = 2
Now my questions
1) Why UIImageView's object retain count is displayed like this ?
2) Is that correct count ?
3) If yes how can i send the release message till it become 0 ?
4) Can I do like this ? Is this proper way ?
for(int i=0;i<[imgView retainCount];i++){
[imageView release];
}
I have number of views like this and have to do operation on UIImageView as displayed.
Also I am getting memory warning and my app getting crash.
1) It is displayed like that because that is the retain count.
2) Yes
3) Absolutely not
4) See the answer to 3
The documentation for retainCount starts with the statement "Do not use this method." While this is a tad harsh the warning is there because it is very hard to interpret its result.
Answers to your questions:
1) Because that was its value at the time. A value of 3 means that at the instant was returned three objects had expressed ownership interest in the object, and that ownership interest was still outstanding but those objects may have already indicated they wish to cancel that interest by issuing an autorelease - this is one of the reasons retainCount should not be used.
2) The count is always correct at the time it is given, but it can be very hard to interpret.
3) You never, ever attempt to reduce the count to zero, that is completely at odds with the retain/release model and will cause havoc, or worse. The rule is if you create it (using alloc, or methods with create or copy in the names) or retain it then you have an ownership interest and must either hand that ownership to someone else or release/autorelease the object to cancel the ownership interest.
4) See 3, you never get here.
You should read the documentation on the retain/release model and understand ownership. Even under ARC, where retain/release is handled automatically for you, you need to understand ownership.
HTH
I have been working on an app for a couple of months now, but have finally run into an issue that I can't solve myself, and can't find anything on the internet to help.
I am using several normal UIAlertViews, in my app. Some have 2 buttons, some have 3 buttons, and a couple have 2 buttons and a text field. However all have the same issue. When you call [someAlertView show]; the alert view appears as normal, but then suddenly its graphics context seems to get corrupted as you can see from the screenshot.
This happens on both iPhone and iPad simulators (both 5.0 and 5.1), and happens on an iPad and iPhone4S device as well.
The image showing through is whatever happens to be behind the alertView.
The Alert still works, I can click the buttons, type in the text field, then when it dismisses the delegate methods are called correctly and everything goes back to normal. When the alertView appears again, the same thing happens.
The view behind the alert is a custom UIScrollView subclass with a content size of approximately 4000 pixels by 1000 with a UIImage as the background. The png file is mostly transparent, so is only about 80kB in memory size, and the phone is having no issues rendering it - the scroll view is still fully responsive and not slow.
It also has a CADisplayLink timer attached to it as part of the subclass. I have tried disabling this just before the alertView is shown, but it makes no difference so I am doubtful that is the issue.
This app is a partial rewrite of one I made for a university project, and that one could display UIAlertViews over the top of a scrollView of the same size and subclass without issue. The difference between this app and that one is that in my old app, I had subclassed UIAlertView to add extra things such as a pickerView, however I decided that I didn't like the way it looked so moved everything out of the alert and am just sticking with a standard UIAlertView.
This is how the alertView in the screenshot is called:
- (IBAction)loadSimulation:(id)sender {
importAlert = [[UIAlertView alloc] initWithTitle:#"Load Simulation" message:#"Enter Filename:" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Load", nil];
[importAlert setAlertViewStyle:UIAlertViewStylePlainTextInput];
[importAlert showPausingSimulation:self.simulationView]; //Calling [importAlert show]; makes no difference.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
[self hideOrganiser]; //Not an issue as the problem occurs on iPad as well.
}
}
With this being the categorised AlertView to add the ability to stop the scrollViews CADisplay link.
#interface UIAlertView(pauseDisplayLink)
- (void)showPausingSimulation:(UILogicSimulatorView*)simulationView;
#end
#implementation UIAlertView(pauseDisplayLink)
- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView {
[simulationView stopRunning];
[simulationView removeDisplayLink]; //displayLink needs to be removed from the run loop, otherwise it will keep going in the background and get corrupted.
[self show];
}
I get no memory warnings when this happens, so I am doubtful it is due to lack of resources.
Has anyone come across an issue like this before? If you need further information I can try to provide it, but I am limited in what code I can post. Any help would be appreciated, I've been trying to solve this for two weeks and can't figure it out.
Edit:
It appears that it is not the AlertView at all (or rather it is not just the alertView), as the problem goes away when I remove the scroll view behind it, so there must be some issue between the two. This is the code for my UIScrollView subclass:
.h file:
#import
#import
#class ECSimulatorController;
#interface UILogicSimulatorView : UIScrollView {
CADisplayLink *displayLink;
NSInteger _updateRate;
ECSimulatorController* _hostName;
}
#property (nonatomic) NSInteger updateRate;
#property (nonatomic, strong) ECSimulatorController* hostName;
- (void) removeDisplayLink;
- (void) reAddDisplayLink;
- (void) displayUpdated:(CADisplayLink*)timer;
- (void) startRunning;
- (void) stopRunning;
- (void) refreshRate:(NSInteger)rate;
- (void) setHost:(id)host;
- (void)setMinimumNumberOfTouches:(NSInteger)touches;
- (void)setMaximumNumberOfTouches:(NSInteger)touches;
#end
.m file:
#import "UILogicSimulatorView.h"
#import "ECSimulatorController.h"
#import <QuartzCore/QuartzCore.h>
#implementation UILogicSimulatorView
#synthesize updateRate = _updateRate;
#synthesize hostName = _hostName;
- (void)reAddDisplayLink {
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be re-added to the run loop after having been removed.
}
- (void)removeDisplayLink {
[displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be removed from the Run loop without deleting it. Removing it is essential to prevent corruption between the games and the simulator as both use CADisplay link, and only one can be in the run loop at a given moment.
}
- (void)startRunning {
[self refreshRate:self.updateRate];
[displayLink setPaused:NO];
}
- (void)refreshRate:(NSInteger)rate {
if (rate > 59) {
rate = 59; //prevent the rate from being set too an undefined value.
}
NSInteger frameInterval = 60 - rate; //rate is the number of frames to skip. There are 60FPS, so this converts to frame interval.
[displayLink setFrameInterval:frameInterval];
}
- (void)stopRunning {
[displayLink setPaused:YES];
}
- (void)displayUpdated:(CADisplayLink*)timer {
//call the function that the snakeController host needs to update
[self.hostName updateStates];
}
- (void)setHost:(ECSimulatorController*)host;
{
self.hostName = host; //Host allows the CADisplay link to call a selector in the object which created this one.
}
- (id)initWithFrame:(CGRect)frame
{
//Locates the UIScrollView's gesture recogniser
if(self = [super initWithFrame:frame])
{
[self setMinimumNumberOfTouches:2];
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(displayUpdated:)]; //CADisplayLink will update the logic gate states.
self.updateRate = 1;
[displayLink setPaused:YES];
}
return self;
}
- (void)setMinimumNumberOfTouches:(NSInteger)touches{
for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers])
{
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
//Changes the minimum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger.
[(UIPanGestureRecognizer*)gestureRecognizer setMinimumNumberOfTouches:touches];
}
}
}
- (void)setMaximumNumberOfTouches:(NSInteger)touches{
for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers])
{
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
//Changes the maximum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger.
[(UIPanGestureRecognizer*)gestureRecognizer setMaximumNumberOfTouches:touches];
}
}
}
#end
Well, I have managed to come up a solution to this. Really it is probably just masking the issue rather than finding the route cause, but at this point I will take it.
First some code:
#interface UIView (ViewCapture)
- (UIImage*)captureView;
- (UIImage*)captureViewInRect:(CGRect)rect;
#end
#implementation UIView (ViewCapture)
- (UIImage*)captureView {
return [self captureViewInRect:self.frame];
}
- (UIImage*)captureViewInRect:(CGRect)rect
{
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenShot;
}
#end
- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView {
[simulationView stopRunning];
UIView* superView = simulationView.superview;
CGPoint oldOffset = simulationView.contentOffset;
for (UIView* subview in simulationView.subviews) {
//offset subviews so they appear when content offset is (0,0)
CGRect frame = subview.frame;
frame.origin.x -= oldOffset.x;
frame.origin.y -= oldOffset.y;
subview.frame = frame;
}
simulationView.contentOffset = CGPointZero; //set the offset to (0,0)
UIImage* image = [simulationView captureView]; //Capture the frame of the scrollview
simulationView.contentOffset = oldOffset; //restore the old offset
for (UIView* subview in simulationView.subviews) {
//Restore the original positions of the subviews
CGRect frame = subview.frame;
frame.origin.x += oldOffset.x;
frame.origin.y += oldOffset.y;
subview.frame = frame;
}
[simulationView setHidden:YES];
UIImageView* imageView = [[UIImageView alloc] initWithFrame:simulationView.frame];
[imageView setImage:image];
[imageView setTag:999];
[superView addSubview:imageView];
[imageView setHidden:NO];
superView = nil;
imageView = nil;
image = nil;
[self show];
}
- (void)dismissUnpausingSimulation:(UILogicSimulatorView *)simulationView {
UIView* superView = simulationView.superview;
UIImageView* imageView = (UIImageView*)[superView viewWithTag:999];
[imageView removeFromSuperview];
imageView = nil;
superView = nil;
[simulationView setHidden:NO];
[simulationView startRunning];
}
Then modifying the dismiss delegate method in my class to have this line:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[alertView dismissUnpausingSimulation:self.simulationView];
...
When the alert view is called, but before it is shown, I need to hide the simulator to prevent it corrupting the alert. However just hiding it is ugly as then all is visible behind is a empty view.
To fix this, I first make a UIImage from the simulator views graphics context. I then create a UIImageView with the same frame as the simulator and set the UIImage as its image.
I then hide the simulator view (curing the alert issue), and add my new UIImageView to the simulators superview. I also set the tag of the image view so I can find it later.
When the alert dismisses, the image view is then recovered based on its tag, and removed from its superview. The simulator is then unhidden.
The result is that the rendering issue is gone.
I know its too late for an answer to this question. Lately I had experianced this very same issue.
My Case:
Added couple of custom UIViews with background images and some controlls to the scroll view with shadow effect. I had also set the shadowOffset.
The Solution:
After some step by step analysis, I found out that setting the setShadowOpacity caused The rendering problem for me. When i commented that line of code, it cured the UIAlertView back to normal appearance.
More:
To make sure, I created a new project mimicing the original ui with shadowOpacity. But it didnt caused the rendering problem as i expected. So I am not sure about the root cause. For me it was setShadowOpacity.