为什么uibutton的outlet是weak以及tag的注意事项

本文解析了IBOutlet属性为何通常被定义为weak的原因,探讨了其在视图控制器与视图之间的引用关系,以及如何正确处理控件与视图控制器之间的交互。
  • 为什么IBOutlet属性是weak的?
    因为当我们将控件拖到Storyboard上,相当于新创建了一个对象,而这个对象是加到视图控制器的view上,view有一个subViews属性,这个属性是一个数组,里面是这个view的所有子view,而我们加的控件就位于这个数组中,那么说明,实际上我们的控件对象是属于view的,也就是说view对加到它上面的控件是强引用。当我们使用Outlet属性的时候,我们是在viewController里面使用,而这个Outlet属性是有view来进行强引用的,我们在viewController里面仅仅是对其使用,并没有必要拥有它,所以是weak的。
    如果将weak改为strong,也是没有问题的,并不会造成强引用循环。当viewController的指针指向其他对象或者为nil,这个viewController销毁,那么对控件就少了一个强引用指针。然后它的view也随之销毁,那么subViews也不存在了,那么控件就又少了一个强引用指针,如果没有其他强引用,那么这个控件也会随之销毁。
    不过,既然没有必将Outlet属性设置为strong,那么用weak就好了: ]
  • 一个控件可以在viewController里面有多个Outlet属性,就相当于一个对象,可以有多个指针指向它(多个引用)。
    但是一个Outlet属性只能对应一个控件,也就是说,如果有button1button2button1viewController里面有一个名为buttonOutlet属性,此时button指向button1,但是如果用button2button重新赋值,那么此时button指向button2。也就是说,后来的覆盖原来的。
  • 一个控件可以在viewController里面触发多个IBAction。比如有一个button控件,在viewController里面有几个方法,那么点击button,会触发所有的这些方法。
    如果我有多个控件,比如button1,button2,button3,它们也可以同时绑定一个buttonClick方法,无论点击button1,button2还是button3,都会触发这个buttonClick方法。
  • 上面说了,button1,button2,button3有可能都触发buttonClick方法,如果想在buttonClick方法里面区分到底是哪个button触发的可能有好几种做法。
  1. 可以给这三个button各设置一个Outlet属性,然后在buttonClick里面判断sender和哪个Outlet属性是同一对象,这样就可以区分了。但是很明显,这样并不合理,因为创建的三个属性有些浪费。
  2. 我们可以给三个button各加一个tag,在buttonClick里面通过switch(或者if...)判断,sendertag和给各个button加上的tag是否一致,如果一致则为同一对象。
