I want to set an image as background that the content mode is scaleAspectFill
and stretch the bottom pixel of line to fullscreen.
Here is a simple sample image that the size is 1280x300px that will be set in Assets as 2x.
Here is a screenshot of the storyboard. I want to fill the the bottom pixel of line to the white space.
I have tried the Stretching
and the Slicing
feature but both effect are not what I want.
Here is the expected result what I want on iPhone 4S.
It's not clear how you are sizing your image...
The 1280 x 300
image you posted, with the imageView constrained to the width of the view...
AspectFit:
AspectFill (using the image's original 300 height):
AspectFill (using 150 height):
However, assuming the text in your images will have varying lengths, you may wind up with...
AspectFit:
AspectFill (using 150 height):
However... assuming you have a plan for solving that, one approach would be to use two image views.
The top image view would hold your full image as you already have it... using .scaleAspectFill
and constraining its height to show just the centered text in the image.
The bottom image view would be constrained to the bottom of the view, with .scaleToFill
, and you could use this extension:
extension UIImage {
// return the CGRect portion as a new UIImage
func subImage(in rect: CGRect) -> UIImage? {
let scale = UIScreen.main.scale
guard let cgImage = cgImage else { return nil }
guard let crop = cgImage.cropping(to: rect) else { return nil }
return UIImage(cgImage: crop, scale: scale, orientation:.up)
}
}
// then, use it like this
let bottomImage = fullImage.subImage(in: CGRect(x: 0.0, y: fullImage.size.height - 1.0, width: 8.0, height: 1.0))
to get an 8px x 1px
portion of the original image. Set the .image
of the bottom image view to that image and it will scale to fill the entire frame.
Result:
and here is a complete example, using your original image (I named it "wake.png"):
extension UIImage {
// return the CGRect portion as a new UIImage
func subImage(in rect: CGRect) -> UIImage? {
let scale = UIScreen.main.scale
guard let cgImage = cgImage else { return nil }
guard let crop = cgImage.cropping(to: rect) else { return nil }
return UIImage(cgImage: crop, scale: scale, orientation:.up)
}
}
class StretchBottomViewController: UIViewController {
var topImageView: UIImageView = {
let v = UIImageView()
v.translatesAutoresizingMaskIntoConstraints = false
v.contentMode = .scaleAspectFill
v.setContentHuggingPriority(.required, for: .vertical)
return v
}()
var bottomImageView: UIImageView = {
let v = UIImageView()
v.translatesAutoresizingMaskIntoConstraints = false
v.contentMode = .scaleToFill
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(topImageView)
view.addSubview(bottomImageView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain top image view to top / leading / trailing at Zero
topImageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
topImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
topImageView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
// constrain bottom image view to bottom of top image view / leading / trailing at Zero
bottomImageView.topAnchor.constraint(equalTo: topImageView.bottomAnchor, constant: 0.0),
bottomImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
bottomImageView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
// constrain bottom image view to bottom at Zero
bottomImageView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
// however you are determining the height of the top image view
// using 150 here to work with your original image
topImageView.heightAnchor.constraint(equalToConstant: 150.0),
])
// load "wake me up" image
if let fullImage = UIImage(named: "wake") {
// get the bottom part of the full image (8 pixels wide, 1-pixel tall)
if let bottomImage = fullImage.subImage(in: CGRect(x: 0.0, y: fullImage.size.height - 1.0, width: 8.0, height: 1.0)) {
topImageView.image = fullImage
bottomImageView.image = bottomImage
}
}
}
}