Flip UIAlertView - cocoa-touch

I have not found a way to do this without using private APIs, which is quite a shame, as it is something my app and many others could benefit from. I have an UIAlertView with a Details... button on it, which I want to sort of 'flip' to the other side and show a different UIAlertView, much like UITwoSidedAlertViewController, but not using any private APIs.
First of all, is this even possible? I looked over the UIAlertView header, but I couldn't see anything relating to this. UIAlertView does inherit from UIView, so I suppose that simple view animation might just be the key, but as I said, I've never done anything like view animation flips.

Why not just use one of the several UIAlertView replacements that have been created and then add the flip functionality yourself?
You can find a UIAlertView replacement here: https://github.com/TomSwift/TSAlertView
The flip can be created using a standard flip animation block via [UIView transitionWithView ...]

Related

Using `valueForKey` to access view in UIBarButtonItem, private API violation?

Since UIBarButtonItem doesn't subclass UIView, it's impossible to get at the normal characteristics like its frame.
One way to do this is [barButtonItem valueForKey:#"view"]
This works perfectly, and allows you to add a GestureRecognizer (for instance) to the underlying UIView.
However, is this a private UIKit API violation?
This is not private in terms of immediate rejection upon validation, but it's private enough to be considered fragile (that is, new iOS version can break your existing app in the app store that's using the code).
I can say, that a similar code (fetching backgroundView ivar of UIToolbar via KVC) has passed app store validation and is being used in production.
In case of possible bad things, you must wrap the method in #try { ... } #catch, so that you intercept KVC possibly failing in newer iOS release.
Five Pieces of Evidence for "It's Not Private"
It's a property that you can get to in other ways. Try this and one of those views is, in fact, the _view ivar of the UIBarButtonItem in question. This indicates that access to this UIView is not prohibited itself, though the KVO way in might be questionable (but I doubt it).
NSArray *array = self.toolBar.subviews;
for (UIView *view in array) {
view.backgroundColor = UIColor.greenColor;
}
They actually trigger the KVO for this property. ivars do not have to trigger the KVO API, right?
#Farcaller mentions a similar case which is for sale in the App Store. Since he/she answered within the first 20 minutes of the question being up there, it's reasonable (but not safe!) to assume that there might be thousands of apps in the App Store that do this.
This UIView gets subbed out each time the button is pressed, so you cannot just, for example, set a gesture recognizer on it and be done. You can, however, keep setting the same gesture recognizer every time the view gets replaced. To me, this is actually more evidence that it's not a private API thing, but rather you have to be very careful when using it (and use KVO to make sure you have the latest one).
My app is for sale in the App Store and does this.

Cocoa Message with no action required

I'm trying to figure out a way to give a user feedback when they have saved settings. similar to Microsoft's "File Saved" dialog Is there a class for this type of dialog? I do not want to require any action by the user. Just "Your setting have been saved" then disappears after a short delay. Maybe a better way to describe would be like a jQuery message box with a fade in fade out type thing
Is there a class for this type of dialog?
That isn't a "dialog", because you're not accepting input from the user. At best, it's an alert, and you could therefore use NSAlert (see also "Dialogs and Special Panels") however, what you are contemplating is contrary to the recommendations given in the HIG for "Alerts":
Avoid using an alert merely to give users information. Although it’s important to tell users about serious problems, such as the potential for data loss, users don’t appreciate being interrupted by alerts that are informative but not actionable. Instead of displaying an alert that merely informs, give users the information in another way, such as in an altered status indicator.
In other words, this probably wouldn't be considered a good user experience by the OS X-using population.
You can still do this, if you absolutely must, by creating a sheet or alert window and setting a timer to dismiss it.
A much better plan would be to have a label somewhere in your interface whose text could display this information, again using a timer to clear the notice after an appropriate duration.
Yet another option (possibly the best) would be to put this notice somewhere that the user only sees it upon request. The HIG mentions Mail.app's information area at the bottom of its sidebar, for example.
It is simple to fade a window in and out using the NSViewAnimation see also NSAnimation Class
An example I use something like this.
- (void)fadeWindowIn{
//--make sure the window starts from 0 alpha. Or you may get it jumping in view then try and fade in.
[theWindow setAlphaValue:0.0];
//-- set up the dictionary for the animation options
NSDictionary *dictIn = [NSDictionary dictionaryWithObjectsAndKeys:
theWindow,NSViewAnimationTargetKey,
NSViewAnimationFadeInEffect,NSViewAnimationEffectKey,nil];
NSViewAnimation * fadeWindowIntAnim = [[[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dictIn]] autorelease];
[fadeWindowIntAnim setAnimationCurve:NSAnimationLinear];
[fadeWindowIntAnim setDuration:2];
[fadeWindowIntAnim setFrameRate:20.0];
//--start the animation
[fadeWindowIntAnim startAnimation];
//--set the timer for the fade out animation
[NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(fadeWindowOut) userInfo:nil repeats:NO];
}
-(void)fadeWindowOut{
//-- fade the window.
NSDictionary *dictOut = [NSDictionary dictionaryWithObjectsAndKeys:
theWindow,NSViewAnimationTargetKey,
NSViewAnimationFadeOutEffect,NSViewAnimationEffectKey,nil];
NSViewAnimation * fadeOutAnim = [[[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dictOut]] autorelease];
[fadeOutAnim setAnimationCurve:NSAnimationLinear];
[fadeOutAnim setDuration:1.2];
[fadeOutAnim setFrameRate:20.0];
[fadeOutAnim startAnimation];
}
theWindow is the NSWindow or NSView you want to fade in and out. Read the references to understand the options.
You can create your own such popup (using NSTimer to dismiss as needed), but perhaps an easier way would be to use the existing third-party library at http://code.google.com/p/toast-notifications-ios/. This library emulates Android's "toast" functionality.
Note that this library is for iOS development (not OSX), but wasn't sure which platform you were planning to target. Regardless, it should be adaptable with a little work.
The other answers about timers and such cover that aspect of it pretty well. I just wanted to jump in and suggest you take a look at the Growl framework. This seems to be the preferred way to do this sort of passive notification until Apple builds it into the OS.
Among other things, it gives the user a lot of control over how the notifications look, where they live on the screen, how long they stay up, and which apps are even allowed to display them. And they do this without you having to write any code. The downside is that it's another thing for your users to have to install, which could be a deal breaker for your app.
They also recently moved into the App Store and started charging a nominal fee ($2 or $3, I think) which could be seen as a downside but I think of it as a more positive thing: users will have a much easier time installing it now.
Some apps that make use of Growl notifications include BBEdit, Transmission, Scrivener, Twitteriffic, etc. Which is to say that it's not a fly-by-night thing.
As a user, I hate it when apps try to roll their own notifications since I lose all of the control that I get with Growl.
Just a thought, anyway.

