【问题标题】:Can I create custom animation in adding rows to NSTableView?我可以在向 NSTableView 添加行时创建自定义动画吗?
【发布时间】:2016-01-12 14:25:39
【问题描述】:

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

this 这样的许多现有问题都谈到了动态高度,我想知道如何使用动画创建具有动态高度的新行。

例如显示这个的动画:

【问题讨论】:

标签: swift macos cocoa nstableview osx-elcapitan


【解决方案1】:

这里是闪烁一行的示例代码。本身没有动画。

@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: 选择器

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

【讨论】:

  • 如何插入行?能够滚动和控制要显示的动画吗?
【解决方案2】:

这里是我添加的 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]];       
   }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多