NSScrollView具有未剪裁的内容视图? [英] NSScrollView with unclipped content view?

查看:563
本文介绍了NSScrollView具有未剪裁的内容视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法,我可以设置我的scrollview不剪辑其内容? (这是一个 NSTextView



我有一个NSScrollView的子类,并希望其内容强>被剪切到其界限。
我试过覆盖:

   - (BOOL)wantsDefaultClipping {
return NO;
}

MyScrollView MytextView 没有任何效果。
在iOS中,我只会这样做: myuitextView.clipsToBounds = NO; 如何在Cocoa中执行此操作?



EDIT



这是我想要实现的一个例子,但是在mac中
scrollview是white ,滚动器将永远不会超出其界限,但文本,因为我有 myuitextView.clipsToBounds = NO



< a href =https://i.stack.imgur.com/rwp8n.png =nofollow noreferrer>查看此处



EDIT2



我不介意剪辑我的视图像@Josh建议的。但我想要的真正的行为可以解释这张图片:





你看到的词*****编辑*****在第一次线?
我希望文本不会以这种方式剪切,而是要让它完全出现,并且我会放置一个半透明的图像,所以当它在框架之外时它会消失。



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



I想要能够控制该区域被NSClipView剪切。我认为这将解决我的问题。有没有任何替代方案?也许我可以通过NSTextView控制插入位置或滚动位置,所以插入符号将永远不会接近顶部/底部框架限制?或任何解决方案?



任何建议都可以。

解决方案

现在,它是2016年,我们使用充满活力的标题栏与全尺寸内容视图,我会添加我的想法,如何有人可能实现这一点。希望这将帮助任何来到这里寻找帮助,因为它帮助我的人。



这回答了关于标题栏下滚动的问题,但你可以很容易修改这个技术,使用insets和插入位置在其他的东西下滚动。



要获得滚动视图(有或没有NSTextView里面)标题栏,您可以使用:

  //对于透明标题。 
window.titlebarAppearsTransparent = true
window.styleMask = window.styleMask | NSFullSizeContentViewWindowMask
window.appearance = NSAppearance(named:NSAppearanceNameVibrantLight)

这实际上覆盖了标题栏将NSWindow放到窗口的contentView上。



在不知道标题栏的高度的情况下,将某些东西限制在窗口的顶部:

  //为窗口顶部布局指南的SOMEVIEW约束:
let topEdgeConstraint = NSLayoutConstraint(
item:SOMEVIEW,attribute:NSLayoutAttribute。 Top,
relatedBy:NSLayoutRelation.Equal,
toItem:window.contentLayoutGuide,
attribute:NSLayoutAttribute.Top,multiplier:1.0,constant:0.0)

自动启用约束:
topEdgeConstraint.active = true

这允许您限制元素的顶部到标题栏的底部(和或工具栏+任何附件视图)。这在2015年WWDC上显示: https://developer.apple.com/videos/ play / wwdc2014 / 220 /



要让scrollview滚动到标题栏,但在窗口的未隐藏部分显示其滚动条,将其固定到IB中的内容视图的顶部或通过代码,这将导致它在标题栏下。然后,让它自动更新 insets

  scrollView.automaticallyAdjustsContentInsets = true 

最后,您可以子类化窗口并处理游标/插入符位置。有一个假定的错误(或我的部分的开发人员错误),不会使scrollview总是滚动到光标/插入符号,当它高于或低于scrollview的内容插入。



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

  // MARK:NSTextViewDelegate 
func textViewDidChangeSelection(通知:NSNotification){
scrollIfCaretIsObscured()
textView.needsDisplay = true //防止选择使毛刺粘在
}

// MARK:我的滚动函数

func scrollIfCaretIsObscured(){
let rect = caretRectInWindow()
let y:CGFloat = caretYPositionInWindow ) - rect.height
// Todo:考虑文本视图的标尺高度,如果存在:
let tbHeight:CGFloat
if textView.rulerVisible {
//标尺显示:
tbHeight =(try!titlebarHeight())+ textViewRulerHeight
} else {
//标尺隐藏
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 {
//我自己的版本的东西,基于一个旧的,过时的
//回答堆栈溢出。
//信用: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
}

///滚动到文本视图内的当前插入位置。
/// - 参数textView:要使用的指定文本视图。
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)
}