UIImage for UIActionSheet button?

I know that UIActionSheets don't offer that much customization but what I am asking, is that instead of the grayish/white buttons, can I use a green button (my own UIImage)? I can supply my own image with the text already on there that I want; so using a normal UIActionSheet, can I supply my own image on one of the buttons? If so, how should I go upon doing that?
Thanks,
O.Z
#huesforalice is right - the cleanest way would be to create your own replacement of UIActionSheet. Basically you have 3 options:
A real replacement: You create a UIActionSheet-subclass to be protocol-compatible to ´UIActionSheetDelegate´. This would allow you to use it exactly as a UIActionSheet — but it might be a costly process to figure out when and why a UIActionSheet will call the delegates method implementation.
Even go a bit further and also extend the protocol. This will give you more possibilities, how to use it (i.e. allow picker to be used via new protocol methods), but will be even harder.
The most easiest way will be to create a very own implementation, that doesn't rely on UIActionSheet nor it's protocol — but it won't replace real UIActionSheet, in the meaning that you cannot drop it into your project and expect it to work. But you will have the highest degree on freedom.
I would recommend 3. I found a project, that is working like that. But be warned: It shows you how to do it in general, but has some poor underlying design-decisions:
It uses a method
- (void) addButtonWithTitle: (NSString*) buttonTitle buttonId: (NSInteger) buttonId textColor: (UIColor*) textColor textShadowColor: (UIColor*) textShadowColor backgroundColor: (UIColor*) buttonBackgroundColor increasedSpacing: (BOOL) spacing
Instead — IMHO — it should be
- (void) addButton: (UIButton*) button;
So you can add buttons with different designs more flexible, and don't depend for a section id, what is totally unnecessary, as the object has its own identity as an object already.
The method [actionSheet showWithAnimation:YES]; should be called
showor showAnimated: as …withAnimation: usually takes a block to perform a custom animation.
This ist not possible using UIActionSheet and the documented methods. You could write your own actionsheet, which you then probably would add to the main window and animate to slide up. Possibly there is a way to do what you want by analyzing the actionsheets private view hierarchy and adding custom buttons, but you have to keep in mind, that private view hierarchies may change from one iOS Version to another, so your app might break or might even get rejected from apple.

Can anyone help out an Objective C novice?

