【发布时间】:2026-01-16 19:15:02
【问题描述】:
背景
我需要一个方形图像来填充表格单元格,边距很小,并让它在所有设备上工作。
我用于处理不同设备的方法是根据设备以编程方式设置表中的行高,并使用 AspectFit 使图像填充行——当我知道要设置什么值时,这很有效行高到。只需要猜测几次即可。
问题
图像在模拟器中的显示方式与在真实设备上的显示方式不同,因此无法在模拟器上进行测试,需要确定真实设备。
这是图像和模拟器的已知问题吗?是否有一些我缺少的解决方法或设置?
我想让模拟器演示与设备演示的图像相匹配,这样我就可以在不访问大量物理设备的情况下进行有效测试。
提前致谢。
参考图片
第一张图片来自 iPhone 6 模拟器。第二个(正确的)来自真正的 iPhone 6 设备。您不会从模拟器中猜测图像在实际设备上是正确的。
我们在其他模拟器上也看到过这个问题,例如 iPhone 7 模拟器和 iPhone SE 模拟器,所以我们认为这是所有模拟器的问题。
此控制器的源代码
import UIKit
import AVFoundation
import GRDB
import SwiftPhotoGallery
class SpeciesDescriptionController: UITableViewController, SwiftPhotoGalleryDataSource, SwiftPhotoGalleryDelegate {
let tableCell = "TableCell"
var target_id : Int64 = 0
var item_scanned : Bool = false
let scanned = Scanned()
var species_array = [Species]()
var species : Species!
var primary_image : Image!
var image_names = [String]()
let favorites = Favorites()
@IBAction func toggle_favorites(_ sender: Any) {
if (favorites.check(species_id: species.id!) == true) {
favorites.remove(species_id: species.id!)
} else {
favorites.add(content_id: species.id!, table_name: "Species", display_name: species.display_name)
}
set_favorites_status()
}
@IBOutlet weak var favorites_status: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
loadSpeciesDescription()
loadPrimaryImage()
setTitle()
formatTable()
set_favorites_status()
if item_scanned == true {
scanned.add(content_id: species.id!, table_name: "Species", display_name: species.display_name)
}
let modelName = UIDevice.current.modelName
print("\n\nThe model name is: \(modelName)\n\n")
}
private func set_favorites_status() {
if (favorites.check(species_id: species.id!) == true) {
favorites_status.image = UIImage(named: "glyphicons-50-star")
} else {
favorites_status.image = UIImage(named: "glyphicons-49-star-empty")
}
}
private func loadSpeciesDescription() {
species = try! dbQueue.inDatabase { db in
try Species.fetchOne(db, key: target_id)
}
}
private func loadPrimaryImage() {
let visibleIdColumn = Column("visible_id")
let visibleTypeColumn = Column("visible_type")
let primaryPhotoColumn = Column("primary_photo")
let request = Image.filter(visibleIdColumn == species.id )
.filter(visibleTypeColumn == "Species")
.filter(primaryPhotoColumn == "t")
primary_image = try! dbQueue.inDatabase { db in
try request.fetchOne(db)
}
}
func formatTable() {
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.tableFooterView = UIView(frame: CGRect.zero) // deny empty table rows
}
func setTitle() {
self.title = species.display_name
}
func species_names() -> String {
var all_names: String = ""
let scientific_names = "Scientific: \(species.scientific_name)\n"
let common_names = "Common: \(species.common_name)"
let other_names = "\nNoongar: \(species.other_names)"
all_names = scientific_names + common_names
if (other_names != "\nNoongar: ") {
all_names = all_names + other_names
}
return all_names
}
/////////////////// Table //////////////////////////////
override func numberOfSections(in tableView: UITableView) -> Int {
return 6
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var title : String = ""
switch section {
case 0 : title = " " // must have blank to print the blank section header
case 1 : title = "Names"
case 2 : title = "Audio"
case 3 : title = "Identification"
case 4 : title = "Description"
case 5 : title = "Range"
default: title = "Not defined..."
}
return title
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if indexPath.section == 0 {
return CGFloat(row_height_for_device())
} else {
return UITableViewAutomaticDimension
}
}
func row_height_for_device() -> Int {
switch UIDevice.current.modelName {
case "iPhone SE" :
return 290 //confirmed to work with SE
case "iPhone 6", "iPhone 6s" :
return 290 // confirmed to work with 6
case "iPhone 7" :
return 348 //
case "iPhone 8" :
return 348 //
case "iPhone 6 Plus", "iPhone 6s Plus","iPhone 7 Plus", "iPhone 8 Plus" :
return 380
case "iPhone X" :
return 400
default:
// handles 2G, 3G, 3GS, 4, 4s, 5, 5s, 5c, SE
// confirmed to work with SE
return 290
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: tableCell) as UITableViewCell?
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: tableCell)
}
cell!.imageView?.image = nil
cell!.imageView?.contentMode = .scaleAspectFit
cell!.textLabel?.text = nil
cell!.textLabel?.numberOfLines = 0
cell!.textLabel?.lineBreakMode = .byWordWrapping
cell!.textLabel?.font = UIFont.systemFont(ofSize: 16)
switch indexPath.section {
case 0 :
let image_file_name = "primary_\(primary_image.image_file_name)"
print("The image the app is looking for is called: \(image_file_name)")
cell!.imageView?.image = UIImage(named: image_file_name)
case 1 : cell!.textLabel?.text = species_names()
case 2 :
cell!.imageView?.image = UIImage(named: "glyphicons-169-ear-plugs")
cell!.textLabel?.text = "1 Minute Audio Summary"
case 3 : cell!.textLabel?.text = species.identification
case 4 : cell!.textLabel?.text = species.description
case 5 : cell!.textLabel?.text = species.range
default : cell!.textLabel?.text = ""
}
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 2 {
textToSpeech(audio_summary: species.audio_summary)
}
if indexPath.section == 0 {
show_gallery(species_id: species.id!)
}
}
func standard_alert(_ alertTitle: String, alertMessage: String) -> Void {
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Ok"), style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func bail_out() {
performSegue(withIdentifier: "no_content", sender: nil)
}
func textToSpeech(audio_summary : String)
{
let synth = AVSpeechSynthesizer()
var myUtterance = AVSpeechUtterance(string: "")
myUtterance = AVSpeechUtterance(string: audio_summary)
myUtterance.voice = AVSpeechSynthesisVoice(language: "en-AU")
synth.speak(myUtterance)
}
///////////
func show_gallery(species_id: Int64) {
// load_image_names(species_id: species_id)
let image_file_name = "large_primary_" + primary_image.image_file_name
image_names = [image_file_name] // array of one item for now
let gallery = SwiftPhotoGallery(delegate: self, dataSource: self)
gallery.backgroundColor = UIColor.black
gallery.pageIndicatorTintColor = UIColor.gray.withAlphaComponent(0.5)
gallery.currentPageIndicatorTintColor = UIColor.white
gallery.hidePageControl = true
present(gallery, animated: true, completion: nil)
}
// MARK: SwiftPhotoGalleryDataSource Methods
func numberOfImagesInGallery(gallery: SwiftPhotoGallery) -> Int {
return image_names.count
}
func imageInGallery(gallery: SwiftPhotoGallery, forIndex: Int) -> UIImage? {
return UIImage(named: image_names[forIndex])
}
// MARK: SwiftPhotoGalleryDelegate Methods
func galleryDidTapToClose(gallery: SwiftPhotoGallery) {
dismiss(animated: true, completion: nil)
}
} // class
【问题讨论】:
-
这与“模拟器和设备”的区别无关。问题是您使用的模拟器与您的设备不同。您的所有图片都是相同大小还是不同大小?
-
模拟器匹配设备:iPhone 6模拟器。 iPhone 6 设备。我仔细检查了一遍。图片被裁剪成相同的大小和形状(正方形和 480x480)。
-
嗯...奇怪的事情正在发生。如您所见,忽略图像,即使标签中的 text 布局也不同 - “Common:...”行环绕在设备图像上,而不是在模拟器图像上。你有一些正在调整的代码吗?或者这一切都是通过自动布局和约束完成的?
-
我添加了控制器的完整源代码。注意:我简单地注释掉了设备模型逻辑,无论如何都返回了 290。问题继续存在——它在 iPhone 6 实际设备上看起来是正确的,但在模拟器中却不是。 (我这样做是为了确保模拟器获得与设备相同的值。然后我将源代码返回到您现在看到的版本。
-
我认为您可能正在尝试解决错误的问题...但是,首先,您可以发布您的模拟器的不同屏幕截图吗?您的模拟器图像是
606 x 1079,您的设备图像是640 x 1136...运行模拟器时,您应该能够选择Window -> Pixel Accurate,然后您可以将屏幕截图保存为相同的尺寸...使它更容易比较两者。
标签: ios xcode ios-simulator