要慎用tag。因为view有一个viewWithTag:方法,可以在view的子view里面找到和我们传入的tag相同的view,这样哪怕不给这个控件创建Outlet属性,也可以通过tag找到这个对象。但是很明显,这个方法要遍历子view,比较每个子viewtag,这样效率并不高,所以尽量要避免这种情况。
请依照上面的xib文件全部检查// // NewCoverImageContainerView.swift // SurveillanceHome // // Created by MaCong on 2025/12/8. // Copyright © 2025 tplink. All rights reserved. // import UIKit import SnapKit class NewCoverImageContainerView: UIView { // MARK: - IBOutlets (now created in code) var coverImageView: UIImageView! var maskImageView: UIImageView! var maskLabel: UILabel! var helpButton: UIButton? var helpLabel: UILabel! var labelToCenterConstraint: NSLayoutConstraint? // Constraints (optional outlets) @IBOutlet weak var coverBGTrailConst: NSLayoutConstraint? @IBOutlet weak var coverBGLeadingConst: NSLayoutConstraint? @IBOutlet weak var coverTrailConst: NSLayoutConstraint? @IBOutlet weak var coverLeadingConst: NSLayoutConstraint? // Private properties private var statusImageViews = [UIImageView]() private var isCollected: Bool = false { didSet { let image = isCollected ? TPImageLiteral("device_have_collect_card") : TPImageLiteral("device_not_collect_card") collectButton.setImage(image, for: .normal) } } private lazy var collectButton: UIButton = { let view = UIButton() view.setImage(TPImageLiteral("device_not_collect_card"), for: .normal) view.addTarget(self, action: #selector(collectButtonClicked), for: .touchUpInside) return view }() var collectAction: ((Bool) -> Void)? var helpAction: (() -> Void)? /* 云存储、WiFi状态、报警状态 */ //首页隐藏图标 private let numberOfStatusImages = 0 private let needHideMask: Int = 1 // MARK: - Initializers override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { setupViews() setupConstraints() awakeFromNib() } // MARK: - Setup Views private func setupViews() { // Create subviews coverImageView = UIImageView() coverImageView.contentMode = .scaleToFill coverImageView.clipsToBounds = true coverImageView.isUserInteractionEnabled = false maskImageView = UIImageView() maskImageView.contentMode = .scaleToFill maskImageView.clipsToBounds = true maskImageView.isUserInteractionEnabled = false maskImageView.tag = 3 maskLabel = UILabel() maskLabel.tag = 4 maskLabel.text = "无设备" maskLabel.font = UIFont(name: "PingFangSC-Regular", size: 12) maskLabel.textColor = UIColor(white: 1.0, alpha: 1.0) maskLabel.textAlignment = .center maskLabel.backgroundColor = .clear maskLabel.adjustsFontSizeToFitWidth = false maskLabel.baselineAdjustment = .alignBaselines maskLabel.numberOfLines = 1 helpButton = UIButton(type: .system) helpButton?.setTitle(LocalizedString(key: deviceListHelp), for: .normal) helpButton?.titleLabel?.font = UIFont.systemFont(ofSize: 10) helpButton?.setTitleColor(.tpbTextPrimary, for: .normal) helpButton?.layer.borderWidth = 1 helpButton?.layer.borderColor = UIColor.tpbTextDisabled.cgColor helpButton?.addTarget(self, action: #selector(helpButtonClicked), for: .touchUpInside) helpLabel = UILabel() helpLabel.text = LocalizedString(key: deviceListHelp) helpLabel.font = UIFont.systemFont(ofSize: 10) helpLabel.textColor = .tpbTextSecondary helpLabel.textAlignment = .right backgroundColor = UIColor(white: 0.0, alpha: 0.0) layer.cornerRadius = 2 layer.masksToBounds = true addSubview(coverImageView) addSubview(maskImageView) addSubview(maskLabel) addSubview(collectButton) if let hb = helpButton, let hl = helpLabel { addSubview(hb) addSubview(hl) } } // MARK: - Setup Constraints with SnapKit private func setupConstraints() { coverImageView.snp.makeConstraints { make in make.edges.equalToSuperview() } maskImageView.snp.makeConstraints { make in make.edges.equalToSuperview() } maskLabel.snp.makeConstraints { make in make.leading.trailing.equalToSuperview() make.centerY.equalToSuperview() make.height.equalTo(17) } collectButton.snp.makeConstraints { make in make.top.equalToSuperview().offset(8) make.trailing.equalToSuperview().offset(-8) make.width.height.equalTo(26) } helpButton?.snp.makeConstraints { make in make.centerY.equalTo(helpLabel!) make.trailing.equalToSuperview().offset(-8) make.width.greaterThanOrEqualTo(30) } helpLabel?.snp.makeConstraints { make in make.centerY.equalTo(maskLabel!) make.trailing.equalTo(helpButton!.snp.leading).offset(-4) make.trailing.lessThanOrEqualToSuperview().offset(-8) self.labelToCenterConstraint = make.centerX.equalToSuperview().constraint } // Initialize optional constraints as zero constants coverBGTrailConst = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0) coverBGLeadingConst = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0) coverTrailConst = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0) coverLeadingConst = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0) } // MARK: - awakeFromNib模拟 override func awakeFromNib() { super.awakeFromNib() #if MERCURY_SURVEILLANCE layer.cornerRadius = 0 #endif helpButton?.layer.borderWidth = 1 helpButton?.layer.borderColor = UIColor.tpbTextDisabled.cgColor helpButton?.addTarget(self, action: #selector(helpButtonClicked), for: .touchUpInside) let isBigImage = bounds.height > 80 for i in 0..<numberOfStatusImages { let imageView = UIImageView() let interval: CGFloat = 16 + (isBigImage ? 2 : 0) let minX: CGFloat = TPLocalizationUtils.isRTL() ? CGFloat(i) * interval + 2 : bounds.maxX - CGFloat(i + 1) * interval - 2 let minY: CGFloat = isBigImage ? 2 : 0 let rect = CGRect(x: minX, y: minY, width: 16, height: 16) imageView.frame = rect addSubview(imageView) imageView.isHidden = true imageView.autoresizingMask = [TPLocalizationUtils.isRTL() ? .flexibleRightMargin : .flexibleLeftMargin, .flexibleBottomMargin] statusImageViews.append(imageView) statusImageViews.forEach { $0.isHidden = true } } self.addSubview(collectButton) collectButton.isHidden = true } // MARK: - Actions @objc private func collectButtonClicked() { collectAction?(!isCollected) } @objc private func helpButtonClicked() { helpAction?() } // MARK: - Public Methods (完全复制原逻辑) func shouldShowCollectButton(device: TPSSDeviceForDeviceList, channel: TPSSChannelInfo? = nil, isCard: Bool) { let isVms = TPAppContextFactory.shared().isVmsLogin collectButton.isHidden = (device.displayType == .solar || device.listType == .local || !isCard || (TPSSAppContext.shared.loginType == .personal ? false : TPSSAppContext.shared.isVmsDeviceListFavoriteOldVersion)) ? true : false if device.deviceType == .IPC { isCollected = isVms ? device.isVMSFavorited : device.isCollected } else if device.deviceType == .NVR { if channel != nil { isCollected = isVms ? channel!.isVMSFavorited : device.isCollected && device.collectChannels.contains(channel!.channelId as NSNumber) } else { isCollected = isVms ? device.isVMSFavorited : device.isCollected } } } func configureCoverWith(size: TPSSDeviceForDeviceList.CoverImageSize, device: TPSSDeviceForDeviceList, channel: TPSSChannelInfo? = nil, hideMaskIfNeeded: Bool = false, isCard: Bool = false, folded: Bool = false, leadingConst: NSLayoutConstraint? = nil, trailConst: NSLayoutConstraint? = nil, isSmall: Bool = false, isModelCover: Bool = false, noDevice: Bool = false, isHideLogo: Bool = false) { var noDevices = true if((channel) != nil){ noDevices = !device.activeChannelsInfo.contains(channel!) } shouldShowCollectButton(device: device, channel: channel, isCard: isCard) var coverImage:UIImage? = device.displayType == .solar ? TPSSDeviceForDeviceList.defaultSolarCoverImage(of: size) : TPSSDeviceForDeviceList.defaultCoverImage(of: size) if isModelCover { coverImage = TPSSDeviceForDeviceList.getDeviceModelImage(type: .IPC, model: noDevice ? "" : channel?.deviceModel ?? "") } if(!noDevices){ coverImage = device.coverImage(of: size, channelID: channel?.channelId.intValue ?? -1, listType: device.listType) } if hideMaskIfNeeded && !maskImageView.isHidden { maskImageView.isHidden = maskImageView.tag == needHideMask && coverImage != nil } coverImageView.image = coverImage ?? (device.displayType == .solar ? TPSSDeviceForDeviceList.defaultSolarCoverImage(of: size) : (isModelCover ? TPSSDeviceForDeviceList.getDeviceModelImage(type: .IPC, model: noDevice ? "" : channel?.deviceModel ?? "") : TPSSDeviceForDeviceList.defaultCoverImage(of: size))) var isFisheye = false if TPSSAppContext.shared.isVmsLogin && device.listType == .remote { isFisheye = coverImage != nil && device.coverImageIsFisheye(of: size, channelID: channel?.channelId.intValue ?? -1, listType: device.listType) } if (!isFisheye) { if let channelInfo = channel, device.displayType == .NVR { isFisheye = coverImage != nil && channelInfo.supportsFisheye } else { isFisheye = coverImage != nil && device.supportFishEye } } var isPano = false if let channelInfo = channel, device.displayType == .NVR { isPano = coverImage != nil && channelInfo.isSupportSplicingSetting } else { isPano = coverImage != nil && device.supportPano } let imageWidth = coverImage?.size.width ?? 1 let imageHeight = coverImage?.size.height ?? 1 if (!isFisheye && imageWidth > 1.1 && abs(imageWidth - imageHeight) < 1) { isFisheye = true; } coverImageView.contentMode = isFisheye ? isCard ? .scaleAspectFit : .scaleAspectFill : .scaleToFill isPano = ( isPano || (imageWidth / imageHeight) >= 3) backgroundColor = isFisheye ? .tpbFisheyeBackground : .clear if (device.displayType != .solar) { let oldImg = coverImageView.image; let newImg = cropFishScaleImg(img: oldImg, isFishEye: isFisheye); if (oldImg != newImg) { coverImageView.image = newImg; coverImageView.contentMode = isCard ? .scaleAspectFit : .scaleAspectFill backgroundColor = .tpbFisheyeBackground } if (isPano) { coverImageView.contentMode = .scaleAspectFill backgroundColor = .clear } if (isCard && (isFisheye || oldImg != newImg) && (!folded || device.deviceType == .IPC)) { coverImageView.contentMode = .scaleAspectFit; } } let block = {(constant:CGFloat) in self.coverBGTrailConst?.constant = constant; self.coverBGLeadingConst?.constant = constant; self.coverTrailConst?.constant = constant; self.coverLeadingConst?.constant = constant; leadingConst?.constant = constant; trailConst?.constant = constant; } block(0); if device.displayType == .solar { coverImageView.contentMode = .scaleAspectFit coverImageView.backgroundColor = .tpbBackground } if isModelCover && (noDevice || coverImage == nil) { coverImageView.contentMode = .scaleAspectFit coverImageView.backgroundColor = .tpbBackground } if isHideLogo && coverImage == nil { coverImageView.isHidden = true } else { coverImageView.isHidden = false } guard let imgSize = coverImageView.image?.size, !isFisheye, imgSize.height > imgSize.width else { return } backgroundColor = .tpbFisheyeBackground coverImageView.contentMode = .scaleAspectFill; var hMargin : CGFloat = 10; if (isCard) { if ((!folded) || device.displayType == .IPC) { hMargin = 70; } else { hMargin = 30; } } else { if (isSmall) { hMargin = 10; } else { hMargin = 20; } } block(hMargin); } func configureWith(cloudStorageEnabled: Bool = false, supportsAlarm: Bool = false, alarm: Bool = true, noDevice: Bool = false, channelOffline: Bool = false, channelHidden: Bool = false, channelUnAuth: Bool = false, channelUninitialized: Bool = false, offline: Bool = false, nvrOffline: Bool = false, ipcOffline: Bool = false, offlineTime: String = "", notInSharePeriod: Bool = false, notShareEnable: Bool = false, notConnected: Bool = false, supportConnectionInfo: Bool = false, connectedViaWifi: Bool = false, wifiRssi: Int = 0, showHelp: Bool = false, playButtonHidden: Bool = false, size: TPSSDeviceForDeviceList.CoverImageSize, showText: Bool = true, showIcons: Bool = true, hasNoVmsLicense: Bool = false, isChannel: Bool = false) { let showAlarm = supportsAlarm && !noDevice let showWifiStatus = supportConnectionInfo && connectedViaWifi && !(offline || nvrOffline || ipcOffline) let showCloudStorage = cloudStorageEnabled let images: [UIImage] = [showAlarm ? (alarm ? TPImageLiteral("devicelist_indicator_alarm_on") : TPImageLiteral("devicelist_indicator_alarm_off")) : nil, showWifiStatus ? UIImage(named: "common_wifi_indicator\(wifiRssi)") : nil, showCloudStorage ? TPImageLiteral("cloud_label") : nil].compactMap {$0} for i in 0..<statusImageViews.count { if i >= images.count { statusImageViews[i].isHidden = true } else { statusImageViews[i].isHidden = !showIcons statusImageViews[i].image = images[i] } } let deviceOffline = offline || nvrOffline || ipcOffline || channelOffline if noDevice || deviceOffline || notInSharePeriod || notShareEnable || notConnected || channelHidden || hasNoVmsLicense { maskImageView.isHidden = false maskLabel.isHidden = false maskImageView.image = nil maskImageView.backgroundColor = .tpbDeviceMask maskImageView.contentMode = .scaleAspectFit } maskLabel.numberOfLines = 3 maskImageView.tag = 0 if deviceOffline { if isChannel && noDevice { maskLabel.text = LocalizedString(key: deviceListNoSuchDevice) } else if isChannel && channelUnAuth { maskLabel.text = LocalizedString(key: NVRAddIPCDeviceNotCertified) } else if isChannel && channelUninitialized { maskLabel.text = LocalizedString(key: multiWindowPlayerUninitialized) } else { let basicText = notInSharePeriod ? LocalizedString(key: deviceListNotInSharePeriod) : LocalizedString(key: deviceListDeviceNotOnline) if !offlineTime.isEmpty { maskLabel.numberOfLines = 0 let firstLine = basicText let secondLine = String(format: LocalizedString(key: deviceListOfflineTimeFormat), offlineTime) let text = NSMutableAttributedString(string: "\(firstLine)\n\(secondLine)") text.addAttributes([NSAttributedString.Key.font: UIFont.projectFont(ofSize: 12)], range: NSMakeRange(0, firstLine.count)) let style = NSMutableParagraphStyle() style.lineSpacing = 8 style.alignment = .center text.addAttributes([NSAttributedString.Key.paragraphStyle: style], range: NSMakeRange(0, text.length)) text.addAttributes([NSAttributedString.Key.font: UIFont.projectFont(ofSize: 10)], range: NSMakeRange(firstLine.count + 1, secondLine.count)) maskLabel.attributedText = text } else { maskLabel.text = basicText } } } else if noDevice { maskLabel.text = LocalizedString(key: deviceListNoSuchDevice) } else if notShareEnable { maskLabel.text = LocalizedString(key: deviceListNotShareEnable) } else if notInSharePeriod && !deviceOffline { maskLabel.text = LocalizedString(key: deviceListNotInSharePeriod) } else if channelUnAuth { maskLabel.text = LocalizedString(key: NVRAddIPCDeviceNotCertified) } else if channelHidden { maskLabel.text = LocalizedString(key: deviceListChannelHidden) } else if notConnected { maskLabel.text = LocalizedString(key: wirelessDirectNotConnected) } else if hasNoVmsLicense { maskLabel.text = LocalizedString(key: deviceListCloudVmsWithoutLicenseMaskLabel) } else { maskImageView.isHidden = playButtonHidden maskLabel.isHidden = true switch size { case .small: maskImageView.image = TPImageLiteral("devicelist_preview_small") maskImageView.contentMode = .scaleAspectFit case .medium: maskImageView.image = TPImageLiteral("devicelist_preview_medium") maskImageView.contentMode = .center default: maskImageView.image = TPImageLiteral("devicelist_preview_large") maskImageView.contentMode = .center } maskImageView.backgroundColor = .clear maskImageView.tag = needHideMask } if !showText { maskLabel.text = "" } if helpButton != nil { if showHelp { helpButton?.isHidden = false helpLabel.isHidden = false labelToCenterConstraint?.constant = -22 } else { helpButton?.isHidden = true helpLabel.isHidden = true labelToCenterConstraint?.constant = 0 } } } } // MARK: - Extension: configure overloads (保持原样) extension NewCoverImageContainerView { enum CoverType { case play case selection } func configure(ipc: TPSSDeviceForDeviceList, size: TPSSDeviceForDeviceList.CoverImageSize = .medium, type: CoverType = .play, isCard:Bool = false, folded:Bool=false) { shouldShowCollectButton(device: ipc, isCard: isCard) let showAccessory = size != .small let showDetailText = showAccessory && size != .medium let showPlayButton = (ipc.displayType != .solar && type == .play) if ipc.listType == .remote { configureWith(cloudStorageEnabled: ipc.cloudStorageService()?.serviceState.isValid ?? false, supportsAlarm: ipc.supportMessage && ipc.displayOnline && !ipc.isSharedDevice, alarm: ipc.messageEnable, ipcOffline: !ipc.displayOnline, offlineTime: showDetailText ? ipc.offlineTime : "", notInSharePeriod: (ipc.isSharedDevice && !ipc.isInSharePeriod), notShareEnable: (ipc.isSharedDevice && !ipc.isShareEnable), supportConnectionInfo: ipc.supportConnectInfo, connectedViaWifi: ipc.linkType == .wifi, wifiRssi: ipc.linkRssi, showHelp: showAccessory && !ipc.displayOnline && !ipc.isSharedDevice, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showAccessory, hasNoVmsLicense: ipc.isLicenseNotActive) } else { configureWith(ipcOffline: !ipc.displayOnline, offlineTime: showDetailText ? ipc.offlineTime : "", supportConnectionInfo: ipc.supportConnectInfo, connectedViaWifi: ipc.linkType == .wifi, wifiRssi: ipc.linkRssi, showHelp: showAccessory && !ipc.displayOnline && !ipc.isSharedDevice, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showAccessory) } configureCoverWith(size: size, device: ipc, channel: ipc.channelsInfo.first, hideMaskIfNeeded: true, isCard: isCard, folded:folded) statusImageViews.forEach { $0.isHidden = true } } func configure(channel: TPSSChannelInfo, nvr: TPSSDeviceForDeviceList, size: TPSSDeviceForDeviceList.CoverImageSize = .medium, type: CoverType = .play, isCard:Bool = false, folded:Bool = false, leadingConst:NSLayoutConstraint? = nil, trialConst:NSLayoutConstraint? = nil, isSmall:Bool=false, isSigleChannel:Bool = false, isHideLogo : Bool = false) { let showAccessory = size != .small let showPlayButton = type == .play && !isSigleChannel shouldShowCollectButton(device: nvr, channel: channel, isCard: isCard) if nvr.listType == .remote { configureWith(cloudStorageEnabled: nvr.cloudStorageService(channel: channel)?.serviceState.isValid ?? false, supportsAlarm: channel.supportsMessagePush && channel.online && !nvr.isSharedDevice, alarm: channel.messageEnable, noDevice: !nvr.activeChannelsInfo.contains(channel), channelOffline: !channel.online, channelUnAuth: channel.authResult == 1, channelUninitialized: channel.authResult == 3, notInSharePeriod: (nvr.isSharedDevice && !channel.isInSharePeriod), notShareEnable: (nvr.isSharedDevice && !channel.isShareEnable), showHelp: !channel.online && channel.authResult == 0 && channel.active, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showIcons, hasNoVmsLicense: channel.isLicenseNotActive, isChannel: true) } else { configureWith(noDevice: !nvr.activeChannelsInfo.contains(channel), channelOffline: !channel.online, channelUnAuth: channel.authResult == 1, channelUninitialized: channel.authResult == 3, showHelp: !channel.online && channel.authResult == 0, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showIcons, isChannel: true) } configureCoverWith(size: size, device: nvr, channel: channel, hideMaskIfNeeded: true, isCard:isCard, folded: folded, leadingConst: leadingConst, trailConst: trialConst, isSmall: isSmall, isHideLogo: !isCard && isHideLogo) statusImageViews.forEach { $0.isHidden = true } } func configure(nvr: TPSSDeviceForDeviceList, size: TPSSDeviceForDeviceList.CoverImageSize = .medium, type: CoverType = .play) { let showAccessory = size != .small let showPlayButton = type == .play let showDetailText = showAccessory && size != .medium let channelHidden = nvr.channelsInfo.count == 0 && nvr.allChannelsInfo.count != 0 var noDevice = nvr.activeChannelsInfo.count == 0 && !channelHidden if nvr.isSharedFromOthers { for channel in nvr.activeChannelsInfo { if channel.isSharedFromOthers { noDevice = false break } else { noDevice = true } } } if nvr.listType == .remote { configureWith(noDevice: noDevice, channelHidden: channelHidden, nvrOffline: !nvr.displayOnline, offlineTime: showDetailText ? nvr.offlineTime : "", showHelp: showAccessory && !nvr.displayOnline && !nvr.isSharedDevice, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showIcons, hasNoVmsLicense: false) } else { configureWith(noDevice: noDevice, channelHidden: channelHidden, nvrOffline: !nvr.displayOnline, offlineTime: showDetailText ? nvr.offlineTime : "", showHelp: showAccessory && !nvr.displayOnline && !nvr.isSharedDevice, playButtonHidden: !showPlayButton, size: size, showText: showAccessory, showIcons: showIcons) } configureCoverWith(size: size, device: nvr, channel: nil, hideMaskIfNeeded: true) } func showEmpty(size: TPSSDeviceForDeviceList.CoverImageSize = .medium) { configureWith(playButtonHidden: true, size: size, showText: false, showIcons: false) coverImageView.image = TPSSDeviceForDeviceList.defaultCoverImage(of: size) coverLeadingConst?.constant = 0 coverTrailConst?.constant = 0 } } // MARK: - Device Setting Extension extension NewCoverImageContainerView { func configure(device: TPSSDeviceForSetting, channel: TPSSChannelInfo?, size: TPSSDeviceForDeviceList.CoverImageSize = .medium, model: String = "") { configureWith(playButtonHidden: true, size: size, showText: false, showIcons: false) let channelID = channel?.channelId.intValue ?? -1 let coverImage = device.coverImage(at: channelID, listType: device.deviceListType) coverImageView.image = coverImage ?? device.defaultCoverImage(at: channelID, size: size, model: model) var isFisheye = false if TPSSAppContext.shared.isVmsLogin && device.deviceListType == .remote { isFisheye = coverImage != nil && device.coverImageIsFisheye(at: channelID, listType: device.deviceListType) } else { if let channelInfo = channel { isFisheye = coverImage != nil && channelInfo.supportsFisheye } else { isFisheye = coverImage != nil && device.isFishEye } } if isFisheye { coverImageView.contentMode = .scaleAspectFill } else if device.deviceType == .solar || coverImage == nil { coverImageView.contentMode = .scaleAspectFit coverImageView.backgroundColor = .tpbProgressBackground coverImageView.layer.cornerRadius = 8 } else { var CorridorContentMode = UIView.ContentMode.scaleAspectFit if let img = coverImage { CorridorContentMode = img.size.height > img.size.width ? .scaleAspectFit : .scaleAspectFill } if let channelInfo = channel { if channelInfo.supportCorridor { coverImageView.contentMode = CorridorContentMode coverImageView.backgroundColor = .tpbProgressBackground } else if channelInfo.isSupportSplicingSetting { coverImageView.contentMode = .scaleAspectFill } else { coverImageView.contentMode = .scaleToFill } } else if device.supportCorridor { coverImageView.contentMode = CorridorContentMode coverImageView.backgroundColor = .tpbProgressBackground } else if device.isSupportSplicingSetting { coverImageView.contentMode = .scaleAspectFill } else { coverImageView.contentMode = .scaleToFill } } backgroundColor = isFisheye ? .tpbFisheyeBackground : .clear } } // MARK: - Subclasses & Utilities class CoverImageBigContainerView: NewCoverImageContainerView { @IBOutlet weak var nvrChannelNameContainer: UIView! @IBOutlet weak var nvrChannelNameLabel: UILabel! } extension UIImage { class func pureColorImage(color: UIColor, size: CGSize) -> UIImage { let size = CGSize(width: size.width.rounded(.awayFromZero), height: size.height.rounded(.awayFromZero)).getNotZeroSize() UIGraphicsBeginImageContext(size) let context = UIGraphicsGetCurrentContext()! context.setFillColor(color.cgColor) context.fill(CGRect(origin: .zero, size: size)) let image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return image } } class ExtendedButton: UIButton { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let rect = bounds.insetBy(dx: -bounds.width / 2, dy: -bounds.height / 2) return rect.contains(point) } } 此外还有其他的报错,并且我要求不使用storyboard方式,要求全部使用纯代码实现,而且是使用snapkit布局
最新发布
12-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值