I feel i am totally out of my depth here, im very new to objective c but have been asked to design an iphone app as part of my uni course. I designed a sinple quiz before, but I was hoping to design a more advanced quiz game with 3 levels (each level will have a different quiz).
I dont know how to use the UIViews and I have tried a tutorial online to help me code a navigation controller. It allows gives me 3 options to go into subview 1, 2 or 3. All the subviews have the same screen though, with one label and a button.
I have 3 classes so far, RootViewController, BasicNavigationAppDelegate and SubViewOneController.
I really dont understand the code at all, im familiar with Java but this objective c is nothing like it. Could someone maybe take a minute to help out a person in distress and explain if i am doing this right by using the navigation controller to display my levels? When i check the xib interface files i dont see the button or label, or dont know where to add the quiz interface objects!! I really am confused by all this. Could anyone help?
You should search google for sample source code, and see how some of the views can be handled. There are many ways you can handle a view, whether its by a UINavigationController, UITabBarController, etc. If you are new to Objective-C, then your not really going to get an answer to this question that will instruct you on what exactly to do.
Interface Builder + View Controllers
Here's a good one for you: View Controllers Programming Guide
(Apple's) View Controller Reference Guide
Some Code Samples
Getting Started Sample Code
I recommend Head First iPhone Development: A Learner's Guide to Creating Objective-C Applications for the iPhone. Within a few chapters you'll know everything you need to build this app and you'll actually understand what you're doing.
(I don't know the authors or the publisher, I just think it's a great book for quickly getting up to speed.)
for a 3 level quiz, UINavigationController is definitely an option.
if you need to find out how to use a class, in xcode, type its name, then press -alt- and double click the class name, this will bring up a short description, with two icons, one will take you to the header file, and the other to the documentation.
to add elements to the nib/xib files, you will need to open the library window, where you will find labels, buttons etc. to use a button, you will need to define an action in your header file, and hook it up in IB, to be able to interact with UIElements in your code, you want to set up outlets in the header file, and hook them up in IB.
something you need to decide on, is how you are going to present the questions, and will also depend if the answer will be true/false, multiple choice, or text entry.
if you arent familiar with obj-c and xcode, it is probably worth picking up an ebook from someone like http://www.pragprog.com. they have an iPhone one up there by Bill Dudney which is quite good(i believe he now works for apple.)
for the standard slide out transition you could use this.
//you would probably want to call this something like level1NavBarItemWasPushed: instead
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//push the view controller onto the navigationController's view stack
[self.navigationController pushViewController:level1AnswersVC animated:TRUE];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}
for the page flip transition you could use this.
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//set the current viewController as the delegate, so that it can call back to us when its done
level1AnswersVC.delegate = self;
//set the modal transition style
level1AnswersVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//show answers as modal view, which has been setup to use the page flip transition.
[self presentModalViewController:level1AnswersVC animated:YES];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}

Best way to capture key events in NSTextView?

I'm slowly learning Objective-C and Cocoa, and the only way I see so far to capture key events in Text Views is to use delegation, but I'm having trouble finding useful documentation and examples on how to implement such a solution. Can anyone point me in the right direction or supply some first-hand help?
Generally, the way you implement it is simply to add the required function to your view's controller, and set its delegate. For example, if you want code to run when the view loads, you just delegate your view to the controller, and implement the awakeFromNib function.
So, to detect a key press in a text view, make sure your controller is the text view's delegate, and then implement this:
- (void)keyUp:(NSEvent *)theEvent
Note that this is an inherited NSResponder method, not a NSTextView method.
Just a tip for syntax highlighting:
Don't highlight the whole text view at once - it's very slow. Also don't highlight the last edited text using -editedRange - it's very slow too if the user pastes a large body of text into the text view.
Instead you need to highlight the visible text which is done like this:
NSRect visibleRect = [[[textView enclosingScrollView] contentView] documentVisibleRect];
NSRange visibleRange = [[textView layoutManager] glyphRangeForBoundingRect:visibleRect inTextContainer:[textView textContainer]];
Then you feed visibleRange to your highlighting code.
It's important to tell us what you're really trying to accomplish — the higher-level goal that you think capturing key events in an NSTextView will address.
For example, when someone asks me how to capture key events in an NSTextField what they really want to know is how to validate input in the field. That's done by setting the field's formatter to an instance of NSFormatter (whether one of the formatters included in Cocoa or a custom one), not by processing keystrokes directly.
So given that example, what are you really trying to accomplish?
I've done some hard digging, and I did find an answer to my own question. I'll get at it below, but thanks to the two fellas who replied. I think that Stack Overflow is a fantastic site already--I hope more Mac developers find their way in once the beta is over--this could be a great resource for other developers looking to transition to the platform.
So, I did, as suggested by Danny, find my answer in delegation. What I didn't understand from Danny's post was that there are a set of delegate-enabled methods in the delegating object, and that the delegate must implement said events. And so for a TextView, I was able to find the method textDidChange, which accomplished what I wanted in an even better way than simply capturing key presses would have done. So if I implement this in my controller:
- (void)textDidChange:(NSNotification *)aNotification;
I can respond to the text being edited. There are, of course, other methods available, and I'm excited to play with them, because I know I'll learn a whole lot as I do. Thanks again, guys.