I have a webview which I would like to remove the elasticity from. As it is now, when scrolling a page that is smaller than the webview, it will make an elasticity effect revealing the background underneath. I would like to remove this.
I have tried doing the following but without success. It finds the WebDynamicScrollBarsView but setting the elasticity of this, does not change anything.
- (void)awakeFromNib
{
NSScrollView *scrollView = [self findScrollViewInSubviews:self.subviews];
scrollView.horizontalScrollElasticity = NSScrollElasticityNone;
scrollView.verticalScrollElasticity = NSScrollElasticityNone;
}
- (NSScrollView *)findScrollViewInSubviews:(NSArray *)subviews
{
for (NSView *view in subviews)
{
if ([view isKindOfClass:[NSScrollView class]])
return (NSScrollView *) view;
else
return [self findScrollViewInSubviews:view.subviews];
}
return nil;
}
Does anyone know how to remove the elasticity effect from a webview?
In my subclass of WebView (or you can just do it directly, with webView.mainFrame.frameView.documentView.enclosingScrollView, but this makes it easier for me, personally)
// return the scroll view that we are currently using, if applicatble
- (NSScrollView *)mainScrollView {
return [[[[self mainFrame] frameView] documentView] enclosingScrollView]; // can be nil
}
Then on finish load, as Anne noted literally as I was typing my answer :) ,
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSScrollView *mainScrollView = [sender mainScrollView];
[mainScrollView setVerticalScrollElasticity:NSScrollElasticityNone];
[mainScrollView setHorizontalScrollElasticity:NSScrollElasticityNone];
}
I'm not sure if doing it after the content has loaded is necessary, but I don't have my mac with me to try right now.
Related
I am trying to customize an NSImageCell for NSTableView using NSArrayController and bindings to change the background of the cell which is selected. So, I created two NSImage images and retain them as normalImage and activeImage in the cell instance, which means I should release these two images when the cell calls its dealloc method. And I override
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
and
- (void) setObjectValue:(id) inObject
But I find that when I click any cell in the tableview, the cell's dealloc method is called.
So I put NSLog(#"%#", self); in the dealloc method and - (void)drawInteriorWithFrame:inView: and I find that these two instance are not same.
Can anyone tell me why dealloc is called every time I click any cell? Why are these two instances not the same? What does OS X do when I customize the cell in NSTableView?
BTW: I found that the -init is called only once. Why?
EDIT:
My cell code
#implementation SETableCell {
NSImage *_bgNormal;
NSImage *_bgActive;
NSString *_currentString;
}
- (id)init {
if (self = [super init]) {
NSLog(#"setup: %#", self);
_bgNormal = [[NSImage imageNamed:#"bg_normal"] retain];
_bgActive = [[NSImage imageNamed:#"bg_active"] retain];
}
return self;
}
- (void)dealloc {
// [_bgActive release]; _bgActive = nil;
// [_bgNormal release]; _bgNormal = nil;
// [_currentString release]; _currentString = nil;
NSLog(#"dealloc: %#", self);
[super dealloc];
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSLog(#"draw: %#", self);
NSPoint point = cellFrame.origin;
NSImage *bgImg = self.isHighlighted ? _bgActive : _bgNormal;
[bgImg drawAtPoint:p fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
NSPoint strPoint = cellFrame.origin;
strPoint.x += 30;
strPoint.y += 30;
[_currentString drawAtPoint:strPoint withAttributes:nil];
}
- (void) setObjectValue:(id) inObject {
if (inObject != nil && ![inObject isEqualTo:_currentString]) {
[self setCurrentInfo:inObject];
}
}
- (void)setCurrentInfo:(NSString *)info {
if (_currentString != info) {
[_currentString release];
_currentString = [info copy];
}
}
#end
As a normal recommendation, you should move to ARC as it takes cares of most of the memory management tasks that you do manually, like retain, releases. My answers will assume that you are using manual memory management:
Can anyone tell me why dealloc is called every time I click any cell ?
The only way for this to happen, is if you are releasing or auto-releasing your cell. If you are re-using cells, they shouldn't be deallocated.
Why these tow instance are not same ?
If you are re-using them, the cell that you clicked, and the cell that has been deallocated, they should be different. Pay close attention to both your questions, in one you assume that you are releasing the same cell when you click on it, on the second you are seeing that they are different.
What does Apple do when I custom the cell in NSTableView ?
Apple as a company? Or Apple as in the native frameworks you are using? I am assuming you are going for the second one: a custom cell is just a subclass of something that the NSTableView is expecting, it should behave the same as a normal one plus your custom implementation.
BTW: I found that the init is called only once, and why ?
Based on this, you are probably re-using cells, and only in the beginning they are actually being initialised.
It would be very useful to see some parts of your code:
Your Cell's code
Your NSTableView cell's creation code.
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 am a newbie in OSx development.
I have a Cocoa application which uses a Webview. Everything is working fine, except for the textfield in the webview. I know how to enable keystrokes in NSTextField, but not the ones in the Webview. I've been searching the web all day, but with no luck.
I badly need some help on how to enable the keystrokes to implement keyboard shortcut keys.
Example:
copy -> command + c
paste -> command + v
cut -> command + x
Any help would be very much appreciated.
I got the answer now. I've realized that I forgot to implement
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
to the class which handles the Webview.
#Kimpoy, thanks for the reference to performKeyEquivalent!
For completeness, I implemented it this way...
Subclass your webview from WebView and implement the method:
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent {
NSString * chars = [theEvent characters];
BOOL status = NO;
if ([theEvent modifierFlags] & NSCommandKeyMask){
if ([chars isEqualTo:#"a"]){
[self selectAll:nil];
status = YES;
}
if ([chars isEqualTo:#"c"]){
[self copy:nil];
status = YES;
}
if ([chars isEqualTo:#"v"]){
[self paste:nil];
status = YES;
}
if ([chars isEqualTo:#"x"]){
[self cut:nil];
status = YES;
}
}
if (status)
return YES;
return [super performKeyEquivalent:theEvent];
}
Credit to #aventurella over here: https://github.com/Beats-Music/mac-miniplayer/issues/3. Just modified slightly to return the super response as default because it should propagate down to its subviews.
As a note, I'd recommend implementing a log or similar in your custom webview to make sure you really are working with your class:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
NSLog(#"Custom webview running...");
}
I'm subclassing NSButton because I need to repeat a selector while the mouse is being held down.
I'm doing that like this:
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
[self setBezelStyle:NSBezelBorder];
PotRightIsDown = NO;
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
// Drawing code here.
}
- (void)mouseDown:(NSEvent *)theEvent;
{
NSLog(#"pot right mouse down");
PotRightIsDown = YES;
holdDownTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(sendCommand) userInfo:nil repeats:YES];
}
- (void)mouseUp:(NSEvent *)theEvent;
{
NSLog(#"pot right mouse up");
PotRightIsDown = NO;
}
-(void)sendCommand
{
if (PotRightIsDown)
{
NSLog(#"run the stuff here");
}
else
{
[holdDownTimer invalidate];
}
}
Works like a champ, sends the command every 100ms.
In the window in IB, I've dragged a Bevel Button onto the window and set it's class to this subclass. When I ran the application, the button is invisible however it works. I'm guessing this is because I have an empty drawRect function in the subclass.
How can I make this subclassed button look like a Bevel button?
Thank you,
Stateful
If you aren't adding any functionality to a particular subclass method then you can simply avoid implementing it altogether, which will allow the superclass to provide the default behaviour.
Alternatively (as pointed out my #Carl Norum) you can explicitly do that using:
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
}
But it's a bit pointless.
I'm trying to write an application that allows the user to drag files from the Finder and drop them onto an NSStatusItem. So far, I've created a custom view that implements the drag and drop interface. When I add this view as a subview of an NSWindow it all works correctly -- the mouse cursor gives appropriate feedback, and when dropped my code gets executed.
However, when I use the same view as an NSStatusItem's view it doesn't behave correctly. The mouse cursor gives appropriate feedback indicating that the file can be dropped, but when I drop the file my drop code never gets executed.
Is there something special I need to do to enable drag and drop with an NSStatusItem?
I finally got around to testing this and it works perfectly, so there's definitely something wrong with your code.
Here's a custom view that allows dragging:
#implementation DragStatusView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//register for drags
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
//the status item will just be a yellow rectangle
[[NSColor yellowColor] set];
NSRectFill([self bounds]);
}
//we want to copy the files
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{
return NSDragOperationCopy;
}
//perform the drag and log the files that are dropped
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard;
NSDragOperation sourceDragMask;
sourceDragMask = [sender draggingSourceOperationMask];
pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
NSLog(#"Files: %#",files);
}
return YES;
}
#end
Here's how you'd create the status item:
NSStatusItem* item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
DragStatusView* dragView = [[DragStatusView alloc] initWithFrame:NSMakeRect(0, 0, 24, 24)];
[item setView:dragView];
[dragView release];
Since Yosemite, the method for setting a view on NSStatusItem is deprecated but fortunately there is a much nicer way using the new NSStatusItemButton property on NSStatusItem:
- (void)applicationDidFinishLaunching: (NSNotification *)notification {
NSImage *icon = [NSImage imageNamed:#"iconName"];
//This is the only way to be compatible to all ~30 menu styles (e.g. dark mode) available in Yosemite
[normalImage setTemplate:YES];
statusItem.button.image = normalImage;
// register with an array of types you'd like to accept
[statusItem.button.window registerForDraggedTypes:#[NSFilenamesPboardType]];
statusItem.button.window.delegate = self;
}
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
//drag handling logic
}
Please be aware that the button property is only available starting in 10.10 and you might have to keep your old solution if you support 10.9 Mavericks or below.