How to increase the height of NSTableHeaderView? - objective-c

I need to implement a headerview with specific size and gradient. I have to insert images in certain cells of the headerview.Tried to create the cells for the headerview using the following code,but i was not able to customize the headerview.
[[tableColumn headerCell] setImage:[NSImage imageNamed:#"sampleHeader"]];
If I use the overridden subclass of headerview, I was not able to view the images or text in the header cell.Please provide me any pointers to solve this issue.
I was able to insert images and text by subclassing the NSTableHeaderCell.How to increase height of the NSTableHeaderView?
If I subclass both NSTableHeaderView and NSTableHeaderCell , was not able to view anything in the
headercell.I used the following code for setting headerview and headercell
[tableView setHeaderView:CustomHeaderView];
[tableColumn setHeaderCell:[[[CustomHeaderTableCell alloc] initImageCell:
[NSImage imageNamed:#"sample"]]autorelease]];
I have the same issue as given in the below url
http://lists.apple.com/archives/cocoa-dev/2002/Jun/msg00331.html

You don't need to subclass NSTableHeaderView.
I was able to change the height of the header view using the following snippet in the controller class:
-(void)awakeFromNib {
NSRect frame = tableView.headerView.frame;
frame.size.height = 26;
tableView.headerView.frame = frame;
}
It should be noted that the scroll view takes care of the layout. It automatically changes the frame of the headerView as necessary, but leaves the height intact. Resizing the clip view etc as suggested in the other answer is not necessary.

You can also create a NSTableHeaderView object, initialize it with a frame(rect with height and width) and set that NSTableHeaderView object to your table view.
NSTableHeaderView *tableHeaderView = [[NSTableHeaderView alloc] initWithFrame:NSMakeRect(0, 0, 120, 60)];
[myTableView setHeaderView:tableHeaderView];
[tableHeaderView release];

Following link helped me in solving the issue.
http://lists.apple.com/archives/cocoa-dev/2003/Feb/msg00676.html
You need to set the Frame for NSClipView, NSTableHeaderView and the CornerView
This is how I implemented the same in Code.
for(NSView * subview in [topScrollView subviews])
{
for(NSView * subSubView in [subview subviews])
{
if([[subSubView className] isEqualToString:#"NSTableHeaderView"] && [[subview className] isEqualToString:#"NSClipView"])
{
[subSubView setFrameSize:NSMakeSize(subSubView.frame.size.width, subSubView.frame.size.height+5)];//HeaderView Frame
[subview setFrameSize:NSMakeSize(subview.frame.size.width, subview.frame.size.height+5)];//ClipView Frame
}
}
if ([[subview className] isEqualToString:#"_NSCornerView"])
{
[subview setFrameSize:NSMakeSize(subview.frame.size.width, subview.frame.size.height+5)]; //CornerView Frame
}
}

Related

UITableViewCell content overlaps delete button when in editing mode in iOS7

I am creating a UITableView with custom UITableViewCells. iOS 7's new delete button is causing some problems with the layout of my cell.
If I use the "Edit" button, which makes the red circles appear I get the problem, but if I swipe a single cell it looks perfect.
This is when the Edit button is used:
[self.tableView setEditing:!self.tableView.editing animated:YES];
This is when I swipe a single cell:
As you can se my labels overlaps the delete button in the first example. Why does it do this and how can I fix it?
try using the accessoryView and editingAccessoryView properties of your UITableViewCell, instead of adding the view yourself.
If you want the same indicator displayed in both editing and none-editing mode, try setting both view properties to point at the same view in your uiTableViewCell like:
self.accessoryView = self.imgPushEnabled;
self.editingAccessoryView = self.imgPushEnabled;
There seems to be a glitch in the table editing animation in IOS7, giving an overlap of the delete button and the accessoryView when switching back to non-editing state. This seems to happen when the accesoryView is specified and the editingAccessoryView is nil.
A workaround for this glitch, seems to be specifying an invisible editingAccessoryView like:
self.editingAccessoryView =[[UIView alloc] init];
self.editingAccessoryView.backgroundColor = [UIColor clearColor];
The problem is that in edit mode the cell's contentView changes in size. So either you have to override layoutSubviews in your cell and support the different frame sizes
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect contentFrame = self.contentView.frame;
// adjust to the contentView frame
...
}
or you take the bait and switch to autolayout.
First I thought setting contentView.clipsToBounds to YES could be an ugly workaround but that does not seem to work.
I've resolved this problem with set up constraints without width only leading and trailing
As tcurdt mentioned, you could switch to autolayout to solve this issue. But, if you (understandably) don't want to mess with autolayout just for this one instance, you can set the autoresizingMask and have that turned automatically into the appropriate autolayout constraints.
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
Just use this method in your custom TableViewCell class you can get the perfect answer,
Here self is UITableviewCell
- (void)layoutSubviews {
[super layoutSubviews];
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
if ([NSStringFromClass([subview2 class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]) { // move delete confirmation view
[subview bringSubviewToFront:subview2];
}
}
}
}
And if any one want to adjust the Delete Button Size, Use the following Code
- (void)layoutSubviews {
[super layoutSubviews];
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
if ([NSStringFromClass([subview2 class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]) { // move delete confirmation view
CGRect rect = subview2.frame;
rect.size.height = 47; //adjusting the view height
subview2.frame = rect;
for (UIButton *btn in [subview2 subviews]) {
if ([NSStringFromClass([btn class]) isEqualToString:#"UITableViewCellDeleteConfirmationButton"]) { // adjusting the Button height
rect = btn.frame;
rect.size.height = CGRectGetHeight(subview2.frame);
btn.frame = rect;
break;
}
}
[subview bringSubviewToFront:subview2];
}
}
}
}
Best way to remove this problem is that add an image in cell and set it in Backside.
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bgImg.png"]];
imageView.frame = CGRectMake(0, 0, 320, yourCustomCell.frame.size.height);
[yourCustomCell addSubview:imageView];
[yourCustomCell sendSubviewToBack:imageView];
If your text would overlap the delete button then implement Autolayout. It'll manage it in better way.
One more case can be generate that is cellSelectionStyle would highlight with default color. You can set highlight color as follows
yourCustomCell.selectionStyle = UITableViewCellSelectionStyleNone;
Set your table cell's selection style to UITableViewCellSelectionStyleNone. This will remove the blue background highlighting or other. Then, to make the text label or contentview highlighting work the way you want, use this method in yourCustomCell.m class.
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
if (highlighted)
self.contentView.backgroundColor = [UIColor greenColor];
else
self.contentView.backgroundColor = [UIColor clearColor];
}
I hope you understand it in a better way.
Bringing to front UITableViewCellDeleteConfirmationView in the layoutSubviews of the custom cell works for me on iPhone, but not on iPad.
I have a UITableView in the master part of a splitViewController for the iPad, and in this case
the frame of the UITableViewCellDeleteConfirmationView is (768 0; 89 44), instead of (320 0; 89 44)
So I resize the frame in the layoutSubviews method and this works for me
- (void)layoutSubviews {
[super layoutSubviews];
for (UIView *subview in self.subviews)
{
for (UIView *subview2 in subview.subviews)
{
if ([NSStringFromClass([subview2 class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"])
{
CGRect frame = subview2.frame;
frame.origin.x = 320;
subview2.frame = frame;
[subview bringSubviewToFront:subview2];
}
}
}
}
If you are putting content in the UITableViewCell's contentView, be sure you use self.contentView.frame.size.width and not self.frame.size.width in layoutSubviews.
self.frame expands width in editing mode, and will cause any content on the right to extend past the bounds of the contentView. self.contentView.frame stays at the correct width (and is what you should be using).
Try this: Might be you are setting cell setBackgroundImage in cellForRowAtIndexPath (Delegate Method). Do not set this here. Set your image in:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellList.png"]]; }
Enjoy Coding.
My solution is to move whole contentView to the left when Delete button showing:
override func layoutSubviews() {
super.layoutSubviews()
if editingStyle == UITableViewCellEditingStyle.Delete {
var rect = contentView.frame
rect.origin.x = self.showingDeleteConfirmation ? -15 : 38
contentView.frame = rect
}
}

NSScrollView doesn't scroll

I'm porting an iPhone app that uses this tutorial into a Mac app. I've been able to get text to display in NSScrollView, but I can't get the text to scroll and I hope someone knows what I am missing.
In the iPhone app, CTView is subclassed from UIScrollView
CTView.h:
#interface CTView : UIScrollView <UIScrollViewDelegate> {
1) But there is no NSScrollViewDelegate in AppKit. Is the missing delegate interface to NSScrollView the problem?
So for the Mac app, CTView.h looks like the following:
#interface CTView : NSScrollView
In CTView.m I have
[self setHasHorizontalScroller:YES];
[self setAcceptsTouchEvents:YES];
Also inside CTView.m I create a NSMutableArray of frames as
self.frames = [NSMutableArray array];
and fill the array up with frames. I also set the frame for the document view for the complete larger image that I want to be able to scroll through as:
[[self contentView] setFrame:[self bounds]];
[self.documentView setFrame: NSMakeRect(0, 0, totalPages * self.bounds.size.width, textFrame.size.height)];
The first frame is visible in the CTView, but when I move the horizontal scroll bar, the second frame doesn't show up in CTView.
I'm using Xcode 4.3.3 and Mac OS X 10.7.4.
Does anyone know what I need to do differently from UIScrollView for NSScrollView to be able to scroll through the frames?
Finally figured it out. Whew!
1) NSScrollView needs a view for its documentView, where the documentView is what is scrolled over. So in the nib I created a NSScrollView that contained a view for the documentView and set the documentView to that view as shown by the code in CTView.m
NSArray *viewArray = [self subviews];
NSArray *docViewArray = [[viewArray objectAtIndex:0] subviews];
NSView *docView = [docViewArray objectAtIndex:0];
[self setDocumentView:docView];
2) Then I added the array of frames, that would normally be added to UIScrollView, to the documentView of NSScrollView. The array of frames consists of multiple elements of content.
while (textPos < [attString length]) {
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(textPos, 0), innerPath, NULL);
CFRange frameRange = CTFrameGetVisibleStringRange(frame);
CTColumnView* content = [[[CTColumnView alloc] initWithFrame: NSMakeRect(0, 0, self.contentSize.width, self.contentSize.height)] autorelease];
[docView addSubview: content]; // <<-- Here is where the frames are added to the documentView
textPos += frameRange.length;
}
And that did the trick.

Changing Popover view frame on fly

When a popover is displaying how can I make its size variable depending on condition check? Is this functionality supported or not when working with a popover?
Here is my sample for changing frame size:
CGFloat newHeight = 200;
NSRect newFrame = [parentView frame];
newFrame.size.height = newHeight;
NSView* childView = someView;
[parentView setFrame:newFrame];
[self.view addSubview:childView];
Don't know if anything was changed but in 10.9 all you have to do is setContentSize on the popover, e.g.:
[popoverView setFrame:NSMakeRect(0, 0, 581, 581)];
[thePopover setContentSize:popoverView.frame.size];
You need to change the popupwindow.contentViewController property of the NSPopover to a new NSViewController with a different-sized view.
That is, resizing the view's frame will only result in weird drawing problems. To get the popover window to change size, the contentViewController must be changed.
Ideally, you would set up a new view controller which is essentially a copy of your existing NSViewController, but containing a view that is taller/shorter. But in the worst-case scenario, you can do something like this:
gPopoverWindow.contentViewController = [[[NSViewController alloc] initWithNibName: #"tempNibName" bundle: nil] autorelease];
NSView *v = self.view;
NSRect b = [v frame];
b.size.height += 25;
[v setFrame: b];
gPopoverWindow.contentViewController = self;
In my testing, this resulted in the popover beginning a shrink animation (because of being set to the temp view controller), then growing to its new size.

How to pass scrolling input to a different view

This site really is awesome.
I have what is hopefully a simple question this time. I would like to pass any scrolling input from the user (could be wheel, touchpad, etc) to an NSScrollView which contains my own subviews.
At the moment if the user scrolls just on the documentView (outside of my subviews' frames) the scroll works normally but if they scroll while the cursor is over a subview nothing happens. So basically I'd like to have the subview recognise the scroll event and pass it back to the scroll view.
Any help is greatly appreciated.
Cheers.
EDIT:
Here is the code I'm using to add the subviews to the documentView
_milestoneView and _activityView are both NSView subclasses which have a corresponding nib (created with instantiateNibWithOwner and objects hooked up accordingly) they contain a NSTextField, PXListView and some have a NSProgressIndicator.
-(void)useProject:(NSNumber *)projectId
{
[self resetView];
NSRect bounds = [[self view] bounds];
NSRect defaultFrame = NSMakeRect(20, NSMaxY(bounds)-93, NSMaxX(bounds)-20, 50);
//Prepare the milestone view
if (_milestoneView == nil)
_milestoneView = [MilestoneView milestoneViewFromNibWithFrame:defaultFrame withProject:[BCLocalFetch projectForId:projectId]];
[_milestoneView reloadList];
//Prepare the activity view
if (_activityView == nil)
_activityView = [ActivityView activityViewFromNibWithFrame:defaultFrame withProject:[BCLocalFetch projectForId:projectId]];
[self refresh];
}
I then use the refresh method to reposition them as the content sizes vary so I wanted to have a separate method.
-(void)refresh
{
//Position the milestones first
[_milestoneView setFrameOrigin:NSMakePoint(20, NSMaxY([[self view] bounds])-[_milestoneView frame].size.height-60)];
if ([[_milestoneView milestones] count] > 0)
[[self view] addSubview:_milestoneView];
//Now the activity view
[_activityView setFrameOrigin:NSMakePoint(20, [_milestoneView frame].origin.y-[_activityView frame].size.height-20)];
[[self view] addSubview:_activityView];
[self autosizeView];
}
-(void)autosizeView
{
//Resize the view to accommodate all subviews
NSRect oldFrame = [[self view] frame];
CGFloat lastY = [_activityView frame].origin.y;
if (lastY < 0) {
CGFloat newHeight = oldFrame.size.height + (-lastY);
[[self view] setFrameSize:NSMakeSize(oldFrame.size.width, newHeight)];
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"BBContentDidResizeNotification" object:self];
}
Ok so I came back to the issue and finally got it worked out. The implementation was actually quite simple.
I added a property to PXListView to point to the NSScrollView that is to be scrolled.
I then implemented NSResponder's scrollWheel: method like this:
-(void)scrollWheel:(NSEvent *)theEvent
{
//Pass scrolling to the superview
[_scrollHandler scrollWheel:theEvent];
}
And all is well!

NSScrollView doesn't display vertical scrollbar after adding content

I've created an NSScrollView which itself contains a NSClippedView as content view (this is all default, created by IB). Inside the contents view there is the (default) document view.
This NSScrollView has horizontal scroller disabled and vertical enabled and, most importantly auto hide scrollers enabled.
When I add new views (via code, runtime) to the document view the scroller does not unhide automatically, until the moment I vertically resize the window (and which in turn resizes the scrollview as well). 1px is enough. Just the new painting of the window seems enough.
What I am looking for is triggering this by code: so when I add views to the scrollviews' content view I would like the scrollbar to appear.
int numberOfChildViews = 10; //hard coded for example here
int childViewHeight = 80; //same as above
NSRect rect = NSMakeRect(0, 0, [[self.scrollView contentView] bounds].size.width, [numberOfChildViews*childViewHeight);
[[self.scrollView documentView] setFrame:rect];
[[self.scrollView documentView] setBounds:rect]; //just added to make sure
Then I added the custom views to the document view, like:
for (int i=0; i<numberOfChildViews; i++) {
NZBProgressViewController *item = [nzbProgressArray objectAtIndex:i];
int y=i*[[item view] bounds].size.height;
rect= NSMakeRect(0, y, [[scrollView contentView] frame].size.width, [[item view] bounds].size.height);
[[item view] setFrame:rect];
currentPosition++;
}
I am using a FlippedView so the origin will be displayed in left-top, like so:
#interface NSFlippedClipView : NSClipView {
}
#implementation NSFlippedClipView
- (BOOL)isFlipped {
return YES;
}
- (BOOL)isOpaque {
return YES;
}
#end
And added the following code to the awakeFromNib
NSFlippedClipView *documentView = [[NSFlippedClipView alloc] init];
[documentView setAutoresizingMask:NSViewWidthSizable];
[documentView setBackgroundColor:[self.scrollView backgroundColor]];
[self.scrollView setDocumentView:documentView];
[documentView release];
The scrollbars should become visible as soon as the document view is resized to be larger than the current viewport of the scroll view. Are you resizing the document view when you add your subviews to it?
Ahh, it's my own bad. For future reference: if you want to move the origin (0,0) to left-top use a NSView instead of NSClippedView extended class with IsFlipped method overriden to YES.
Thanks irsk for answering.