Swift:裁剪没有 TabBar 和 NavigationBar 的屏幕截图

Posted

技术标签:

【中文标题】Swift:裁剪没有 TabBar 和 NavigationBar 的屏幕截图【英文标题】:Swift: Cropping a Screenshot without TabBar and NavigationBar 【发布时间】:2015-08-15 03:24:51 【问题描述】:

我有整个屏幕的屏幕截图,screenshot,使用以下内容生成:

let layer = UIApplication.sharedApplication().keyWindow!.layer
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

layer.renderInContext(UIGraphicsGetCurrentContext())
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

我想裁剪它以便不包含标签栏,我尝试使用以下代码:

let crop = CGRectMake(0, 0, //"start" at the upper-left corner
self.view.bounds.width, //include half the width of the whole screen
self.view.bounds.height + self.navigationController!.navigationBar.frame.height) //include the height of the navigationBar and the height of view

let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
let image: UIImage = UIImage(CGImage: cgImage)!

此代码导致image 仅显示屏幕的一小部分,从屏幕左上角 (0, 0) 开始的矩形,向右延伸不到屏幕宽度的一半,然后向下低于屏幕高度的一半。不过,我希望它包含 整个 屏幕,但标签栏占据的区域除外。有没有这样的裁剪方法?

【问题讨论】:

【参考方案1】:

据此

新图像由创建 1) 通过调用CGRectIntegralrect 调整为整数范围; 2) 将结果与具有原点 (0, 0) 和大小的矩形相交 等于image的大小; 3) 引用生成的矩形内的像素,处理 图像数据的第一个像素作为图像的原点。 如果生成的矩形是空矩形,则此函数返回 空。

如果 W 和 H 分别是图像的宽度和高度,则 point (0,0) 对应图像数据的第一个像素;重点 (W-1, 0) 是图像数据第一行的最后一个像素; (0, H-1) 是图像数据最后一行的第一个像素; (W-1, H-1) 是 图像数据最后一行的最后一个像素。

你需要有这样的裁剪功能。您可能需要调整bottomBarHeight的计算方式

func takeScreenshot(sender: AnyObject) 
    let layer = UIApplication.sharedApplication().keyWindow!.layer
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

    layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    let croppedImage = self.cropImage(screenshot)


func cropImage(screenshot: UIImage) -> UIImage 
    let scale = screenshot.scale
    let imgSize = screenshot.size
    let screenHeight = UIScreen.mainScreen().applicationFrame.height
    let bound = self.view.bounds.height
    let navHeight = self.navigationController!.navigationBar.frame.height
    let bottomBarHeight = screenHeight - navHeight - bound
    let crop = CGRectMake(0, 0, //"start" at the upper-left corner
        (imgSize.width - 1) * scale, //include half the width of the whole screen
        (imgSize.height - bottomBarHeight - 1) * scale) //include the height of the navigationBar and the height of view

    let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
    let image: UIImage = UIImage(CGImage: cgImage)!
    return image

【讨论】:

【参考方案2】:

迅速:

let contextImage: UIImage = <<screenshot>>!
let cropRect: CGRect = CGRectMake(x, y, width, height)
let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, cropRect)
let image: UIImage = UIImage(CGImage: imageRef, scale: originalImage.scale, orientation: originalImage.imageOrientation)!

obj-c:

UIImage *image = <<screenshot>>;

CGRect croprect = CGRectMake(0, 0,
self.view.bounds.width,
self.view.bounds.height + self.navigationController!.navigationBar.frame.height));

// Draw new image in current graphics context
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], croprect);

// Create new cropped UIImage
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];

【讨论】:

这个问题在 Swift 中寻找答案,而不是在 Objective-C 中。 我的错...我加了 swift【参考方案3】:

您有两种选择: 首先,您可以使用UIApplication.sharedApplication().keyWindow 截取屏幕截图,然后我们将拥有这个:

    UIGraphicsBeginImageContext(UIApplication.sharedApplication().keyWindow!.bounds.size)
    UIApplication.sharedApplication().keyWindow!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

因此,您必须像这样裁剪图像:

    let yPosition = self.navigationController!.navigationBar.frame.height + UIApplication.sharedApplication().statusBarFrame.size.height
    let crop = CGRectMake(0, yPosition,
            self.view.bounds.width, 
            self.view.bounds.height)
    let cgImage = CGImageCreateWithImageInRect(screenshot.CGImage, crop)
    let image: UIImage = UIImage(CGImage: cgImage)!

第二种选择是直接截取您的视图,如下所示:

    UIGraphicsBeginImageContext(self.view!.bounds.size)
    self.view!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

在这种情况下,您不需要裁剪导航栏。

