我可以在向NSTableView添加行时创建自定义动画吗?

时间:2016-01-12 14:25:39

标签: swift macos cocoa nstableview osx-elcapitan

对于自定义动画,我的意思是像Clear一样。

许多现有的问题,如this,讨论动态高度,我想知道如何使用动画创建一个动态高度的新行。

e.g。显示此内容的动画:

enter image description here

2 个答案:

答案 0 :(得分:0)

以下是闪烁行的示例代码。不是动画本身。

@interface DTableView : NSTableView {
   NSTrackingArea       *trackingArea;
   NSUInteger mouseHoverRow;
   NSUInteger mouseHoverColumn;
   NSUInteger lastHoverRow;
   NSUInteger lastMouseHoverColumn; 

   NSUInteger      flashRow; // temporary flash
   DTableFlashType flashType;
   BOOL            flashToggle;

   NSUndoManager *textEditUndoManager; // private mgr, separate from global document undoManager!
}
@property (assign, nonatomic) NSUInteger      flashRow;
@property (assign, nonatomic) DTableFlashType flashType;

- (void)customDrawFlashRow:(NSRect)dirtyRect; // override point for subclassers
@end



@implementation DTableView
@synthesize flashRow;
@synthesize flashType;
-(void)awakeFromNib
{
   flashRow = NSNotFound;
}

// override point for subclassers.
// the default implementation flashes flashRow, depending on 
- (void)customDrawFlashRow:(NSRect)dirtyRect
{
   ///// NOTE! customDrawFlashRow is overridden by Director DScenesView

   if ( flashRow != NSNotFound )
   {

      NSRect rowFrame = [self frameOfCellAtColumn:0 row:flashRow];
      if ( NSIntersectsRect(rowFrame, dirtyRect) )
      {
         rowFrame.origin.x = dirtyRect.origin.x;
         rowFrame.size.width = dirtyRect.size.width;

         if ( flashType == kDTableFlashYellow )
         {
            flashToggle = !flashToggle;
            if ( flashToggle ) [[NSColor whiteColor] set];
            else               [[NSColor yellowColor] set];
         }
         else
            [[NSColor whiteColor] set];
         NSFrameRect(rowFrame);
      }
   }
}

- (void)drawRect:(NSRect)dirtyRect
{
   //getCpuCyclesMark();
   sVisRectIncrement++; // invalidate cache
   sDoingDrawRect = true;

   [super drawRect:dirtyRect];
   [self customDrawFlashRow:dirtyRect]; // overridden by Director DScenesView
   sDoingDrawRect = false;
}


- (void)setFlashRow:(NSUInteger)iRow // note: DScenesView overrides this
{
   // first, deal with previous flashRow if applicable
   if ( flashRow >= 0 && flashRow < [self numberOfRows] )
   {
      NSRect rowFrame = [self frameOfCellAtColumn:0 row:flashRow];
      rowFrame.origin.x = [self visibleRect].origin.x;
      rowFrame.size.width = [self visibleRect].size.width;

      [self setNeedsDisplayInRect:rowFrame];
   }

   flashRow = iRow;
   if ( flashRow >= 0 && flashRow < [self numberOfRows] )
   {
      NSRect rowFrame = [self frameOfCellAtColumn:0 row:flashRow];
      rowFrame.origin.x = [self visibleRect].origin.x;
      rowFrame.size.width = [self visibleRect].size.width;

      [self setNeedsDisplayInRect:rowFrame];
   }
}

在我的控制器类中:

     [toScenesTable setFlashRow:row];
     [self performSelector:@selector(endFlash:) withObject:self afterDelay:0.2]; // :@selector(endFlash)

和endFlash:selector

- (void)endFlash:(id)sender
{
   [toScenesTable setFlashRow:NSNotFound];
   //[toScenesTable setSelectionHighlightStyle:0];
}

答案 1 :(得分:0)

以下是我添加的NSTableView类别方法,它以有用的方式滚动,大约25%来自顶部。

#pragma mark NSTableView category
@implementation NSTableView (VNSTableViewCategory)

-(NSInteger)visibleRow
{
   NSRect theRect = [self visibleRect];
   NSRange theRange = [self rowsInRect:theRect];
   if ( theRange.length == 0 )
      return -1;
   else if ( NSLocationInRange( [self editedRow], theRange ) )
      return [self editedRow];        
   else if ( NSLocationInRange( [self clickedRow], theRange ) )
      return [self clickedRow];      
   else if ( NSLocationInRange( [self selectedRow], theRange ) )
      return [self selectedRow];
   else
      return theRange.location + (theRange.length/2);
}

-(NSRange)visibleRows
{
   NSRect theRect = [self visibleRect];
   NSRange theRange = [self rowsInRect:theRect];
   return theRange;
}
-(void)scrollRowToVisibleTwoThirds:(NSInteger)row
{
   NSRect theVisRect = [self visibleRect];
   NSUInteger numRows = [self numberOfRows];   
   NSRange visibleRows = [self rowsInRect:theVisRect];
   //NSUInteger lastVisibleRow = NSMaxRange(visibleRows);
   if ( NSLocationInRange( row, visibleRows ) )
   {
      if ( row - visibleRows.location < (visibleRows.length * 2 / 3) )
      {
         // may need to scroll up
         if ( visibleRows.location == 0 )
            [self scrollRowToVisible:0];
         else if ((row - visibleRows.location) > 2 )
            return;
      }
   }

   NSRect theRowRect = [self rectOfRow:row];

   NSPoint thePoint  = theRowRect.origin;
   thePoint.y -= theVisRect.size.height / 4; // scroll to 25% from top

   if (thePoint.y < 0 )
      thePoint.y = 0;

   NSRect theLastRowRect = [self rectOfRow:numRows-1];
   if ( thePoint.y + theVisRect.size.height > NSMaxY(theLastRowRect) )
      [self scrollRowToVisible:numRows-1];
   else
   {
      [self scrollPoint:thePoint]; // seems to be the 'preferred' method of doing this

      // kpk note: these other approaches cause redraw artifacts in many situations:
//      NSClipView *clipView = [[self enclosingScrollView] contentView];
//      [clipView scrollToPoint:[clipView constrainScrollPoint:thePoint]];
//      [[self enclosingScrollView] reflectScrolledClipView:clipView];
//      [self scrollRowToVisible:row];

//      [[[self enclosingScrollView] contentView] scrollToPoint:thePoint];
//      [[self enclosingScrollView] reflectScrolledClipView:[[self enclosingScrollView] contentView]];       
   }

}