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.
Related
I'm coding an app, and have several views that are reused (f. ex. containing a textfield, a label and a button)
Now i would like to just create it in a "globalviews.m" file once and add it as a subview to the mainview. (I really don't like the interface builder)
I could easily create a function that returns a UIView, with the components in them, but i would like to access the controls of course.
I was hoping something like (making "searchview" global in the viewcontroller in use)
// making searchview a global thingy
UIView *seachview ;
// rest of code here and then in viewdidload:
UIView *seachview = [[UIView alloc] init] ;
searchview = [[globaviews alloc] thesearchviews_name] ;
[self addsubview:searchview] ;
But how could I make controls inside easily accessible. Like:
NSString *something = searchview.textviewname.text ;
Or would this be a terrible idea to begin with?
Its just the way I would prefer to code...
You can create a custom class that is a subclass of UIView. You could then add properties for each control (the same way you would add NSString, NSNumber etc). Or you could create public methods to modify / get data.
e.g.
- (void)setTextFiledColour:(UIColor *)color;
- (NSString *)getTextFieldText;
My personal opinion (from a lot of experience) is to learn interface builder and deal with it. It is perfectly possible to do what you want and many people agree with you and choose to do it that way. Personally I've never seen it done "right". Meaning that its all done custom to create their own patterns and methodologies, avoiding years of experience and testing that has gone into the patterns provided by interface builder.
I find that storyboards in particular force a very specific pattern and style of coding. I think moving away form that is a huge mistake, as if used correctly it has great potential to abstract away UI / Code, prevents taking shortcuts that come back later on and most importantly when someone else needs to change it, there is no ambiguity, you can't make a mistake with class names or variable names etc.
I've used storyboards a lot and have yet to have an issue with them, on the flip side i've worked with developers who insist on doing it all by hand and have never had so many issues, and shocked at how long it takes to develop applications in this manner.
In the end its up to you.
Note
You mentioned wanting to create a view and reuse it. Its also possible to do this in a .xib file and reuse it that way. Losing some of the storyboard abilities but might give you a little of both worlds.
I'm fairly new to Cocoa programming, and have a question about control event handling.
I create an 'action' for a button, and get an updated AppDelegate.m to handle this eg.
- (IBAction)seedBtnPressed:(id)sender {
NSString* myString = #"Hi there";
[_updateLbl setStringValue:myString];
}
When running this, pressing the 'seed' button does what it should - the label updates.
My question is: why have I captured the 'button press event' by default, as I don't see any place where I've specified this. Alternately, how would I capture a mouse-over event with an action? I gather I'd create another action for the button, but am not sure how to specify this to handle 'mouse-over' events only? Sorry if I've used Windows terminology here, I understand Cocoa uses different names for things.
Thanks
Pete
You need to Subclass the NSButton class (or even better the NSButtonCell class).
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
They should get called when the mouse enter and exit the area. You may also need to re create the tracking area, look here:
- (void)updateTrackingAreas
For fade in and fade out effect I played with animator and alpha value for example:
[[self animator]setAlphaValue:0.5];
To get mouse-over events for an NSView you should use the NSTrackingArea class (assuming you're targeting a relatively modern version of OS X). Apple have good documentation on this available at http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html
For your other query about the seedBtnPressed: triggering although you don't specify it - have you set an action in Interface Builder for the button rather than programmatically?
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.
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 ...]
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.