2011-04-25 16 views
2

有没有一种方法可以让我的scrollview不去剪辑它的内容? (这是一个NSTextView带有未剪切内容视图的NSScrollView?

我有一个NSScrollView的子类,并希望其内容而不是被剪切到其界限。 我试图压倒一切的:

- (BOOL) wantsDefaultClipping{ 
    return NO; 
} 

MyScrollViewMytextView无任何影响。 在iOS中,我只会做:myuitextView.clipsToBounds=NO;我该怎么在可可中做到这一点?

编辑

这是我想要达到一个例子,但在MAC 滚动视图是白色的,滚动条将永远不会在其范围之外,但文字确实,因为我做了myuitextView.clipsToBounds=NO

​​

EDIT2

我不会介意像@Josh所建议的那样剪辑我的视图。

normal NSScrollView with NSTextView

你看到已被切断的第一行字*****编辑*****:但真正的行为,我想有可能与此图片说明? 我希望文字不会被这样剪切,而是我希望它完全显示,并且我会放置一张半透明图像,以便它看起来像在框架外面时会消失。

问:为什么我不简单地放上一个半透明的NSImageView,所以它看起来像我想要的? 答:因为1.Scroller也会褪色。即使我正确放置半透明NSImageView,使滚动条看起来不错,光标/插入符号将能够在半透明NSImageView下面再次显示,看起来不太好。

我想能够控制该区域被NSClipView剪辑。我认为这将解决我的问题。我有没有其他选择?也许我可以通过NSTextView控制插入位置或滚动位置,这样脱字符将永远不会接近顶部/底部框架限制?或任何变通?

任何意见表示赞赏。

回答

0

我会简单地尝试观察文档视图的frame,并在文档调整大小时匹配滚动视图的frame

+0

即使文档没有调整大小,我也想达到这个目的......例如,当用户输入很多滚动视图不应该剪辑其内容时。不适合滚动视图框架的文本应该出现在滚动视图边界之外。 – nacho4d 2011-04-25 09:14:51

0

您可能会考虑使用半透明图层来实现此外观,而无需在视图外实际绘制。我不确定iOS上的规则,但在Mac上,超出界限的视图可能会干扰周围的绘图。

但是,您可以设置剪辑区域是不管你喜欢你的滚动视图子类的drawRect:使用-[NSBezierPath setClip:]内:

- (void)drawRect:(NSRect)dirtyRect { 

    [NSGraphicsContext saveGraphicsState]; 
    [[NSBezierPath bezierPathWithRect:[[self documentView] frame]] setClip]; 

    //... 

    [NSGraphicsContext restoreGraphicsState]; 
} 

可能可以(既然你问)在一个NSClipView子类使用此代码,但关于这方面的信息并不多,而且我认为您可能很难使其与滚动视图正确交互。如果是我,我会先尝试继承NSScrollView

+0

你有什么想法会发生什么,我把这段代码放在NSClipView的子类中?我已经更新了我的问题,因为我认为它不是很清楚。 – nacho4d 2011-04-29 07:36:53

+0

@ nacho4d:不,我不知道。没有太多有关'NSClipView'的信息,如果你继承它的话,你可能会有一段艰难的时间让它与它的滚动视图正确地交互。如果是我,我想我会尝试子类化'NSScrollView',但你当然可以尝试'NSScrollView'。 – 2011-04-29 09:09:35

+0

@nacho:我的意思是“...当然尝试'NSClipView'”,当然 – 2011-04-29 23:38:24

0

这是一个有点毛。 AFAIK,NSViews 不能在自己的框架外画出来。无论如何,我从来没有看到它完成,当我意识到UIView默认允许它时,我有些惊讶。但是你可能想在这里做的不是操纵裁剪矩形(在NSScrollView中做任何这样的事情可能不会做你想要的或期望的),而是试图掩盖垂直截断的文本行,无论是图层还是视图与背景颜色相同。也许你可以继承NSClipView并覆盖viewBoundsChanged:和/或viewFrameChanged:以便注意文本视图何时被移位,并相应地调整你的“阴影”。

+0

但是如果我这样做,插入符号仍然可以在“阴影”下面,例如开始输入时等等。 。这是我想避免的。我目前的做法是:将“阴影”放在滚动视图和子类NSScroller的顶部以调整插槽框架大小,以便我的垂直滚动条不会被“阴影”隐藏。尽管如此,它仍然有同样的问题。 ;( – nacho4d 2011-04-29 09:01:58

+0

)确实,脱字符号可能会消失,但在正常情况下也是可能的,你可以随时滚动以使脱字符号消失,就你的情况而言,它会稍微消失一些,因为你覆盖了一些像素; – 2011-04-29 09:10:45

+0

'NSView'可以_definitely_在它的框架之外绘制;你所要做的就是改变它的'drawRect:'中的剪辑矩形;它可以在它的窗口内容视图中的任何地方绘制它,这不是一个好主意(尽管你有做一些像自定义聚焦环一样的东西)幸运的是,这个窗口有一个“更难”的剪辑,可能是因为系统不会被困扰在活动窗口之外重绘,无论你说什么它。 – 2011-04-29 21:48:52

1

既然现在是2016年了,我们正在使用具有全尺寸内容视图的充满活力的标题栏,我会将自己的想法添加到某人可能实现的目标中。希望这能帮助任何来这里寻求帮助的人,因为这对我有帮助。

这回答了关于在标题栏下滚动的问题,但您可以轻松修改此技巧以使用插页和插入位置在其他事物下滚动。

为了得到一个滚动视图(有或没有的它内部的NSTextView)一个标题栏背后滚动,你可以使用:

// For transparent title. 
    window.titlebarAppearsTransparent = true 
    window.styleMask = window.styleMask | NSFullSizeContentViewWindowMask 
    window.appearance = NSAppearance(named: NSAppearanceNameVibrantLight) 

这有效地覆盖了NSWindow的标题栏到窗口的内容查看。

要限制一些东西到窗口的顶部不知道标题栏的高度:

// Make a constraint for SOMEVIEW to the top layout guide of the window: 
let topEdgeConstraint = NSLayoutConstraint(
item: SOMEVIEW, attribute: NSLayoutAttribute.Top, 
relatedBy: NSLayoutRelation.Equal, 
toItem: window.contentLayoutGuide, 
attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0.0) 

// Turn the constraint on automatically:  
topEdgeConstraint.active = true 

这可以让你的元素的顶部约束到标题栏的底部(和或工具栏+任何它可能有配件)。这表现在WWDC 2015年:https://developer.apple.com/videos/play/wwdc2014/220/

要获得滚动视图的标题栏下滚动,但显示窗口的遮掩部分内的滚动条,其固定在内容鉴于IB或通过代码的顶部,这将导致它在标题栏下。然后,告诉它自动更新它的插图

scrollView.automaticallyAdjustsContentInsets = true 

最后,你也可以继承你的窗口和处理光标/插入位置。有一个假设的错误(或我的部分开发人员错误),它不会使滚动视图始终滚动到光标/插入符号,当它超出或低于滚动视图的内容插入。

要解决此问题,您必须手动查找插入位置并在选择更改时滚动以查看它。原谅我糟糕的代码,但它似乎完成了工作。此代码属于NSWindow子类,因此self指的是窗口。

// MARK: NSTextViewDelegate 
func textViewDidChangeSelection(notification: NSNotification) { 
    scrollIfCaretIsObscured() 
    textView.needsDisplay = true // Prevents a selection rendering glitch from sticking around 
} 

// MARK: My Scrolling Functions 

func scrollIfCaretIsObscured() { 
    let rect = caretRectInWindow() 
    let y: CGFloat = caretYPositionInWindow() - rect.height 
    // Todo: Make this consider the text view's ruler height, if present: 
    let tbHeight: CGFloat 
    if textView.rulerVisible { 
     // Ruler is shown: 
     tbHeight = (try! titlebarHeight()) + textViewRulerHeight 
    } else { 
     // Ruler is hidden 
     tbHeight = try! titlebarHeight() 
    } 
    if y <= tbHeight { 
     scrollToCursor() 
    } 
} 

func caretYPositionInWindow() -> CGFloat { 
    let caretRectInWin: NSRect = caretRectInWindow() 
    let caretYPosInWin: CGFloat = self.contentView!.frame.height - caretRectInWin.origin.y 
    return caretYPosInWin 
} 

func caretRectInWindow() -> CGRect { 
    // My own version of something based off of an old, outdated 
    // answer on stack overflow. 
    // Credit: http://stackoverflow.com/questions/6948914/nspopover-below-caret-in-nstextview 
    let caretRect: NSRect = textView.firstRectForCharacterRange(textView.selectedRange(), actualRange: nil) 
    let caretRectInWin: NSRect = self.convertRectFromScreen(caretRect) 
    return caretRectInWin 
} 

/// Scrolls to the current caret position inside the text view. 
/// - Parameter textView: The specified text view to work with. 
func scrollToCursor() { 
    let caretRectInScreenCoords = textView.firstRectForCharacterRange(textView.selectedRange(), actualRange: nil) 
    let caretRectInWindowCoords = self.convertRectFromScreen(caretRectInScreenCoords) 
    let caretRectInTextView = textView.convertRect(caretRectInWindowCoords, fromView: nil) 
    textView.scrollRectToVisible(caretRectInTextView) 
} 

enum WindowErrors: ErrorType { 
    case CannotFindTitlebarHeight 
} 

/// Calculates the combined height of the titlebar and toolbar. 
/// Don't try this at home. 
func titlebarHeight() throws -> CGFloat { 
    // Try the official way first: 
    if self.titlebarAccessoryViewControllers.count > 0 { 
     let textViewInspectorBar = self.titlebarAccessoryViewControllers[0].view 
     if let titlebarAccessoryClipView = textViewInspectorBar.superview { 
      if let view = titlebarAccessoryClipView.superview { 
       if let titleBarView = view.superview { 
        let titleBarHeight: CGFloat = titleBarView.frame.height 
        return titleBarHeight 
       } 
      } 
     } 
    } 
    throw WindowErrors.CannotFindTitlebarHeight 
} 

希望这有助于!