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.
Related
In my MainControllerClass I have a few XIB's that I am initializing and throwing on the screen - Here is an Example
self.widgetPeopleToBuyFor = [[WidgetAddPeopleToBuyFor alloc] initWithNibName:#"WidgetAddPeopleToBuyFor" bundle:nil andUser:self.currentUser];
self.widgetPeopleToBuyFor.view.frame = CGRectMake(10,10,492,537);
self.widgetPeopleToBuyFor.delegate = self;
[self.viewMainView addSubview:self.widgetPeopleToBuyFor.view];
[self.viewMainView bringSubviewToFront:self.widgetPeopleToBuyFor.view];
if ([self.currentUser.wPeopleToBuyForRect length] > 2) {
NSLog(#"LOADING FROM DB");
CGRect rect9 = CGRectFromString(self.currentUser.wPeopleToBuyForRect);
self.widgetPeopleToBuyFor.view.frame = rect9;
}
else
{
NSLog(#"FIRST TIME");
self.widgetPeopleToBuyFor.view.frame = CGRectMake(10,10,492,537);
}
I'm building this app so the user can resize the the view to their desire, move it around etc. So when he user Exits I call this method to grab the view information.
- (NSString *) showInfoViewSize: (UIView *) view
{
return NSStringFromCGRect(view.frame);
}
So from there I save the information in the Database, it saves ok - But I just learned the size doesn't matter - I could change it to (10,10,200,200) and the view stays the same exact size on the screen.
So I know I threw a buch at you there. But in the End, the DB works fine - the IF statement gets fired off - Its just I can't resize the XIB on launch.
Should I be resizing it a different way? Should I keep track of the TRANSFORM from the pinch recoginier and just retransform it the scaleFactor at load? Seems kinda hokey to me.
Any help is appreciated - I've been beating myself up on this, and I bet its something super simple I'm missing.
view does not loads from xib until it is presented and hence at that time there will be no frame to set for view. let the view load first then set its frame afterwards.
change the view.frame in "viewWillAppear" in your controller's implementation.
Normally when something is just not working, it's because you've got a nil floating around somewhere you didn't expect. Remember, sending messages to nil is completely legal in ObjC (it just always returns nil).
So I'd step through this in the debugger and check everything to make sure it's a real instance and not nil.
But generally what you're doing (allocing a controller with a nib, setting that controller's view's frame, then adding the controller's view to a superview) is the correct way to do it.
I have a UITableView with a custom cell that has a TextField. I have the DecimalPad comes up, and as we all know, there is no done key. I previously had resolved this type of issue when I had a "Decimal only" textfield on a normal UIView by handling the TouchesEnded event and then checking to see if the TextField was the first responder and if so, it would then resign, but if that technique could work now then I'm not able to figure out who's TouchesEnded I should be using (The UIView that everything is presented on, the UITableView, the Cell, the CellControler, the TextField.. I think I've tried everything).
I'm hoping there's another, cleaner way of dealing with this.
Anyone?
I think David has the best idea - here is some Monotouch code to get you started. You will need to put this in the View Controller where the decimal pad is being shown:
UIView dismiss;
public override UIView InputAccessoryView
{
get
{
if (dismiss == null)
{
dismiss = new UIView(new RectangleF(0,0,320,27));
dismiss.BackgroundColor = UIColor.FromPatternImage(new UIImage("Images/accessoryBG.png"));
UIButton dismissBtn = new UIButton(new RectangleF(255, 2, 58, 23));
dismissBtn.SetBackgroundImage(new UIImage("Images/dismissKeyboard.png"), UIControlState.Normal);
dismissBtn.TouchDown += delegate {
textField.ResignFirstResponder();
};
dismiss.AddSubview(dismissBtn);
}
return dismiss;
}
}
If you're targeting iOS 4.0 or greater you can create an inputAccessoryView containing a Done button to attach to the keyboard that will dismiss the keyboard when tapped. Here is an example from the documentation on creating a simple inputAccessoryView.
You could dismiss it when the user taps on the background; I think that's the most intuitive way.
In Interface Builder, change your View's class to UIControl. This is a subclass of UIView, so your program will work the same way, but you also get the standard touch events.
From here it's simple, create a method for the Touch Down event:
[numberField resignFirstResponder]
Of course it might be slightly different with MonoTouch -- unfortunately I don't know much about it, but wanted to help.
Hopefully you can use the concept, and modify your code accordingly.
Or you may just add some gesture to your main view.
For example:
//Just initialise the gesture you want with action that dismisses your num pad
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
UISwipeGestureRecognizer *swipeToHideNumPad = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(hideNumPad:)];
swipeToHideNumPad.delegate = self;
swipeToHideNumPad.direction = UISwipeGestureRecognizerDirectionDown;
[swipeToHideNumPad setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:swipeToHideNumPad];
}
//action
- (void)hideNumPad:(UIGestureRecognizer *)gestureRecognizer
{
[self.amountTextField resignFirstResponder];
}
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
I have a view where a UITextView always has focus. What I want to do is extend the built-in undo/redo behavior to support undo/redo for when I programmatically set the text (e.g., for when I clear it, by setting it to #"").
Since only the firstResponder gets undo/redo events, I thought I'd simply use the UITextView's undoManager property to create my invocations. e.g.,
// Before clearing the text...
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:self.myTextView.text];
[self.myTextView.undoManager setActionName:#"Clear"];
// ...
-(void)undoClear:(NSString *)textToRestore
{
self.myTextView.text = textToRestore;
if ([self.myTextView.undoManager isUndoing])
{
// Prepare the redo.
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:#""];
}
}
Unfortunately, this is not working. It:
Introduces an empty item into the undo stack ("Undo")
The "Undo Clear" gets added after that item (if I tap "Undo", I see "Undo Clear")
Undo Clear and Redo Clear work, however, then I see "Undo Clear" again and it doesn't work from there on.
Any ideas? Am I approaching this wrong?
Update: It seems like I've figured out the empty undo item issue: it happens when I set the text of the UITextView after I've called prepareWithInvocationTarget. If I call it before, it doesn't happen. Funny thing is, the empty item isn't pushed onto the undo stack if I don't call prepareWithInvocationTarget (i.e., normally, when I set the text of a UITextView).
OK, figured it out:
The issue with #1 is as outlined in the update to my original post.
Issues #2 and #3 were just me using the NSUndoManager incorrectly. My final unClear method (which gets called on undos is as follows:
-(void)undoClear:(NSString *)textToRestore
{
NSString *textBackup = [self.myTextView.text copy];
self.myTextView.text = textToRestore;
if ([self.myTextView.undoManager isUndoing])
{
// Prepare the redo.
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:#""];
}
else if ([self.myTextView.undoManager isRedoing])
{
[[self.myTextView.undoManager prepareWithInvocationTarget:self] undoClear:textBackup];
}
[textBackup release];
}
It's working as it should now.
You can change your textview to whatever text you want and preserve undo and redo manager's memory stacks. self.content is UITextView.
-(void) yourClearAllButtonIsPressed
{
[[self.content.undoManager prepareWithInvocationTarget:self] undoClear:self.content.text];
[self.content setText:#""];//Or something else you want to change your textview to
}
}
//just one, my method I created
-(void) undoClearBlablabla:(NSString*) text
{
[[self.content.undoManager prepareWithInvocationTarget:self] undoClear:self.content.text];
[self.content setText:text];
}
I'm not sue how many Text Fields you are working with, though textBackup is not getting retained by prepareWithInvocationTarget: How is it still in the Undo Stack several clear's later? Seems like it might still be there after the first one, though not after the 2nd one or after the Autorelease pool flushes.
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