tableview update cells at wrong indexpath - tableview

i´ve got a problem with tableview.
i have a list of audio track and i check every track if this track actually exists. if not, i set a deleted image over the artwork in cells image view.
//SET DELETED IMAGE IF TRACK NOT EXISTS
if (!trackExists && cell.trackImageView.subviews.count < 1) {
UIImageView *deletedImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 60, 60)];
deletedImageView.image = [self resizeImageWithImage:[UIImage imageNamed:#"cellDeletedImage"] scaledToSize:CGSizeMake(60, 60)];
[cell.trackImageView addSubview:deletedImageView];
}
sometimes when i reload the tableview, the deleted image is on existing tracks. i know there are more efficient ways to do this, but i tried and tried and i ended up here.
also i logged this method, and it puts the deleted image even when there is no log.

Chances are, that if you're using table views as they are designed, that you are reusing cells. Does this happen when you scroll the table up and down a few times too? Does one cell that has the deleted image suddenly not have it if you scroll again?
It sounds like the reused cell still has a reference to that deleted image.
It's not quite clear where you add that image view, but I suggest that you move that code to the custom class for your table view cell (or create one if it doesn't exist). Subsequently in prepareForReuse, ensure that the image view is removed or hidden.
#class TrackTableViewCell : UITableViewCell
{
- (void) prepareForReuse
{
//Remove / hide image view
}
- (void) setAsDeleted
{
//Add / show image view
}
}
(Forgive objective-c syntax errors! I've been using Swift for a while now.)

Related

How to expand table view cell and show content beneath it?

I want to have the table view cell expand and show the buttons that I have laid out below the visible view when the cell isn't selected. So far I have managed to expand the cell so that the entire view shows with the buttons, but there is one major problem with this....
The buttons that are supposed to be revealed only when the cell is selected always appear in the table, and the table view looks really weird becuase for each cell there are buttons overlapping the next cell which were supposed to be hidden!
I have tired making a subclass of the cell, but I am stuck because when I override the setSelected method to show the button, all the buttons from all the cells show up, not just the one I clicked, Ill provide my code below.
I there an easier way to show the buttons without using a subclass? And if not how could I use the subclass in a way that wouldn't show all the buttons for all the cells?
Cell Subclass (.m file)
- (void)awakeFromNib {
// Initialization code
editHidden.hidden = YES;
removeHidden.hidden = YES;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
editHidden.hidden = NO;
removeHidden.hidden = NO;
// Configure the view for the selected state
}
Your table view delegate needs to implement tableView:heightForRowAtIndexPath:. Implement this method to return the correct height for your cell given the state that it is in (collapsed or expanded). When it comes time to expand your cell you should update your state and call [tableView beginUpdates]; [tableView endUpdates]; to have it recalculate and relayout the tableview.

Continuous scroll with UIScrollView Xcode

How do I make a scroll view start over again?
IE: my UIScrollView is 1000px wide. The user will swipe through the view to find a topic. When the user reaches the last topic (say topic 10) how do I have the UIScrollView start back at the beginning (topic 1) without having to scroll backwards?
So, the view will just continue in a circle forever, if the user wishes.
This is the method that you are going to use:
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
after you detect that user reaches the last topic.
I am assuming you are using a paging UIScrollView with topics as pages. The trick is to duplicate the end pages, and then when the user swipes to the last page in the scrollview (which is a duplicate of the first page) and the deceleration stops you want to change the content offset back to the first page.
When I needed to do this, I found this post. I used setContentOffset in scrollViewDidEndDecelerating rather than scrollRectToVisible, but either approach will work.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{
if (scrollView.contentOffset.x == 0) {
[scrollView setContentOffset:contentOffsetOfLastTopic animated:NO];
}
else if (scrollView.contentOffset.x == contentOffsetOfLastPage) {
[scrollView setContentOffset:contentOffsetOfFirstTopic animated:NO];
}
}

NSSplitView resizes the custom NSView contained

I've a vertical NSSplitView, the bottom subview contains a custom view (eg NSView) and a NSTextView.
The NSView contains inside it two NSButtons.
When I resize the splitView, making it smaller, the NSView containing the buttons is resized, too.
I don't want this behavior.
To better explain my problem please view the attached image.
Image 1: the window at application startup, everything is ok
Image 2: I've resized making smaller the split view, only a little part of buttons is visible
Image 3: I've enlarged again the split view but as you can see the NSView remains smaller and buttons are no longer visible (if I resize the splitView to bottom the NSView 'disappears')
This is a vicious problem that's based on the legacy workings of Cocoa views. The best solution I've seen is to constrain the minimum dimension of any portion of the split view. If the subviews never collapse, their metrics don't cross into another dimension and they should re-enlarge just fine.
To do this, set up a delegate for your split view, which will implement - splitView:constrainMaxCoordinate:ofSubviewAt:. The split view will call your delegate method hoping it can leave the max divider position at the height of the split view (passing this in as the second argument), but you can simply subtract some quantity from that value (say, 60) to return it as the minimum height for the bottom view.
- (CGFloat)splitView:(NSSplitView *)aSplitView
constrainMaxCoordinate:(CGFloat)proposedMin
ofSubviewAt:(NSInteger)dividerIndex {
return proposedMin - 60;
}
Of course, you'll probably want to do more checking in this method to make sure you're talking about the right split view, and the right subview, to avoid overreaching effects, but this is the basic idea.
(See also this fabulicious article on the subject.)
Constraining the divider position did not help in my case, as I'm animating the subviews and subviews can be collapsed.
I managed to achieve an acceptable solution by implementing the splitView delegate method -splitviewWillResizeSubviews: (means, you have to connect the delegate property from the split view to your controller in IB or in code) to maintain a minimum width by setting the subview to hidden instead of shrinking it to zero:
- (void)splitViewWillResizeSubviews:(NSNotification *)notification {
NSUInteger divider = [[[notification userInfo] valueForKey:#"NSSplitViewDividerIndex"] intValue];
NSView *subview = nil;
if(divider == SPLITVIEW_DIVIDER_SIDEBAR) {
subview = (NSView*)[self.splitView.subviews objectAtIndex:SPLITVIEW_SIDEBAR_INDEX];
}
if(subview) {
if(subview.frame.size.width < SPLITVIEW_MINIMUM_SIDEBAR_WIDTH) {
CGRect correctedFrame = subview.frame;
correctedFrame.size.width = SPLITVIEW_MINIMUM_SIDEBAR_WIDTH;
subview.frame = correctedFrame;
subview.hidden = YES;
} else {
subview.hidden = NO;
}
}
}

Unable to get tab order working within NSPopover

I have a View within an NSPopover, and I am unable to set the tab order correctly. I have set the nextKeyView within my 4 text fields. But it tends to flip from TextField1 to Search1, instead of TextField1 -> TextField2. I have tried inserting [self.view.window makeFirstResponder:textField1] also [self.view.window setInitialFirstResponder:textField1] along with recalculatekeyviewloop but with no luck.
Any help would be much appreciated.
I had a similiar problem when composing the popover-view of certain subviews programatically in awakeFromNIB. I could solve the problem by inserting the subviews after the popover had its private NSPopoverWindow set (i.e. it was shown the first time). It seems like the popover is re-evaluating the view-loop when the popover-view is embedded in the private child-window - ignoring the view-loop given in the view.
You could try the following:
-(void) popoverDidShow:(NSNotification *)notification{ // NSPopoverDelegate-method
if (!popoverDidShowForTheFirstTime){
[self setUpViews];
}...
-(void) setUpViews{
popoverDidShowForTheFirstTime = YES;
// insert views and establish nextKeyViews ...

NSTableView content view inset

I am looking to inset the contents of an NSTableView so that there is a gap between the top of the table view and the first cell.
On iOS this is easy with UITableView - achieved by using setContentInset:.
Turn headers back on and substitute the header view with your own subclass. Override its -drawRect: to draw only your background color. Also override -headerRectOfColumn: to prevent any of the column headers from being drawn. I'm not sure if this prevents column dragging or sorting but I'll bet it does.
The question asked how to adjust content insets similar to iOS. The currently selected answer shows how to move the first row down, but that's not quite the same thing. Adjusting the content insets will also move the start of the scrollbar to the inset position, just like iOS. This is useful when placing content underneath a "vibrant" or transparent toolbar.
An NSTableView itself does not have content insets. On macOS content insets are usually part of NSScrollView. To get access to the scroll view of NSTableView's view controller you can use the enclosingScrollview method of NSView, disable automatic adjustment and set the insets like this:
(warning old school Obj-C here)
self.enclosingScrollView.automaticallyAdjustsContentInsets = NO;
self.enclosingScrollView.contentInsets = NSEdgeInsetsMake(50.f,0.f,0.f,0.f);
Calling these from viewDidLoad is usually fine, however some types of table views will override your values with their own.
NSOutlineView set to source-list mode comes with lots of default values overridden to make the view look like the Finder sidebar.
There is no "clean" way to set the content-insets of these views. They stubbornly override your values, I've found that if you subclass NSOutlineView and overload setFrameSize: it will do the trick. So like this (inside the NSOutlineView subclass):
- (void)setFrameSize:(NSSize)newSize {
[super setFrameSize:newSize];
self.enclosingScrollView.automaticallyAdjustsContentInsets = NO;
self.enclosingScrollView.contentInsets = NSEdgeInsetsMake(100.f,0.f,0.f,0.f);
}
This will do the trick, but the initial scroll position will be strange. Calling scrollToBeginningOfDocument: from the initWithCoder: method of the subclass will scroll it to the correct initial position.
It's not very clean but you can achieve that by having the first row higher than the rest. Implement heightOfRow table delegate method:
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{
if (row == 0) {
return normalRowHeight + topPadding;
} else {
return normalRowHeight;
}
}
The drawback is that you would also need to implement custom highlighting and custom cell drawing to take into account the extra space for the first row.
scrollView.automaticallyAdjustsContentInsets = false
scrollView.contentInsets = NSEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)

Resources