The basis of my problem is that when I resize my window, the left pane of my split view resizes and the right side keeps a fixed width, i'd like it to work the other way around.
If I try to move the split divider to make the right side bigger, it snaps back.
I add the SplitView items in my NSSplitViewController subclass like this:
// Add a new SplitViewItem with list view
if (self.tabView == nil)
{
self.tabView = [self.storyboard instantiateControllerWithIdentifier:#"ListTabView"];
}
[self addChildViewController:self.tabView];
NSSplitViewItem *slSplitView = [self splitViewItemForViewController:self.tabView];
[slSplitView setCanCollapse:NO];
[slSplitView setHoldingPriority:260];
if (self.mediaview == nil)
{
self.mediaview = [self.storyboard instantiateControllerWithIdentifier:#"MediaView"];
}
[self insertChildViewController:self.mediaview atIndex:1];
NSSplitViewItem *slSplitViewMedia = [self splitViewItemForViewController:self.mediaview];
[slSplitViewMedia setCanCollapse:NO];
[slSplitViewMedia setHoldingPriority:251];
The subviews in my mediaView have their widths set to >=400 so that's not the issue.
Related
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.
I have an NSTextField in a container:
[textField setFrameOrigin:NSMakePoint(0, -t.frame.size.height)];
content = [[NSView alloc] init];
[content setWantLayer:YES]
content.layer=[CALayer layer];
[content addSubview:textField];
[content scaleUnitSquareToSize:NSMakeSize(1, -1)];
content.frame=textField.frame;
content.layer.backgroundColor=textBGColor.CGColor;
The container itself is located in a view with
[view scaleUnitSquareToSize:NSMakeSize(1, -1)];
This is all for obtaining a top left origin for the TextField and it works great, the only problem consist in the InsertionPoint not drawing (at least not in the visible frame).
I presume the InsertionPoint is either not Scaled or translated with the TextField. Other possibility is that InsertionPoint can't be drawn in a layer backed View.
Is there a way to display the InsertionPoint cursor ?
EDIT
After trying all the possibilities out, it seems the InsertionPoint (and the focusRing) are not drawing because of its frame being positioned out of the superviews bounds and its dirtyDrawRect. Is there a way to remove the clipping of an NSView ? I need to be able to place my TextField on every absolute position possible.
I found a way through: implementing the drawing myself.
1) giving a custom TextView as Editor for the window.
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject
{
if (!myCustomFieldEditor) {
myCustomFieldEditor = [[TextView alloc] init];
[myCustomFieldEditor setFieldEditor:YES];
}
return myCustomFieldEditor;
}
2) Overiding the drawInsertionPoint method in the custom TextView class.
-(void)drawInsertionPointInRect:(NSRect)rect color:(NSColor *)color turnedOn:(BOOL)flag{
[color set];
NSRectFill(rect);
[super drawInsertionPointInRect:rect color:color turnedOn:flag];
}
For insertion point just make your textfield to first responder.
[myTextField becomeFirstResponder];
i created a image view
for(int i=0; i<pcount; i++)
{
int x = rand() % 350;
int y = rand() % 350;
NSRect rect = NSMakeRect((x+10),(y+10), 200, 200);
//NSImageView *imageView
imageView1 = [[NSImageView alloc]initWithFrame:rect];
[imageView1 setTag:i];
// imageView = [[NSImageView alloc]initWithFrame:rect];
// [imageView1 rotateByAngle:rand() % 150];
[imageView1 setImageScaling:NSScaleToFit];
[imageView1 canBecomeKeyView];
NSImage *theImage = [[NSImage alloc]initWithContentsOfURL:(NSURL*)[patharray objectAtIndex:(i)]];
[imageView1 setImage:theImage];
[[imageView1 cell] setHighlighted:YES];
[[layoutCustom view] addSubview:imageView1 positioned:NSWindowMovedEventType relativeTo:nil];}
now how can select each image view by mouse click ? thanks in advance.
I'm assuming here that you have your reasons for not using existing collection views. So from what I read in your code you have layoutCustom.view, which contains a bunch of NSImageViews. Here are two options:
In your layoutCustom object implement the mouseDown: (or mouseUp: or both). Take the event location convert it view coordinates and look for any subview for which CGRectContainsPoint(subview.frame, mouseDownPoint) return YES. You should select that view.
Subclass NSImageView and implement mouseDown: (or mouseUp: or both). On mouseDown: simply set a "selected" flag. Either the view can draw something itself when selected or the layoutCustom object can observe the property and draw the selection accordingly.
I would prefer option 1 because it simpler, requires fewer classes and fewer interactions between objects.
// Option 1 (in layoutCustom class)
- (void) mouseDown:(NSEvent*)theEvent {
CGPoint mouseDownPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];
for (NSView *view in self.subviews) {
if (CGRectContainsPoint(view.frame, mouseDownPoint)) {
// Do something to remember the selection.
// Draw the selection in drawRect:
[self setNeedsDisplay:YES];
}
}
}
// Option 2 (in Custom subclass of NSImage)
- (void) mouseDown:(NSEvent*)theEvent {
self.selected = !self.selected;
}
// Option 2 (in layoutCustom class)
- (void) addSubview:(NSView*)view positioned:(NSWindowOrderingMode)place relativeTo:(NSView*)otherView {
[super addSubview:view positioned:place relativeTo:otherView];
[self startObservingSubview:view];
}
- (void) willRemoveSubview:(NSView*)view {
[self stopObservingSubview:view];
}
- (void) startObservingSubview:(NSView*)view {
// Register your KVO here
// You MUST implement observeValueForKeyPath:ofObject:change:context:
}
- (void) stopObservingSubview:(NSView*)view {
// Remove your KVO here
}
I've got a better idea: Instead of fighting with converting mouse clicks in a view to coordinates and then figuring out how to map it to the right subview or sub-image, why not have one big (or scrolling?) view and then add your images as giant "NSButton" objects (set to custom type), where the button images can be the images you want to add.
As for how to select each image? You can either subclass "NSButton" and keep track of some custom data within it, or you can use a "tag" to figure out which button was pressed in your "IBAction" method and then decide what to do with it.
Another approach might be to embed your images into NSTableView cells...
I have a ScrollView that contains a ContainerView. The ContainerView contains another View that the user is supposed to be able to pan around in.
The scrollView scrolls vertical only, the "view inside the containerView" is panable in all directions.
Here is what I have
self.scrollView.contentSize = CGSizeMake(1024,1440);
self.modelController = [self.storyboard instantiateViewControllerWithIdentifier:#"LCProduct3DViewController"];
self.modelController.meshIdentifier = self.meshIdentifier;
[self addChildViewController:self.modelController];
self.modelController.view.frame = self.threeDView.bounds;
[self.threeDView addSubview:self.modelController.view];
What happens is that the touch events inside the modelController's view and the ones outside the modelControler's view but inside the scrollview bounds seems to be getting the the way of each other.
I played around with
self.scrollView.canCancelContentTouches = NO;
self.scrollView.delaysContentTouches = NO;
but havent found a working solution yet.
Any Ideas ?
Thanks in advance
as can be found in other places:
The trick is to subclass the scrollView and override the hitTest method like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
if ([result isKindOfClass:[GLKView class]]) {
self.scrollEnabled = NO;
} else {
self.scrollEnabled = YES;
}
return result;
}
this way - if the hittest for the innver view is positive, scrolling for the scrollview is disabled and only the innver view will get the event.
I have a UITabBarController,displaying 4 tabs.
I want to add an animated UIViewController transition when user swiping screen to switch tab. (- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController method only work for select tab directly). transition will be in easeinout style.
I tried following codes but not work. only coming UIViewController moves, going UIViewController doesn't show at all.(I printed all UIViewControllers' frame data, all these 4 UIViewControllers are {0,0},{320,480} )
// Get views. controllerIndex is passed.
UIViewController *fromVC = [_tabBarController.viewControllers objectAtIndex:startIndex];
UIViewController *toVC = [_tabBarController.viewControllers objectAtIndex:to];
UIView *fromView = fromVC.view;
UIView *toView = toVC.view;
MWLog(#"from view is %#",fromView);
int direct = startIndex - to;
// calculate move direction.
if (direct < 0) {
CGRect outFrame = fromView.frame;
outFrame.origin.x = -320; // expect fromView will move to {-320,0}, out of screen.
MWLog(#"fromView's frame is %#", NSStringFromCGRect(fromView.frame));
CGRect inFrame = toView.frame;
inFrame.origin.x = 0;
MWLog(#"toView's frame is %#", NSStringFromCGRect(toView.frame));
[UIView beginAnimations:#"moveView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.5f];
toView.frame = inFrame;
fromView.frame = outFrame;
[UIView commitAnimations];
}else
{
// reverse moving. ignored....
}
Could you tell me what's wrong and how to do it correctly? thanks in advance!
finally I found the solution.
use CATransition animation, type push, type left or right depending on direction(by calculating tabbarcontroller's selectedIndex property). then, add this animation to tabbarcontroller's container view.
This view's reference can be got by enumerate all UIViews in [tabbarcontroller subviews] array. Actually, if no custom UIView, tabbarcontroller contains 2 subviews, one is UITabBar, the other is the container view, UITransitionView. Add animation on this view, you can enable page transition animation for different content screen.