枚举WindowErrors:ErrorType {
case CannotFindTitlebarHeight
}

///计算标题栏和工具栏的组合高度。
///不要在家里试试。
func titlebarHeight()throws - > CGFloat {
//尝试正式方式:
if self.titlebarAccessoryViewControllers.count> 0 {
let textViewInspectorBar = self.titlebarAccessoryViewControllers [0] .view
如果let titlebarAccessoryClipView = textViewInspectorBar.superview {
如果let view = titlebarAccessoryClipView.superview {
如果let titleBarView = view .superview {
let titleBarHeight:CGFloat = titleBarView.frame.height
return titleBarHeight
}
}
}
}
throw WindowErrors。 CannotFindTitlebarHeight
}

希望这有助!


Is there a way I can set my scrollview not to clip its contents? (Which is a NSTextView)

I have a subclass of NSScrollView and want its content not to be clipped to its bounds. I have tried overriding:

- (BOOL) wantsDefaultClipping{
    return NO;
}

in MyScrollView and in MytextView without any effect. In the iOS I would simply would do: myuitextView.clipsToBounds=NO; how can I do this in Cocoa?

EDIT

This is an example of what I want to achieve but in the mac The scrollview is white, the scroller will never go outside its bounds but the text does since I did myuitextView.clipsToBounds=NO

See picture here

EDIT2

I wouldn't mind clip my view like @Josh suggested. But the real behaviour I would like to have can be explained with this picture:

Do you see the word *****EDIT***** that has being cut in the very first line? I want the text not to be cut this way, rather I want it to completely appear and I will put a semitransparent image so it looks like it fades off when it's outside the frame.

Q: Why don't I simply put a semitransparent NSImageView on it so it looks like what I want? A: Because 1.Scroller will be faded as well. Even if I correctly place the semitransparent NSImageView so the scroller looks fine, the cursor/caret will be able to go underneath the semitransparent NSImageView again it does not look good.

I would like to be able to control the area is clipped by NSClipView. I think that would solve my problem. Is there any alternative I have? maybe I can control the caret position or scrolling position through NSTextView so caret will never go near the top/bottom frame limits? or any work-around?

Any advice is appreciated.

解决方案

Now that it's 2016 and we're using vibrant titlebars with full size content views, I'll add my thoughts to how someone might accomplish this. Hopefully, this will help anyone who came here looking for help on this, as it helped me.

This answers the question in regards to scrolling under the titlebar, but you could easily modify this technique to scroll under other things using the insets and caret position.

To get a scroll view (with or without an NSTextView inside of it) to scroll behind a titlebar, you can use:

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

This effectively overlays the titlebar of the NSWindow onto the window's contentView.

To constrain something to the top of the window without knowing the height of the titlebar:

// 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

This allows you to constrain the top of an element to the bottom of the titlebar (and or toolbar + any accessory views it may have). This was shown at WWDC in 2015: https://developer.apple.com/videos/play/wwdc2014/220/

To get the scrollview to scroll under the titlebar but show its scrollbars inside the unobscured part of the window, pin it to the top of the content view in IB or via code, which will cause it to be under the titlebar. Then, tell it to automatically update it's insets:

scrollView.automaticallyAdjustsContentInsets = true

Finally, you can subclass your window and handle the cursor/caret position. There is a presumed bug (or developer error on my part) that doesn't make the scrollview always scroll to the cursor/caret when it goes above or below the content insets of the scrollview.

To fix this, you must manually find the caret position and scroll to see it when the selection changes. Forgive my awful code, but it seems to get the job done. This code belongs in an NSWindow subclass, so self is referring to the window.

// 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
}

Hope this helps!

这篇关于NSScrollView具有未剪裁的内容视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