NSImageView image aspect fill?

自闭症网瘾萝莉.ら 提交于 2019-12-02 23:02:23
Chris Demiris

You may find it much easier to subclass NSView and provide a CALayer that does the aspect fill for you. Here is what the init might look like for this NSView subclass.

- (id)initWithFrame:(NSRect)frame andImage:(NSImage*)image
{
  self = [super initWithFrame:frame];
  if (self) {
    self.layer = [[CALayer alloc] init];
    self.layer.contentsGravity = kCAGravityResizeAspectFill;
    self.layer.contents = image;
    self.wantsLayer = YES;
  }
  return self;
}

Note that the order of setting the layer, then settings wantsLayer is very important (if you set wantsLayer first, you'll get a default backing layer instead).

You could have a setImage method that simply updates the contents of the layer.

I had the same problem. I wanted to have the image to be scaled to fill but keeping the aspect ratio of the original image. Strangely, this is not as simple as it seems, and does not come out of the box with NSImageView. I wanted the NSImageView scale nicely while it resize with superview(s). I made a drop-in NSImageView subclass you can find on github: KPCScaleToFillNSImageView

whale

You can use this: image will be force to fill the view size

( Aspect Fill )

imageView.imageScaling = .scaleAxesIndependently


( Aspect Fit )

imageView.imageScaling = .scaleProportionallyUpOrDown


( Center Top )

imageView.imageScaling = .scaleProportionallyDown

It works for me.

Here is what I'm using, written with Swift. This approach works well with storyboards - just use a normal NSImageView, then replace the name NSImageView in the Class box, with MyAspectFillImageNSImageView ...

open class MyAspectFillImageNSImageView : NSImageView {

  open override var image: NSImage? {
    set {
      self.layer = CALayer()
      self.layer?.contentsGravity = kCAGravityResizeAspectFill
      self.layer?.contents = newValue
      self.wantsLayer = true

      super.image = newValue
    }

    get {
      return super.image
    }
  }
}
Surjeet

For getting AspectFit property of UIImageView in Cocoa NSImageView have this method

[imageView setImageScaling:NSScaleProportionally];

Here are more options to change image display property.

enum {
    NSScaleProportionally = 0, // Deprecated. Use NSImageScaleProportionallyDown
    NSScaleToFit,              // Deprecated. Use NSImageScaleAxesIndependently
    NSScaleNone                // Deprecated. Use NSImageScaleNone
};

I was having an hard time trying to figure out how you can make an Aspect Fill Clip to Bounds :

Picture credit: https://osxentwicklerforum.de/index.php/Thread/28812-NSImageView-Scaling-Seitenverh%C3%A4ltnis/

Finally I made my own Subclass of NSImageView, hope this can help someone :

import Cocoa

@IBDesignable
class NSImageView_ScaleAspectFill: NSImageView {

    @IBInspectable
    var scaleAspectFill : Bool = false


    override func awakeFromNib() {
        // Scaling : .scaleNone mandatory
        if scaleAspectFill { self.imageScaling = .scaleNone }
    }

    override func draw(_ dirtyRect: NSRect) {

        if scaleAspectFill, let _ = self.image {

            // Compute new Size
            let imageViewRatio   = self.image!.size.height / self.image!.size.width
            let nestedImageRatio = self.bounds.size.height / self.bounds.size.width
            var newWidth         = self.image!.size.width
            var newHeight        = self.image!.size.height


            if imageViewRatio > nestedImageRatio {

                newWidth = self.bounds.size.width
                newHeight = self.bounds.size.width * imageViewRatio
            } else {

                newWidth = self.bounds.size.height / imageViewRatio
                newHeight = self.bounds.size.height
            }

            self.image!.size.width  = newWidth
            self.image!.size.height = newHeight

        }

        // Draw AFTER resizing
        super.draw(dirtyRect)
    }
}

Plus this is @IBDesignable so you can set it on in the StoryBoard

WARNINGS

  • I'm new to MacOS Swift development, I come from iOS development that's why I was surprised I couldn't find a clipToBound property, maybe it exists and I wasn't able to find it !

  • Regarding the code, I suspect this is consuming a lot, and also this has the side effect to modify the original image ratio over the time. This side effect seemed negligible to me.

Once again if their is a setting that allow a NSImageView to clip to bounds, please remove this answer :]

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!