iPhone UIActionSheet with multiple red, destructive buttons [duplicate] - iphone

Is there any way to have more than 1 red "destructive button" in an iPhone app's UIActionSheet?
I need to have different clear options, in the same action sheet, one where it deletes everything and one where it deletes less, so both need to be red.

I just created a simple customizable replacement for UIActionSheet for iPhone to use in a similar case. It does not use the standard appearance, but this can be changed. Probably it is of any use to you.
https://github.com/4marcus/WMActionSheet

The poster of this question seemed to manage what you want...if i understand you correctly.
Is using subviews in Alert undocumented
EDIT:
I swear I searched for UIActionSheet the first time. Really.
http://www.nearinfinity.com/blogs/andrew_homeyer/display_a_custom_uiview_like_a.html

There's no supported way of doing this on the standard UIActionSheet. You could build your own "action sheet" replacement using gradient buttons like the ones here:
http://iphonedevelopment.blogspot.com/2010/05/gradient-buttons-yet-again.html
I would expect someone to have created a more customizable lookalike action sheet replacement, but I don't know of one off the top of my head.

I tried this before I saw griotspeak updated answer:
SEL getTitle = NSSelectorFromString(#"title");
SEL getBackground = NSSelectorFromString(#"background");
SEL setBackground = NSSelectorFromString(#"setBackgroundImage:");
SEL setTitleColor = NSSelectorFromString(#"setTitleColor:");
UIImage *redImage;
UIColor *titleColor;
UIColor *shadowColor;
for (NSObject *object in [action subviews]) {
if ([[NSString stringWithFormat:#"%#", [object class]] isEqualToString:#"UIThreePartButton"]) {
if ([[object performSelector:getTitle] isEqualToString:#"Clear all"]) {
redImage = [object performSelector:getBackground];
titleColor = [object performSelector:#selector(titleColor)];
shadowColor = [object performSelector:#selector(shadowColorForState:) withObject:0];
shadowOffset = [object performSelector:#selector(shadowOffset)];
}
if ([[object performSelector:getTitle] isEqualToString:#"Clear all except this month"]) {
[object performSelector:setBackground withObject:redImage];
[object performSelector:setTitleColor withObject:titleColor];
[object performSelector:#selector(setShadowColor:) withObject:shadowColor];
//[object performSelector:#selector(setShadowOffset:) withObject:CGSizeMake(-2.5,0)];
}
}
}
(I use NSSelectorFromString rather than a #selector() because it means it's not really using undocumented things, kind of, if you get what I mean)
It's not entirely documented but I don't think I've used undocumented methods.
Basically what it does is take the red background from the destructive background and apply it to the other button named "Cancel".
So that should Apple change the color of the destructive button, so will the non-destructive-destructive change as well without needing an update. Although it doesn't use particularly Apple-safe methods.
I'm having a little bit of trouble with the commented-out line above, if you can help please answer here: performSelector:withObject:, but not with an object

Related

Moving status bar in iOS 7

The problem I'm facing is this:
I want to implement an iOS 7 app with nice design and left/right menu, which appears after the main view animate itself to the right/left. I'm doing this with [UIView animateWithDuration...] code, but that's not really important. What I want to achieve is the same effect the Mailbox iOS 7 app has: to move the status bar away (to the right/left) with the main view
Image for better explanation:
What I only found is this article about the issue, with some working code using Private APIs, which I'd like not to use, since I want my app to be accepted on the App Store.
I'd like to achieve the same effect ('legally'). Does anybody knows how to?
Thanks!
The gist of it is to use this method introduced in iOS 7:
https://developer.apple.com/documentation/uikit/uiscreen/1617814-snapshotview:
With that you get a UIView containing a screenshot that includes the status bar. Once you have that, it's just a matter of hiding your current view then pushing the screenshot view around.
I posted a proof of concept here:
https://github.com/simonholroyd/StatusBarTest
NOTE I haven't submitted code that does this through the Apple review process, but this is not a private API method.
So, after the initial push by Mr. Simon Holroyd and some searching, I've found the solution of how to achieve this "effect" functionality. This is the code:
statusbarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
EDIT: mister pcholberg correctly pointed out that the former code did not work on the actual device, only on the iOS Simulator, so I've edited it by his recommendation
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
UIView *screenShot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
[statusbarView addSubview:screenShot];
[statusbarView setClipsToBounds:YES];
[self.view addSubview:statusbarView];
[self setPrefersStatusBarHidden:YES];
[self prefersStatusBarHidden];
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
}
...
- (BOOL)prefersStatusBarHidden
{
return prefersStatusBarHidden;
}
...
So the first part creates context, uses the method Simon mentioned, draws the view with the statusbar, and saves that as an UIImage
The second part adds the snapshot UIView to my viewController's UIView
And the third part sets my bool for statusbar to YES (for easier use in the method above), and calls methods to redraw it
This then sets the UIView as not-functional statusbar at its place and hides the original one, so there is no double-rendering. Then I can use this view in my [UIView animateWithDuration... method
And when I return, I use this code in the completion handler of the animation block:
[statusbarView removeFromSuperview];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
{
[self setPrefersStatusBarHidden:NO];
[self prefersStatusBarHidden];
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
}
And voilá! This works as the described effect in my question.
Hope this helps somebody!
I use this method to move statuebar with slider view,in a application there are two window,one normal window,other statuBarWindow,i get statuBarView which superView is statuBarWindows ,and move it with slider view.
- (UIView *)statuBarView
{
NSString *key = [[NSString alloc] initWithData:[NSData dataWithBytes:(unsigned char []){0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x61, 0x72} length:9] encoding:NSASCIIStringEncoding];
id object = [UIApplication sharedApplication];
UIView *statusBar = nil;
if ([object respondsToSelector:NSSelectorFromString(key)]) {
statusBar = [object valueForKey:key];
}
return statusBar;
}
I just created BSPanViewController which makes it extremely easy to achieve this effect. The control and instructions on how to use it can be found on GitHub.
The implementation is the same as the one explained by Simon Holroyd.
In my experience, App Store reviewers generally don't care about private API's use, especially this simple and harmless.
For the task you can get a pointer to application's status bar view through several methods, which you can find in iOS complete headers like https://github.com/nst/iOS-Runtime-Headers

Drag from NSOutlineView never accepted

I'm trying to implement dragging from an NSOutlineView and although the drag starts OK it is never accepted by another app. The pertinent code is:
- (BOOL) outlineView:(NSOutlineView*)pOutlineView writeItems:(NSArray*)pItems toPasteboard:(NSPasteboard*)pBoard
{
CItem* theItem = [pItems objectAtIndex:0];
BOOL canDrag = ([theItem subItems] == 0);
if (canDrag) {
[pBoard clearContents];
[pBoard writeObjects:[NSArray arrayWithObject:[theItem name]]];
}
return canDrag;
}
[theItem name] returns an NSString*. At some point I'll want to add more to the pasteboard contents but until I can get it to work with a simple string there doesn't seem to be much point in getting into that.
The drag looks fine but the receiver doesn't show any highlighting when being hovered over and the drag image 'flies back' when released.
Any help gratefully received!
Rev. Andy
Turns out that draggingSourceOperationMaskForLocal: is never called for the delegate of NSOutlineView (or NSTableView possibly) so that drag operation is never allowed. Subclassing NSOutlineView just to override this method fixes everything.

How do i properly discard a subview?

I have a problem with my app where the code for which is far too long to go into, but suffice to say when i'm removing a UIView and replacing it with a new one like so:
NSLog(#" .. %#", (Icon *)[self viewWithTag:index]);
Icon *icon = (Icon *)[self viewWithTag:index];
CGRect frame = icon.frame;
int tag = icon.tag;
[icon removeFromSuperview];
[icon release];
Icon *icon2 = [[Icon alloc] init];
icon2.frame = frame;
[icon2 makeIconStandardWithTag:(int)tag];
[self addSubview:icon2];
It does some weird thing where that NSLog the first time (because the view is already there) shows that the object is an icon, but the second time after running this code shows that it's a UIImageView for some reason now, and it displays what i presume to be the original icon at some odd position on the screen. It's very erratic behaviour. But what i do know is this:
Removing the [icon removeFromSuperview]; line, although keeping the object there, stops this behaviour and causes the NSLog to return an Icon, as it should.
So my guess is that it's not removing icon correctly. Is there a way to completely remove icon, or is removeFromSuperview as far as i can go. What i could do is just have it set to alpha = 0 but this is more of a patch-over solution and not how i want to solve it.
"Is there a way to completely remove
icon, or is removeFromSuperview as far
as i can go"
You can set the object to nil:
icon = nil;
Can you verify what "self" is in this line of code:
It might not be what you think.
[self addSubview:icon2];
NSLog(#" Self is %#", self);
This is a guess, but try setting self.tag to -1 or some other value that doesn't collide with the tags you're setting on your Icon objects. The viewWithTag: method searches the current view and its subviews for a match, so if self.tag == 0 and you call [self viewWithTag:0], you'll get self.
Did you retain icon somewhere prior to this? If not, no need to release it after the call to removeFromSuperview. Similarly, unless you need the reference to icon2 elsewhere, you can release that after calling addSubview.
Views retain views added via addSubview, and they release views removed via removeFromSuperview.

UITextField settext not working

This is frustrating the hell out of me. I am a beginner programmer and cannot figure out why the text is not being changed.
Here is my method which is supposed to set the text of a UITextField:
-(void)updateDays:(NSInteger)days
{
NSString* daysString = [[NSString alloc] initWithFormat:#"%d", days];
[daysTextField setText:daysString];
[daysString release];
}
For whatever reason nothing is happening.
Help appreaciated!
Anytime you have a frustration along the lines of "why isn't this line working", use the debugger or just add an NSLog before it to print out the relevant data:
NSLog(#"updateDays: %# %# <= %#", daysTextField, daysTextField.text, daysString);
Then you know the line (a) is getting executed, (b) the variables are the ones you think they are, and (c) the values are reasonable.
I have experienced this several times, but I think all of them was reasoned by that the UITextField was not initialized at that point.
Set a breakpoint and use debugger to make sure that your UITextField is not nil. You should also check the connection between the .xib file and your code.
Check if the method is called. If yes check if the textfield is set up properly. Cross check to see if the IBOutlet connections are made to the correct object.
I meet this problem too .
It's my code:(in viewdidload)
UITextView *tv = [[UITextView alloc]initWithFrame:CGRectMake(0,0,320,50)]];
tv.text = #"12345";
tv.textColor=[UIColor blackColor];
[self.view addSubView:tv];
And the text(12345) doesn't show;
Lastly,I found that when i set textColor to gray,or any color not black,it works;
I think that it's a bug of the simulator.
I use xcode 4.2 and the iphone5.0simulator.

Multiple red/destructive buttons UIActionSheet

Is there any way to have more than 1 red "destructive button" in an iPhone app's UIActionSheet?
I need to have different clear options, in the same action sheet, one where it deletes everything and one where it deletes less, so both need to be red.
I just created a simple customizable replacement for UIActionSheet for iPhone to use in a similar case. It does not use the standard appearance, but this can be changed. Probably it is of any use to you.
https://github.com/4marcus/WMActionSheet
The poster of this question seemed to manage what you want...if i understand you correctly.
Is using subviews in Alert undocumented
EDIT:
I swear I searched for UIActionSheet the first time. Really.
http://www.nearinfinity.com/blogs/andrew_homeyer/display_a_custom_uiview_like_a.html
There's no supported way of doing this on the standard UIActionSheet. You could build your own "action sheet" replacement using gradient buttons like the ones here:
http://iphonedevelopment.blogspot.com/2010/05/gradient-buttons-yet-again.html
I would expect someone to have created a more customizable lookalike action sheet replacement, but I don't know of one off the top of my head.
I tried this before I saw griotspeak updated answer:
SEL getTitle = NSSelectorFromString(#"title");
SEL getBackground = NSSelectorFromString(#"background");
SEL setBackground = NSSelectorFromString(#"setBackgroundImage:");
SEL setTitleColor = NSSelectorFromString(#"setTitleColor:");
UIImage *redImage;
UIColor *titleColor;
UIColor *shadowColor;
for (NSObject *object in [action subviews]) {
if ([[NSString stringWithFormat:#"%#", [object class]] isEqualToString:#"UIThreePartButton"]) {
if ([[object performSelector:getTitle] isEqualToString:#"Clear all"]) {
redImage = [object performSelector:getBackground];
titleColor = [object performSelector:#selector(titleColor)];
shadowColor = [object performSelector:#selector(shadowColorForState:) withObject:0];
shadowOffset = [object performSelector:#selector(shadowOffset)];
}
if ([[object performSelector:getTitle] isEqualToString:#"Clear all except this month"]) {
[object performSelector:setBackground withObject:redImage];
[object performSelector:setTitleColor withObject:titleColor];
[object performSelector:#selector(setShadowColor:) withObject:shadowColor];
//[object performSelector:#selector(setShadowOffset:) withObject:CGSizeMake(-2.5,0)];
}
}
}
(I use NSSelectorFromString rather than a #selector() because it means it's not really using undocumented things, kind of, if you get what I mean)
It's not entirely documented but I don't think I've used undocumented methods.
Basically what it does is take the red background from the destructive background and apply it to the other button named "Cancel".
So that should Apple change the color of the destructive button, so will the non-destructive-destructive change as well without needing an update. Although it doesn't use particularly Apple-safe methods.
I'm having a little bit of trouble with the commented-out line above, if you can help please answer here: performSelector:withObject:, but not with an object