2017-05-24 64 views
1

所以我試圖做的Instagram類似觀點,這應該是相當簡單的。要開始只是一個UITableViewControllerUITableViewCell只包含一個標籤和圖像:具有動態大小和寬高比的UIImages。我究竟做錯了什麼?

class FoodListVC: UITableViewController { 

    let samples = [ 
     "things", 
     "stuff", 
     "foo" 
    ] 
    let images = [ 
     UIImage(named: "photo1"), 
     UIImage(named: "photo2"), 
     UIImage(named: "photo3") 
    ] 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Row size 
     tableView.rowHeight = UITableViewAutomaticDimension 
     tableView.estimatedRowHeight = 88 
    } 

    // MARK: - Table view data source 

    override func numberOfSections(in tableView: UITableView) -> Int { 
     return 1 
    } 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return samples.count 
    } 

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell", for: indexPath) as! FoodCell 

     cell.setContent(title: samples[indexPath.row], image: images[indexPath.row]!) 

     return cell 
    } 
} 

和:

class FoodCell: UITableViewCell { 
    @IBOutlet weak var titleLabel: UILabel! 
    @IBOutlet weak var mainImage: UIImageView! 

    override func awakeFromNib() { 
     super.awakeFromNib() 
     // Initialization code 
    } 

    override func setSelected(_ selected: Bool, animated: Bool) { 
     super.setSelected(selected, animated: animated) 

     // Configure the view for the selected state 
    } 

    func setContent(title: String, image: UIImage) { 
     titleLabel.text = title 

     mainImage.image = image 
     mainImage.backgroundColor = UIColor.red 
    } 

} 

在接口布局方面,事情看起來簡單,以及: enter image description here

但是,一旦我加載應用程序,利潤率僅僅是巨大的:enter image description here

我的理論是,圖像的尺寸大於可用於在手機中繪製圖像的尺寸,並具有「Aspect Fit」,它只是在圖像上方和下方添加了一些透明度。

我該如何解決這個問題?

+0

所以紅色是不想要的部分吧?你有沒有嘗試固定標籤的高度? – RomOne

回答

1

你似乎是讓圖像視圖大小的圖像視圖的固有大小來決定。但圖像視圖的固有尺寸取決於圖像的大小,而不管圖像視圖的內容模式如何。

不是依賴於攝像畫面的固有大小,您可以定義圖像視圖大小的限制,如:

class FoodCell: UITableViewCell { 
    @IBOutlet weak var titleLabel: UILabel! 
    @IBOutlet weak var mainImage: UIImageView! 

    private var aspectConstraint: NSLayoutConstraint? 

    func setContent(title: String, image: UIImage) { 

     // remove constraint, if any 

     if aspectConstraint != nil { 
      mainImage.removeConstraint(aspectConstraint!) 
     } 

     // add constraint 

     let ratio = image.size.width/image.size.height 
     aspectConstraint = NSLayoutConstraint(item: mainImage, attribute: .width, relatedBy: .equal, toItem: mainImage, attribute: .height, multiplier: ratio, constant: 0) 
     aspectConstraint?.priority = 999 
     mainImage.addConstraint(aspectConstraint!) 

     // set the image and label 

     titleLabel.text = title 
     mainImage.image = image 
     mainImage.backgroundColor = .red 
    } 

} 

注意,我設置爲高優先級的限制,但低於1000我這樣做的原因有兩個:如果您在返回執行剛剛在時間的調整限制

  • 首先,細胞會產生各種有關表視圖單元格的內在高度自動佈局警告從cellForRowAt(即使是約束實際上是完全可以滿足的)。第二,當你的單元的高度可以根據外部輸入(例如圖像的大小)而改變時,你經常想約束單元格中圖像視圖有多高,恕我直言,恕不另行通知。如果讓細胞圖像增長到荒謬的高度(如果什麼形象是一個蘿蔔,這是200像素寬和2000像素高大的垂直光),就可以結束了怪異UX在圖像的觀點是如此高大,你失去整個「我在桌面視圖中滾動」的氛圍。

    所以我喜歡約束圖像視圖的最大高度,不顧形象。因此,在IB中,我定義了一個約束條件,指出圖像視圖的高度應該爲<=到200點(使用任何你想要的值)。然後,我使用內容模式顯示「縮放比例適合」的圖像。


