UIGestures for a Two Finger Swipe Down From Top To Bottom - uigesturerecognizer

Pretty much a Gesture to bring in a separate Menu class with the Gesture being a two finger swip/pull from the very top of the screen to the very bottom of the screen. All I need is the code for the rest of my tweak. Thanks!

Your question is not clear enough.
but from what I understood, try UIScreenEdgePanGestureRecorgnizer
-(void)viewDidLoad{
[super viewDidLoad];
UIScreenEdgePanGestureRecognizer *gesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
gesture.edges = UIRectEdgeTop; //you can change it to whatever edge you want
[yourView addGestureRecognizer:gesture];
}
-(void)handleGesture:(UIScreenEdgePanGestureRecognizer* )arg {
//handle the gesture here
}

Related

xcode UITapGestureRecognizer on scrollview not calling until second tap

I have the following code to dismiss the keyboard if the user taps the background. It works fine if the scrollview is in the PointZero position, but if the user scrolls the view and then selects the textview, it doesn't call the "dismissKeyboard' method until the 2nd background tap.
On the first tap (for some reason) moves the scrollview offset to align with the scrollview frame to the screen bottom. The second tap will dismiss the keyboard and run the code below. I know it has to do with the scrollview. Any help would be appreciated.
Thanks
- (void)viewDidLoad {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
tapGesture.cancelsTouchesInView = NO;
[_scrollView addGestureRecognizer:tapGesture];
}
-(void)dismissKeyboard {
[self.view endEditing:YES];
}
- (void)keyboardWasShown:(NSNotification *)notification {
scrollViewRect = _scrollView.contentOffset.y;
NSDictionary* info = [notification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
keyboardSize.height += 10;
CGFloat viewBottom = CGRectGetMaxY(self.scrollView.frame);
if ([_itemNotes isFirstResponder]) {
CGFloat notesBottom = CGRectGetMaxY(_itemNotes.frame);
viewBottom -= notesBottom;
if (viewBottom < keyboardSize.height) {
keyboardSize.height -= viewBottom;
CGPoint scrollPoint = CGPointMake(0.0, keyboardSize.height);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
else {
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
}
else {
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification {
CGPoint scrollPoint = CGPointMake(0.0, scrollViewRect);
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
EDIT:
So I figured out a solution but it seems like there must be a better way to handle this. The problem was because I was setting the contentOffset of the scrollView so that the contentSize was beyond the screen boundaries. Thus the first tap was moving the scrollView contentOffset back within the screen boundaries and the second was performing the tap gesture. I will post my solution below hoping that someone has a better answer.
I would recommend setting
_scrollView.layer.borderColor = [UIColor redColor].CGColor;
_scrollView.layer.borderWidth = 1;
This will show you exactly where your scrollview boundaries are, which may not be where you think they are, or may be covered by something else. Also, when I open the keyboard, I generally set the scrollview frame bottom to the top of the keyboard. Otherwise, you may have content below the keyboard you can't get to. Not sure if this is exactly related to your issues.
I am assuming there must be a better solution to this but I was able to solve the issue by extending the contentSize when the keyboard is displayed and then shrinking it back down when the keyboard is hidden.
Set a float (scrollViewHeight) to hold the original content size for the reset.
//add this right before setting the content offset
scrollViewHeight = _scrollView.contentSize.height;
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width , scrollViewHeight + keyboardSize.height);
//add this right before reseting the content offset
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width , scrollViewHeight);
It really seems like there must be a better way that I'm not aware of. I will have to go back through the documentation to see if there is another way.

NSTextField Drawing on Top of Sub View

I have created a secondary NSViewController to create a progress indicator "popup". The reason for this is that the software has to interact with some hardware and some of the functions take the device a few seconds to respond. So being thoughtful of the end user I have a NSViewController that has a NSView (that is black and semi-transparent) and then a message/progress bar on top. This is added to the window using addSubView.
Everything works great except when the screen has a NSTextField in it. The popup shows but the NSTextField is drawn on top. What is this?
The view code I used for drawing semi-transparent:
#implementation ConnectingView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
CGContextSetRGBFillColor(context, 0.227,0.251,0.337,0.8);
CGContextFillRect(context, NSRectToCGRect(dirtyRect));
}
#end
The code I use to show the progress view
-(void) showProgressWithMessage:(NSString *) message andIsIndet:(BOOL) indet
{
connectingView = [[ConnectingViewController alloc] init];
[self.view.window.contentView addSubview:connectingView.view];
connectingView.view.frame = ((NSView*)self.view.window.contentView).bounds;
[connectingView changeProgressLabel:message];
if (indet)
[connectingView makeProgressBar:NO];
}
Is there a better way to add the subview or to tell the NSTextFields I don't want them to be drawn on top?
Thanks!
So Setting [self setWantsLayer] to my custom NSViews sort of worked however there are a lot of redraw issues (white borders, and backgrounds). A NSPopover may be better in some instances however I was going for "locked down" approach where the interface is unreachable until it finishes (or times out).
What worked for me was to go to the instance of my NSView, select the window in Interface Builder, then go to layers (far right on properties view) and select my view under "Core Animation Layer".

NSOutlineView scroll animation is not working

I want to remove the NSOutlineView's show/hide button.So,I override the NSOutlineView and get the mouseDown event.The follow is the code.
-(void)mouseDown:(NSEvent *)theEvent
{
NSLog(#"LeftFolderListOutlineView mouseDown");
[super mouseDown:theEvent];
NSPoint localPoint = [self convertPoint:theEvent.locationInWindow
fromView:nil];
NSInteger row = [self rowAtPoint:localPoint];
id clickedItem = [self itemAtRow:row];
if (![clickedItem isKindOfClass:[NSDictionary class]]) {
return;
}
if ([self isItemExpanded:clickedItem]) {
[[self animator] collapseItem:clickedItem];
}else{
[[self animator] expandItem:clickedItem];
}
}
It should be a scroll animation when the NSOutlineView collapse or expand.But in this case it's not working.Anyone tell me why and how can I improve this?
To remove 'show/hide button' (outline cell) you could implement - (NSRect)frameOfOutlineCellAtRow:(NSInteger)row method in the NSOutliveView subclass and return NSZeroRect.
NSOutlineView collapse/expand animation is not animatable via animator.
Only OS 10.7 or above provide collapse/expand animation effects. So it you planed to support older OS versions you need to provide separate implementation.
If you want to provide collapse/expand animation on OS 10.6 or below, you definitely needed to override 'drawRect' of NSOutlineView.
-- Update --
Sorry, I think I neglected the main point. 10.7 expand/collapse animation is automatically kick in only when users clicked the outline cell. If we want to show the animation without default outline cells, there is no other way but manually implementing animation effects, I think.
I made a sample project that implement expand/collapse animation effects with image drawing.
Check the source codes in here: https://github.com/roh0sun/ovanimation

How to add subview in ListView?

I am developing my first MAC application, i downloaded one Example of PxListView
and i have to added one button and background image on cell xib and bind them with controller
and, when on button click i was set height of that cell is much bigger then other. that is done,
and work fine.
but now i want to develop like after is witch cell has open in that cell i want to add some extra contain (Controller) on it, so how it will possible using given example?
pls help me to give some suggest how it will be done.
for Ex like before click on button
after chick on button i want to develop like
You write
i have to added one button and background image on cell xib and bind them with controller
It sounds like you've subclassed PXListViewCell--for convenience, let's call your subclass TemplateListViewCell--and added a xib from which instances of TemplateListViewCell will be loaded in
+[PXListViewCell cellLoadedFromNibNamed:bundle:reusableIdentifier:]
In addition, there is a[t least one] button in TemplateListViewCell.xib.
You write
when on button click i was set height of that cell is much bigger then other. that is done, and work fine
It sounds like this button has as its action a method on TemplateListViewCell such as
- (IBAction)toggleDetail:(id)sender
{
//Code to grow or shrink the height of [self frame].
//...
}
In my approach to implementing -toggleDetail, two modifications to the PXListView files were necessary:
1. Adding a protocol method
- (void)listView:(PXListView *)aListView setHeight:(CGFloat)height ofRow:(NSUInteger)row;
to the PXListViewDelegate protocol.
2. Adding a property
#property (nonatomic, assign) BOOL expanded;
to PXListViewCell.
My implementation of -toggleDetail looks something like this:
- (IBAction)toggleDetail:(id)sender
{
BOOL wasExpanded = [self expanded];
NSRect oldFrame = [self frame];
CGFloat oldHeight = oldFrame.size.height;
CGFloat newHeight = oldHeight;
CGFloat heightIncrement = 0.0f;
if (wasExpanded) {
heightIncrement = -80.0f; //use whatever value is appropriate
} else {
heightIncrement = 80.0f; //use whatever value is appropriate
}
newHeight += heightIncrement;
[[[self listView] delegate] listView:[self listView] setHeight:newHeight ofRow:[self row]];
[[self listView] reloadData];
BOOL isExpanded = !wasExpanded;
[self setExpanded:isExpanded];
}
It might seem better to use [[self listView] reloadRowAtIndex:[self row]]; in place of [[self listView] reloadData], but unfortunately, this doesn't work: if the user hides the detail--shrinks the cell vertically--new cells which should appear on the screen do not.
You write
that is done, and work fine.
It sounds like you were able to implement successfully a method analogous to -[TemplateListViewCell toggleDetail:].
You write
but now i want to develop like after is witch cell has open in that cell i want to add some extra contain (Controller) on it, so how it will possible using given example? pls help me to give some suggest how it will be done.
It sounds like you want instances of TemplateListViewCell to contain extra views if they are expanded.
It might seem tempting to put this code into -[TemplateListViewCell toggleDetail], but this will not work out as we might hope. The trouble is, we need to handle cases where expanded cells have been scrolled out of view and scrolled back into view.
To get this right, we need to have a notion of expanded which persists beyond the usage of a PXListViewCell subclass instance: we either need to keep track of expansion in the PXListView itself or in its delegate.
The better--but less expedient--design seems to be to keep track of this information in the PXListView itself. For the sake of this question, however, I'll demonstrate how to keep track of cell expansion in the delegate. To do this, I'm expanding the PXListViewDelegate protocol and making other changes to the PXListView files:
1. Adding the methods
- (void)listView:(PXListView *)aListView setExpanded:(BOOL)expanded atRow:(NSUInteger)row;
- (BOOL)listView:(PXListView *)aListView expandedAtRow:(NSUInteger)row;
to PXListViewDelegate.
2. Adding the method
- (void)setCell:(PXListViewCell *)cell expandedAtRow:(NSUInteger)row
{
if ([[self delegate] respondsToSelector:#selector(listView:expandedAtRow:)]) {
[cell setExpanded:[[self delegate] listView:self expandedAtRow:row]];
}
}
to PXListView.
3. Calling -[PXListView setCell:expandedAtRow:] from -[PXListView layoutCells]
- (void)layoutCells
{
//Set the frames of the cells
for(id cell in _visibleCells)
{
NSInteger row = [cell row];
[cell setFrame:[self rectOfRow:row]];
[self setCell:cell expandedAtRow:row];
[cell layoutSubviews];
}
NSRect bounds = [self bounds];
CGFloat documentHeight = _totalHeight>NSHeight(bounds)?_totalHeight:(NSHeight(bounds) -2);
//Set the new height of the document view
[[self documentView] setFrame:NSMakeRect(0.0f, 0.0f, NSWidth([self contentViewRect]), documentHeight)];
}
and from -[PXListView layoutCell:atRow:]:
- (void)layoutCell:(PXListViewCell*)cell atRow:(NSUInteger)row
{
[[self documentView] addSubview:cell];
[cell setFrame:[self rectOfRow:row]];
[cell setListView:self];
[cell setRow:row];
[cell setHidden:NO];
[self setCell:cell expandedAtRow:row];
}
4. Setting _expanded to NO in -[PXListViewCell prepareForReuse]:
- (void)prepareForReuse
{
_dropHighlight = PXListViewDropNowhere;
_expanded = NO;
}
Note: In the sample PXListViewCell subclass, MyListViewCell, distributed with PXListView, the implementation of -[MyListViewCell prepareForReuse] fails to call [super prepareForReuse]. Make sure that this call is made in [TemplateListViewCell prepareForReuse]:
- (void)prepareForReuse
{
//...
[super prepareForReuse];
}
One change needs to be made to -[TemplateListViewCell toggleDetail:]. The line
[self setExpanded:isExpanded];
needs to be replaced by
[[[self listView] delegate] listView:[self listView] setExpanded:isExpanded atRow:[self row]];
Once you've set up your PXListView's delegate to properly handle the new delegate methods, you're ready to override [PXListViewCell setExpanded:] in your subclass TemplateListViewCell:
- (void)setExpanded:(BOOL)expanded
{
if (expanded) {
//add detail subviews
} else {
//remove detail subviews
}
[super setExpanded:expanded];
}
Replace //add detail subviews with your own code which programmatically adds the detail subviews that you want and replace //remove detail subviews with code to remove the detail subviews that you want, checking to see that they are present first.
You write
i want to add some extra contain (Controller) on it
It sounds like you want to add view controllers rather than views to your TemplateListViewCell. To do this, use an NSBox and set the box's contentView to your view controller's view. (For details on this, see this answer.)
If you plan on just showing a single view controller's view in an NSBox on the expanded TemplateListViewCell, you can just (1) add a property to TemplateListViewCell referencing your view controller and (2) add an NSBox to TemplateListViewCell xib and set its contentView to the appropriate view controller's view on [cell setExpanded:YES] and set its contentView to nil on [cell setExpanded:NO].

NSColorWell subclass not getting mouseMoved events

I'm trying to implement a color picker in my Cocoa app. (Yes, I know about NSColorPanel. I don't like it very much. The point of rolling my own is that I think I can do better.)
Here's a picture of the current state of my picker.
(source: ryanballantyne.name)
The wells surrounding the color wheel are NSColorWell subclasses. They are instantiated programmatically and added to the color wheel view (an NSView subclass) by calling addSubView on the color wheel class.
I want to make it so that you can drag the color wells around by their grab handles. The start of that journey is making the cursor change to an open hand when the mouse hovers over the handles. Sadly, I can't use a cursor rect for this because most of my views are rotated. I must therefore use mouseMoved events and do the hit detection myself.
Here's the mouse event code I'm trying to make work:
- (void)mouseMoved:(NSEvent*)event
{
NSLog(#"I am over here!\n");
[super mouseMoved:event];
NSPoint eventPoint = [self convertPoint:[event locationInWindow] fromView:nil];
BOOL isInHandle = [grabHandle containsPoint:eventPoint];
if (isInHandle && [NSCursor currentCursor] != [NSCursor openHandCursor]) {
[[NSCursor openHandCursor] push];
}
else if (!isInHandle) [NSCursor pop];
}
- (void)mouseEntered:(NSEvent*)event
{
[[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseExited:(NSEvent*)event
{
[[self window] setAcceptsMouseMovedEvents:NO];
[NSCursor pop];
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)resignFirstResponder
{
return YES;
}
I find that my mouseMoved method is never called. Ditto for entered and exited. However, when I implement mouseDown, that one does get called, so at least some events are getting to me, just not the ones I want.
Any ideas? Thanks!
mouseEntered: and mouseExited: don't track entering/exiting your view directly; they track entering/exiting any tracking areas you've established in your view. The relevant methods are -addTrackingRect:owner:userData:assumeInside: and -removeTrackingRect:. Just pass [self bounds] for the first parameter if you want your whole view to be tracked. If your app is 10.5+ only, you should probably use NSTrackingArea instead as it directly supports getting mouse-moved events only inside the tracking area.
Keep in mind that 1) tracking rects have the same somewhat odd behavior as cursor rects w/r/t rotated views, and 2) if your bounds change (not merely your frame) you'll probably need to re-establish your tracking rect, so save the tracking rect's tag to remove it later.

Resources