这是github上的示例代码https://github.com/gazolla/crop

【讨论】:

您关于裁剪图像的建议似乎没有达到我想要的效果——它仍然只是屏幕左上角的一小部分。 这会裁剪出导航栏,而不是标签栏。 我只是赞成你的回答,但我只是意识到它并不排除 tabBar【参考方案4】:

我认为你的作物CGRect 是错误的。

let crop = CGRectMake(0,
                      0,
                      self.view.frame.size.width,
                      self.view.frame.size.height + self.navigationController!.navigationBar.frame.height - self.tabBar.frame.size.height
                     )

X: 0 和 Y: 0 - 分别从 0 和 0 开始。

宽度:捕获视图的整个宽度

高度:整个视图的高度加上UINavigationBar 的高度减去UITabBar 的高度。

【讨论】:

对不起,这仍然不适合我,我仍然只看到左上象限。这可能与我正在使用的显示器类型(iPhone 6 Plus)有关吗? 你在哪里调用这个代码?视图控制器?子视图? 视图控制器,特别是导航栏按钮的操作。 “左上象限”是什么意思?你是指整个屏幕的左上象限吗?只有按钮?你能发布一个截图和一个可以重现问题的独立项目吗?【参考方案5】:

我在 Swift 4.2 中的回答,步骤在函数 getScreenshot() 代码上方的 cmets 中

@IBAction fileprivate func takeScreenshotButtonTapped(_ sender: UIButton) 

    guard let croppedScreenshotImage = getScreenshot() else  return 

    // do something with the croppedScreenshotImage


func getScreenshot() -> UIImage? 

    // 1. get screenshot of the entire screen
    UIGraphicsBeginImageContext(UIApplication.shared.keyWindow!.bounds.size)
    UIApplication.shared.keyWindow!.layer.render(in: UIGraphicsGetCurrentContext()!)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // 2. height of statusBar
    let statusBarHeight = UIApplication.shared.statusBarFrame.size.height

    // 3. height of navigationBar
    var navBarHeight: CGFloat = 0
    if let navigationBarHeight = navigationController?.navigationBar.frame.height 
        navBarHeight = navigationBarHeight
    

    // 4. total height of statusBar + navigationBar
    let topBarHeight = statusBarHeight + navBarHeight

    // 5. get the height of the tabBar
    var tabBarHeight: CGFloat = 0
    if let tabBarController = tabBarController 
        tabBarHeight = tabBarController.tabBar.frame.size.height
    

    // 6. to exclude the navigationBar, statusBar, and tabBar from your screenshot start the rect's y-axis at everything below the topBarHeight. For the height subtract the topBarHeight and tabBarHeight from the view's height 
    let rectWithoutNavStatusAndTabBar = CGRect(x: 0, y: topBarHeight, width: self.view.bounds.width, height: self.view.bounds.height - topBarHeight - tabBarHeight)

    guard let safeScreenshot = screenshot else  return nil 

    // 7. crop the screenshot to the rectWithoutNavStatusAndTabBar
    guard let cgImage = safeScreenshot.cgImage?.cropping(to: rectWithoutNavStatusAndTabBar) else  return nil 

    // 8. create an image from the cgImage
    let yourCroppedScreenshotImage = UIImage(cgImage: cgImage)

    return yourCroppedScreenshotImage

这也是公认答案的 Swift 4.2 版本:

func takeScreenshot(sender: AnyObject) 
    let layer = UIApplication.shared.keyWindow!.layer
    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

    layer.render(in: UIGraphicsGetCurrentContext()!)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    let croppedImage = self.cropImage(screenshot: screenshot!)


func cropImage(screenshot: UIImage) -> UIImage 
    let scale = screenshot.scale
    let imgSize = screenshot.size
    let screenHeight = UIScreen.main.bounds.height
    let bound = self.view.bounds.height
    let navHeight = self.navigationController!.navigationBar.frame.height
    let bottomBarHeight = screenHeight - navHeight - bound
    let crop = CGRect(x: 0, y: 0, width: (imgSize.width - 1) * scale, height: (imgSize.height - bottomBarHeight - 1) * scale)
    let cgImage = screenshot.cgImage?.cropping(to: crop)
    let image: UIImage = UIImage(cgImage: cgImage!)
    return image

【讨论】:

以上是关于Swift:裁剪没有 TabBar 和 NavigationBar 的屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

Swift 防止 TabBar 在键盘处于活动状态时向上移动

添加 TabBar 推送单元格并向上查看 [Swift]

如何在 Swift 中设置导航栏的标题? [复制]

如何在单击 tabBar 项目 Swift 上刷新 tableView?

如何在 tabBar swift 中更改项目或图像颜色?

swift 实现悬浮Tabbar