注意,除上述外,另一種方法是讓你的約束是,但調整圖像大小,本身,因此,如果它真的很大,它是按比例縮小的尺寸適合圖像視圖的寬度。例如,你可以這樣做:

func setContent(title: String, image: UIImage) { 
    titleLabel.text = title 

    if image.size.width > mainImage.frame.width { 
     let size = CGSize(width: mainImage.frame.width, height: max(200, mainImage.frame.width * image.size.height/image.size.width)) 
     mainImage.image = image.scaledAspectFit(to: size) 
    } else { 
     mainImage.image = image 
    } 

    mainImage.backgroundColor = .red 
} 

其中:

extension UIImage { 

    /// Resize the image to be the required size, stretching it as needed. 
    /// 
    /// - parameter newSize:  The new size of the image. 
    /// - parameter contentMode: The `UIViewContentMode` to be applied when resizing image. 
    ///       Either `.scaleToFill`, `.scaleAspectFill`, or `.scaleAspectFit`. 
    /// 
    /// - returns:    Return `UIImage` of resized image. 

    func scaled(to newSize: CGSize, contentMode: UIViewContentMode = .scaleToFill) -> UIImage? { 
     if contentMode == .scaleToFill { 
      return filled(to: newSize) 
     } else if contentMode == .scaleAspectFill || contentMode == .scaleAspectFit { 
      let horizontalRatio = size.width/newSize.width 
      let verticalRatio = size.height/newSize.height 

      let ratio: CGFloat! 
      if contentMode == .scaleAspectFill { 
       ratio = min(horizontalRatio, verticalRatio) 
      } else { 
       ratio = max(horizontalRatio, verticalRatio) 
      } 

      let sizeForAspectScale = CGSize(width: size.width/ratio, height: size.height/ratio) 
      let image = filled(to: sizeForAspectScale) 
      if contentMode == .scaleAspectFill { 
       let subRect = CGRect(
        x: floor((sizeForAspectScale.width - newSize.width)/2.0), 
        y: floor((sizeForAspectScale.height - newSize.height)/2.0), 
        width: newSize.width, 
        height: newSize.height) 
       return image?.cropped(to: subRect) 
      } 
      return image 
     } 
     return nil 
    } 

    /// Resize the image to be the required size, stretching it as needed. 
    /// 
    /// - parameter newSize: The new size of the image. 
    /// 
    /// - returns:    Resized `UIImage` of resized image. 

    func filled(to newSize: CGSize) -> UIImage? { 
     UIGraphicsBeginImageContextWithOptions(newSize, false, scale) 
     draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) 
     let image = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 

     return image 
    } 

    /// Crop the image to be the required size. 
    /// 
    /// - parameter bounds: The bounds to which the new image should be cropped. 
    /// 
    /// - returns:    Cropped `UIImage`. 

    func cropped(to bounds: CGRect) -> UIImage? { 
     var rect = bounds 
     rect.size.width *= scale 
     rect.size.height *= scale 

     if let imageRef = cgImage?.cropping(to: rect) { 
      return UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation) 
     } else { 
      return nil 
     } 
    } 

    /// Resize the image to fill the rectange of the specified size, preserving the aspect ratio, trimming if needed. 
    /// 
    /// - parameter newSize: The new size of the image. 
    /// 
    /// - returns:    Return `UIImage` of resized image. 

    func scaledAspectFill(to newSize: CGSize) -> UIImage? { 
     return scaled(to: newSize, contentMode: .scaleAspectFill); 
    } 

    /// Resize the image to fit within the required size, preserving the aspect ratio, with no trimming taking place. 
    /// 
    /// - parameter newSize: The new size of the image. 
    /// 
    /// - returns:    Return `UIImage` of resized image. 

    func scaledAspectFit(to newSize: CGSize) -> UIImage? { 
     return scaled(to: newSize, contentMode: .scaleAspectFit) 
    } 

} 

這種 「調整圖像大小」 的方法還有另外一個優點。小圖像視圖中的大圖像仍然需要大量內存。但是,如果將圖像大小調整爲適合圖像視圖的大小,則可避免浪費內存。

+0

這是一種魅力。謝謝@Rob! – pyriku