这是代码import UIKit
protocol CustomMenuItem {
}
protocol CustomMenuView: UIView {
associatedtype MenuItemView: CustomMenuItemView
var items: [MenuItemView.MenuItem] { get }
func itemClickCallback(index: Int)
}
protocol CustomMenuItemView: UIView {
associatedtype MenuItem: CustomMenuItem
init(item: MenuItem)
var action: (() -> Void)? { get set }
}
extension CustomMenuView {
func setup() {
backgroundColor = .tpbCard
let count = items.count
let container = UIView()
addSubview(container)
container.frame = bounds.inset(by: UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0))
container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
var previousView: UIView? = nil
var height: CGFloat = 0
for i in 0..<count {
let menuView = MenuItemView(item: items[i])
menuView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(menuView)
let cons1 = NSLayoutConstraint(item: menuView, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 0)
let cons2 = NSLayoutConstraint(item: menuView, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0)
let cons3: NSLayoutConstraint
if let prev = previousView {
cons3 = NSLayoutConstraint(item: menuView, attribute: .top, relatedBy: .equal, toItem: prev, attribute: .bottom, multiplier: 1, constant: 0)
} else {
cons3 = NSLayoutConstraint(item: menuView, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
}
menuView.action = { [weak self] in
self?.itemClickCallback(index: i)
}
NSLayoutConstraint.activate([cons1, cons2, cons3])
menuView.layoutIfNeeded()
height += menuView.frame.size.height
previousView = menuView
}
frame.size.height = 8 + height + 8
}
}
class AnyMenuItemView<MenuItem: CustomMenuItem>: TapGestureSwallowingControl, CustomMenuItemView {
var action: (() -> Void)?
let item: MenuItem
required init(item: MenuItem) {
self.item = item
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
backgroundColor = .tpbBackgroundInCard
return true
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
stopTracking(with: event)
}
override func cancelTracking(with event: UIEvent?) {
stopTracking(with: event)
}
private func stopTracking(with event: UIEvent?) {
backgroundColor = .tpbCard
if let loc = event?.touches(for: self)?.first?.location(in: self), bounds.contains(loc) {
action?()
}
}
}
class DeviceGroupMenuView: UIView, CustomMenuView {
typealias MenuItemView = DeviceGroupMenuItemView
enum Item: Int {
//Fix: 隐藏Home/Away Mode
// case alarmMode = 0
case viewMode = 0
case reorder
case search
}
//Fix: 隐藏Home/Away Mode
// let items: [DeviceGroupMenuItem] = [.alarmMode, .viewMode, .reorder, .search]
var items: [DeviceGroupMenuItem] = [.viewMode, .reorder, .search] {
didSet {
setup()
}
}
var action: ((Item) -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func itemClickCallback(index: Int) {
if items[index] == .viewMode {
action?(.viewMode)
} else if items[index] == .reorder {
action?(.reorder)
} else if items[index] == .search {
action?(.search)
}
}
}
class DeviceGroupMenuItem: NSObject, CustomMenuItem {
@objc dynamic var image: UIImage
@objc dynamic var title: String
@objc dynamic var subtitle: String?
@objc dynamic var enabled: Bool
init(image: UIImage, title: String, subtitle: String? = nil, enabled: Bool = true) {
self.image = image
self.title = title
self.subtitle = subtitle
self.enabled = enabled
super.init()
}
//Fix: 隐藏Home/Away Mode
// static let alarmMode: DeviceGroupMenuItem = DeviceGroupMenuItem(image: TPImageLiteral("devicelist_home_active").withRenderingMode(.alwaysOriginal), title: LocalizedString(key: deviceListModeHome), subtitle: LocalizedString(key: deviceListSwitchModeToOut))
static let viewMode: DeviceGroupMenuItem = DeviceGroupMenuItem(image: TPImageLiteral("deviceList_display_bigPic").withRenderingMode(.alwaysOriginal), title: LocalizedString(key: deviceListSwitchView), subtitle: "")
static let reorder: DeviceGroupMenuItem = DeviceGroupMenuItem(image: TPImageLiteral("devicelist_nvr_channel_reorder"), title: LocalizedString(key: deviceListReorder))
static let search: DeviceGroupMenuItem = DeviceGroupMenuItem(image: TPImageLiteral("devicelist_search"), title: LocalizedString(key: deviceListSearch))
}
class DeviceGroupMenuItemView: AnyMenuItemView<DeviceGroupMenuItem> {
var observers = [NSKeyValueObservation]()
required init(item: DeviceGroupMenuItem) {
super.init(item: item)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: 44)
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
observers = []
} else {
observers = [
item.observe(\.image, options: .initial) { [weak self] (object, _) in
self?.imageView.image = object.image
},
item.observe(\.title, options: .initial) { [weak self] (object, _) in
self?.titleLabel.text = object.title
},
item.observe(\.enabled, options: .initial) { [weak self] (object, _) in
self?.isEnabled = object.enabled
},
item.observe(\.subtitle, options: .initial) { [weak self] (object, _) in
self?.informationLabel.text = object.subtitle
}
]
}
}
private lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}()
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.textColor = UIColor.tpbTextPrimary
titleLabel.font = UIFont.projectFont(ofSize: 16)
titleLabel.textAlignment = .left
titleLabel.numberOfLines = 1
// titleLabel.lineBreakMode = .byWordWrapping
return titleLabel
}()
private lazy var informationLabel: UILabel = {
let label = UILabel(frame: .zero)
label.textColor = UIColor.tpbTextThirdContent
label.font = UIFont.projectFont(ofSize: 13)
label.textAlignment = .right
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
private func setup() {
backgroundColor = .tpbCard
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
let cons1 = NSLayoutConstraint(item: container, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 16)
let cons2 = NSLayoutConstraint(item: container, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let cons3 = NSLayoutConstraint(item: container, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: -16)
let cons4 = NSLayoutConstraint(item: container, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([cons1, cons2, cons3, cons4])
imageView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(imageView)
let imageViewCons1 = NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 4)
let imageViewCons2 = NSLayoutConstraint(item: imageView, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0)
let imageViewCons3 = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 24)
let imageViewCons4 = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 24)
NSLayoutConstraint.activate([imageViewCons1, imageViewCons2, imageViewCons3, imageViewCons4])
titleLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(titleLabel)
let titleLabelCons1 = NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .equal, toItem: imageView, attribute: .trailing, multiplier: 1, constant: 4)
let titleLabelCons2 = NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
let titleLabelCons3 = NSLayoutConstraint(item: titleLabel, attribute: .bottom, relatedBy: .equal, toItem: container, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([titleLabelCons1, titleLabelCons2, titleLabelCons3])
informationLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(informationLabel)
let informationLabelCons1 = NSLayoutConstraint(item: informationLabel, attribute: .leading, relatedBy: .equal, toItem: titleLabel, attribute: .trailing, multiplier: 1, constant: 5)
let informationLabelCons2 = NSLayoutConstraint(item: informationLabel, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
let informationLabelCons3 = NSLayoutConstraint(item: informationLabel, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0)
let informationLabelCons4 = NSLayoutConstraint(item: informationLabel, attribute: .bottom, relatedBy: .equal, toItem: container, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([informationLabelCons1, informationLabelCons2, informationLabelCons3, informationLabelCons4])
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
container.isUserInteractionEnabled = false
}
}
// MARK: GeneralMenuView
class GeneralMenuView: UIView, CustomMenuView {
typealias MenuItemView = GeneralMenuItemView
var items: [GeneralMenuItem] = [] {
didSet {
setup()
}
}
/// 点击后的动作
/// index: 第几个menuItem
var action: ((_ itemId: String) -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func itemClickCallback(index: Int) {
action?(items[safe: index]?.itemId ?? "")
}
}
class GeneralMenuItem: NSObject, CustomMenuItem {
var itemId: String
@objc dynamic var image: UIImage
@objc dynamic var title: String
@objc dynamic var subtitle: String?
@objc dynamic var enabled: Bool
init(itemId: String, image: UIImage, title: String, subtitle: String? = nil, enabled: Bool = true) {
self.itemId = itemId
self.image = image
self.title = title
self.subtitle = subtitle
self.enabled = enabled
super.init()
}
}
class GeneralMenuItemView: AnyMenuItemView<GeneralMenuItem> {
var observers = [NSKeyValueObservation]()
var informationLabelWidthConstraint: NSLayoutConstraint?
required init(item: GeneralMenuItem) {
super.init(item: item)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: 44)
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
observers = []
} else {
observers = [
item.observe(\.image, options: .initial) { [weak self] (object, _) in
self?.imageView.image = object.image
},
item.observe(\.title, options: .initial) { [weak self] (object, _) in
self?.titleLabel.text = object.title
},
item.observe(\.enabled, options: .initial) { [weak self] (object, _) in
self?.isEnabled = object.enabled
},
item.observe(\.subtitle, options: .initial) { [weak self] (object, _) in
if object.subtitle == nil || object.subtitle == "" {
self?.informationLabelWidthConstraint?.isActive = true
} else {
self?.informationLabelWidthConstraint?.isActive = false
self?.informationLabel.text = object.subtitle
}
}
]
}
}
private lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}()
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.textColor = UIColor.tpbTextPrimary
titleLabel.font = UIFont.projectFont(ofSize: 16)
titleLabel.textAlignment = .left
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
return titleLabel
}()
private lazy var informationLabel: UILabel = {
let label = UILabel(frame: .zero)
label.textColor = UIColor.tpbTextThirdContent
label.font = UIFont.projectFont(ofSize: 13)
label.textAlignment = .right
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
private func setup() {
backgroundColor = .tpbCard
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
let cons1 = NSLayoutConstraint(item: container, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 16)
let cons2 = NSLayoutConstraint(item: container, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let cons3 = NSLayoutConstraint(item: container, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: -16)
let cons4 = NSLayoutConstraint(item: container, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([cons1, cons2, cons3, cons4])
imageView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(imageView)
let imageViewCons1 = NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 4)
let imageViewCons2 = NSLayoutConstraint(item: imageView, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0)
let imageViewCons3 = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 24)
let imageViewCons4 = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 24)
NSLayoutConstraint.activate([imageViewCons1, imageViewCons2, imageViewCons3, imageViewCons4])
titleLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(titleLabel)
let titleLabelCons1 = NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .equal, toItem: imageView, attribute: .trailing, multiplier: 1, constant: 12)
let titleLabelCons2 = NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
let titleLabelCons3 = NSLayoutConstraint(item: titleLabel, attribute: .bottom, relatedBy: .equal, toItem: container, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([titleLabelCons1, titleLabelCons2, titleLabelCons3])
informationLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(informationLabel)
let informationLabelCons1 = NSLayoutConstraint(item: informationLabel, attribute: .leading, relatedBy: .equal, toItem: titleLabel, attribute: .trailing, multiplier: 1, constant: 5)
let informationLabelCons2 = NSLayoutConstraint(item: informationLabel, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
let informationLabelCons3 = NSLayoutConstraint(item: informationLabel, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0)
let informationLabelCons4 = NSLayoutConstraint(item: informationLabel, attribute: .bottom, relatedBy: .equal, toItem: container, attribute: .bottom, multiplier: 1, constant: 0)
informationLabelWidthConstraint = NSLayoutConstraint(item: informationLabel, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([informationLabelCons1, informationLabelCons2, informationLabelCons3, informationLabelCons4])
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
container.isUserInteractionEnabled = false
}
}
class DeviceListMenuView: UIView, CustomMenuView {
enum Item: Int {
case alarmMode = 0
//Fix: 隐藏云存储
// case cloudStorage
//Fix: 隐藏设备分享
// case share
case upgrade
// case reonboard
case unbind
case setting
case collect
}
typealias MenuItemView = DeviceListMenuItemView
let items: [DeviceListMenuItem] = DeviceListMenuItem.allItems
static var deviceChannel: (device: TPSSDeviceForDeviceList, channel: TPSSChannelInfo?)?
var action: ((Item, TPSSDeviceForDeviceList, TPSSChannelInfo?) -> Void)? = nil
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func itemClickCallback(index: Int) {
action?(Item(rawValue: index)!, DeviceListMenuView.deviceChannel!.device, DeviceListMenuView.deviceChannel!.channel)
}
}
class DeviceListMenuItem: NSObject, CustomMenuItem {
@objc dynamic var image: UIImage
@objc dynamic var title: String
@objc dynamic var subtitle: String?
@objc dynamic var enabled: Bool
@objc dynamic var hidden: Bool
@objc dynamic var subtitleTextColor: UIColor
@objc dynamic var subtitleBackgroundColor: UIColor
@objc dynamic var alpha: Float
init(image: UIImage, title: String, subtitle: String? = nil, enabled: Bool = true, hidden: Bool = false, subtitleTextColor: UIColor = .tpbTextPrimary, subtitleBackgroundColor: UIColor = .tpbCard, alpha: Float = 1) {
self.image = image
self.title = title
self.subtitle = subtitle
self.enabled = enabled
self.hidden = hidden
self.subtitleTextColor = subtitleTextColor
self.subtitleBackgroundColor = subtitleBackgroundColor
self.alpha = alpha
super.init()
}
static let alarmMode: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("devicelist_alarm_on").withRenderingMode(.alwaysOriginal), title: LocalizedString(key: deviceListEventAlarmOn))
//Fix: 隐藏云存储
// static let cloudStorage: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("cloud_service"), title: LocalizedString(key: deviceListCloudStorage), subtitle: LocalizedString(key: deviceListSwitchViewToList))
//Fix: 隐藏设备分享
// static let share: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("devicelist_share_nor"), title: LocalizedString(key: deviceListShare))
static let upgrade: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("devicelist_update_reddot_nor"), title: LocalizedString(key: deviceListUpgrade))
// static let reonboard: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("common_reonboarding_wifi"), title: LocalizedString(key: deviceListReonboarding))
static let setting: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("common_setting_nor"), title: LocalizedString(key: deviceListMoreSetting))
static let unbind: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("devicelist_unbind"), title: LocalizedString(key: deviceUnbindButtonTitle))
static let collect: DeviceListMenuItem = DeviceListMenuItem(image: TPImageLiteral("device_not_collect_list"), title: LocalizedString(key: deviceCollectFavorite))
//Fix: 隐藏云存储
//Fix: 隐藏设备分享
// static let allItems: [DeviceListMenuItem] = [.alarmMode, .cloudStorage, .share, .upgrade, .reonboard, .setting]
static let allItems: [DeviceListMenuItem] = [.alarmMode, .upgrade, unbind, .setting, .collect]
}
extension Array where Element == DeviceListMenuItem {
var preferredheight: CGFloat {
return CGFloat(filter {!$0.hidden}.count) * 44 + 16
}
}
class DeviceListMenuItemView: AnyMenuItemView<DeviceListMenuItem> {
var observers = [NSKeyValueObservation]()
required init(item: DeviceListMenuItem) {
super.init(item: item)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: item.hidden ? 0 : 44)
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
observers = []
} else {
observers = [
item.observe(\.image, options: .initial) { [weak self] (object, _) in
self?.imageView.image = object.image
},
item.observe(\.title, options: .initial) { [weak self] (object, _) in
self?.titleLabel.text = object.title
},
item.observe(\.enabled, options: .initial) { [weak self] (object, _) in
self?.isEnabled = object.enabled
},
item.observe(\.subtitle, options: .initial) { [weak self] (object, _) in
if let subtitle = object.subtitle {
self?.informationButton.isHidden = false
self?.informationLabel.text = subtitle
} else {
self?.informationButton.isHidden = true
self?.hasInformationLayout(false)
}
},
item.observe(\.subtitleTextColor, options: .initial) { [weak self] (object, _) in
self?.informationLabel.textColor = object.subtitleTextColor
},
item.observe(\.subtitleBackgroundColor, options: .initial) { [weak self] (object, _) in
self?.informationButton.backgroundColor = object.subtitleBackgroundColor
},
item.observe(\.hidden, options: .initial) { [weak self] (object, _) in
self?.isHidden = object.hidden
self?.invalidateIntrinsicContentSize()
},
item.observe(\.alpha, options: .initial) {
[weak self] (object, _) in
self?.alpha = CGFloat(object.alpha)
}
]
}
}
private lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}()
private lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.textColor = UIColor.tpbTextPrimary
titleLabel.font = UIFont.projectFont(ofSize: 16)
titleLabel.textAlignment = .left
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
return titleLabel
}()
private lazy var informationButton: UIButton = {
let btn = UIButton(type: .system)
btn.tintColor = .tpbTextPrimary
btn.backgroundColor = .tpbCard
btn.titleLabel?.font = UIFont.projectFont(ofSize: 13)
btn.layer.cornerRadius = 12
// btn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
NSLayoutConstraint(item: btn, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 24).isActive = true
return btn
}()
private lazy var informationLabel: UILabel = {
let informationLabel = UILabel()
informationLabel.textColor = UIColor.tpbTextPrimary
informationLabel.font = UIFont.projectFont(ofSize: 13)
informationLabel.textAlignment = .left
informationLabel.numberOfLines = 1
// informationLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
return informationLabel
}()
private func hasInformationLayout(_ hasInfo: Bool) {
let titleLabelCons4 = NSLayoutConstraint(item: titleLabel, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)
titleLabelCons4.isActive = !hasInfo
}
private func setup() {
backgroundColor = .tpbCard
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
let cons1 = NSLayoutConstraint(item: container, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 16)
let cons2 = NSLayoutConstraint(item: container, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let cons3 = NSLayoutConstraint(item: container, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: -22)
let cons4 = NSLayoutConstraint(item: container, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([cons1, cons2, cons3, cons4])
imageView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(imageView)
let imageViewCons1 = NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 4)
let imageViewCons2 = NSLayoutConstraint(item: imageView, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0)
let imageViewCons3 = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 24)
let imageViewCons4 = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 24)
NSLayoutConstraint.activate([imageViewCons1, imageViewCons2, imageViewCons3, imageViewCons4])
titleLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(titleLabel)
let titleLabelCons1 = NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .equal, toItem: imageView, attribute: .trailing, multiplier: 1, constant: 4)
let titleLabelCons2 = NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: container, attribute: .top, multiplier: 1, constant: 0)
let titleLabelCons3 = NSLayoutConstraint(item: titleLabel, attribute: .bottom, relatedBy: .equal, toItem: container, attribute: .bottom, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([titleLabelCons1, titleLabelCons2, titleLabelCons3])
informationButton.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(informationButton)
informationLabel.translatesAutoresizingMaskIntoConstraints = false
informationButton.addSubview(informationLabel)
let informationLabelCons1 = NSLayoutConstraint(item: informationLabel, attribute: .leading, relatedBy: .equal, toItem: titleLabel, attribute: .trailing, multiplier: 1, constant: 12)
let informationLabelCons2 = NSLayoutConstraint(item: informationLabel, attribute: .trailing, relatedBy: .equal, toItem: informationButton, attribute: .trailing, multiplier: 1, constant: -12)
let informationLabelCons3 = NSLayoutConstraint(item: informationLabel, attribute: .top, relatedBy: .equal, toItem: informationButton, attribute: .top, multiplier: 1, constant: 0)
let informationLabelCons4 = NSLayoutConstraint(item: informationLabel, attribute: .bottom, relatedBy: .equal, toItem: informationButton, attribute: .bottom, multiplier: 1, constant: 0)
let informationLabelCons5 = NSLayoutConstraint(item: informationLabel, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .width, multiplier: 1, constant: 40)
NSLayoutConstraint.activate([informationLabelCons1, informationLabelCons2, informationLabelCons3, informationLabelCons4, informationLabelCons5])
let informationButtonCons1 = NSLayoutConstraint(item: informationButton, attribute: .leading, relatedBy: .equal, toItem: informationLabel, attribute: .leading, multiplier: 1, constant: -12)
let informationButtonCons2 = NSLayoutConstraint(item: informationButton, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0)
let informationButtonCons3 = NSLayoutConstraint(item: informationButton, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([informationButtonCons1, informationButtonCons2, informationButtonCons3])
container.isUserInteractionEnabled = false
}
}
extension DeviceListMenuView {
private class func setDeviceListMenuItemAlpha(_ alpha: Float, for itemList: [DeviceListMenuItem]) {
if alpha >= 0 && alpha <= 1 {
itemList.forEach({$0.alpha = alpha})
}
}
class func configure(device: TPSSDeviceForDeviceList, channel: TPSSChannelInfo?, displayMode: TPSSDeviceGroupDisplayMode = .card) {
deviceChannel = (device, channel)
//OnlineDeviceListViewController调用configure函数是配置两个item title以满足多语言切换刷新文案
DeviceListMenuItem.upgrade.title = LocalizedString(key: deviceListUpgrade)
DeviceListMenuItem.setting.title = LocalizedString(key: deviceListMoreSetting)
DeviceListMenuItem.collect.title = LocalizedString(key: deviceCollectFavorite)
DeviceListMenuItem.unbind.title = LocalizedString(key: deviceUnbindButtonTitle)
//太阳能\NVR\local;card模式此处不显示收藏,老版本vms也不支持
let isVms = TPAppContextFactory.shared().isVmsLogin
DeviceListMenuItem.collect.hidden = (device.deviceType == .solar || device.listType == .local || displayMode == .card || (TPSSAppContext.shared.loginType == .personal ? false : TPSSAppContext.shared.isVmsDeviceListFavoriteOldVersion) || ( device.deviceType == .NVR && channel == nil) ) ? true : false
//根据设备收否被收藏来设置收藏按钮状态
var isCollected = false
if device.deviceType == .IPC {
isCollected = isVms ? device.isVMSFavorited : device.isCollected
} else {
if channel != nil {
isCollected = isVms ? channel!.isVMSFavorited : device.isCollected && device.collectChannels.contains(channel!.channelId as NSNumber)
} else {
isCollected = isVms ? device.isVMSFavorited : device.isCollected
}
}
DeviceListMenuItem.collect.image = isCollected ? TPImageLiteral("device_have_collect_list") : TPImageLiteral("device_not_collect_list")
//太阳能设备适配
if device.deviceType == .IPC || device.deviceType == .solar {
// 消息报警
var showMessage = device.listType == .remote && device.supportMessage && device.displayOnline && !device.isSharedDevice
if let cn = channel {
showMessage = cn.supportsMessagePush && cn.online && device.displayOnline && !device.isSharedDevice
}
//太阳能设备适配
if device.deviceType == .solar {
//太阳能设备不支持通知开关
showMessage = false
// showMessage = device.listType == .remote && device.displayOnline
}
if !showMessage {
DeviceListMenuItem.alarmMode.hidden = true
} else {
DeviceListMenuItem.alarmMode.hidden = false
let messageEnable = channel?.messageEnable ?? device.messageEnable
DeviceListMenuItem.alarmMode.image = messageEnable ? TPImageLiteral("devicelist_alarm_on").withRenderingMode(.alwaysOriginal) : TPImageLiteral("devicelist_alarm_off")
DeviceListMenuItem.alarmMode.title = messageEnable ? LocalizedString(key: deviceListEventAlarmOn) : LocalizedString(key: deviceListEventAlarmOff)
}
if device.deviceSubType == .doorBellCamera {
DeviceListMenuItem.alarmMode.hidden = true
}
// 如果是分享的设备且没有管理权限, cell设为透明, 不许设置
if device.isSharedFromOthers && device.shareDevicePermissionInfo.deviceSettingWrite == false {
setDeviceListMenuItemAlpha(0.5, for: [.alarmMode, .upgrade, .unbind])
} else {
setDeviceListMenuItemAlpha(1, for: [.alarmMode, .upgrade, .unbind])
}
// 云存储
//Fix: 隐藏云存储
// if !device.supportCloudStorage || device.isSharedDevice {
// DeviceListMenuItem.cloudStorage.hidden = true
// } else {
// let cloudStorageService = appContext.currentServiceInfo(forDevice: device.cloudDeviceId,
// channel: max(0, channelID),
// serviceType: .cloudStorage)
//
// DeviceListMenuItem.cloudStorage.hidden = false
//
// if cloudStorageService.isVaild {
// DeviceListMenuItem.cloudStorage.subtitle = cloudStorageService.cloudStorageStateText
// DeviceListMenuItem.cloudStorage.subtitleTextColor = cloudStorageService.stateColor
// DeviceListMenuItem.cloudStorage.subtitleBackgroundColor = cloudStorageService.stateBackgroundColor
// } else {
// DeviceListMenuItem.cloudStorage.subtitle = nil
// }
// }
// 分享
//Fix: 隐藏设备分享
// let appContext = TPSSAppContext.shared
//
// let channelID = channel?.channelId.intValue ?? -1
// if device.isSharedDevice || !device.supportsShare {
// DeviceListMenuItem.share.hidden = true
// } else {
// DeviceListMenuItem.share.hidden = false
// let isEnterpriseShare = appContext.isValidEnterpriseShareDevice(device.cloudDeviceId, channelD: max(0, channelID))
// let shareService: TPSSCloudStorageService
// if isEnterpriseShare {
// shareService = appContext.enterpriseShareService
// } else {
// shareService = appContext.currentServiceInfo(forDevice: device.cloudDeviceId,
// channel: max(0, channelID),
// serviceType: .paidShare)
// }
// let stateText = shareService.shareStateText(isEnterpriseShare: isEnterpriseShare)
// if shareService.isVaild && !stateText.isEmpty && (shareService.serviceState != .expired || UserDefaults.standard.needShowRenewalHint(for: device.cloudDeviceId, channelID: max(0, channelID), isEnterpriseShare: isEnterpriseShare)) {
// DeviceListMenuItem.share.subtitle = stateText
// DeviceListMenuItem.share.subtitleTextColor = shareService.stateColor
// DeviceListMenuItem.share.subtitleBackgroundColor = shareService.stateBackgroundColor
// } else {
// DeviceListMenuItem.share.subtitle = nil
// }
// }
//
// // 重新配置WiFi
// if (device.displayOnline || !device.supportsReonboarding) || channel != nil {
// DeviceListMenuItem.reonboard.hidden = true
// } else {
// DeviceListMenuItem.reonboard.hidden = false
// }
// 固件升级
if device.listType != .remote {
DeviceListMenuItem.upgrade.hidden = true
} else {
if let cn = channel {
if let version = cn.shortReleaseFirmwareVersion, cn.hasNewFirmware && !device.isSharedDevice {
DeviceListMenuItem.upgrade.hidden = false
DeviceListMenuItem.upgrade.image = device.showUpdateForChannel(channel: channel) ? TPImageLiteral("devicelist_update_reddot_nor") : TPImageLiteral("devicelist_update_nor")
DeviceListMenuItem.upgrade.subtitle = version
DeviceListMenuItem.upgrade.subtitleTextColor = .tpbRed
DeviceListMenuItem.upgrade.subtitleBackgroundColor = .tpbRedLight
} else {
DeviceListMenuItem.upgrade.hidden = true
}
} else {
if let version = device.shortReleaseFirmwareVersion, device.online && device.needUpgrade && !device.isSharedDevice {
DeviceListMenuItem.upgrade.hidden = false
DeviceListMenuItem.upgrade.image = device.showUpdateForChannel(channel: nil) ? TPImageLiteral("devicelist_update_reddot_nor") : TPImageLiteral("devicelist_update_nor")
DeviceListMenuItem.upgrade.subtitle = version
DeviceListMenuItem.upgrade.subtitleTextColor = .tpbRed
DeviceListMenuItem.upgrade.subtitleBackgroundColor = .tpbRedLight
} else {
DeviceListMenuItem.upgrade.hidden = true
}
}
}
//未初始化设备只有非本地设备首页可显示解绑按钮
if device.listType == .local || device.factoryStatus != .yes || !device.online {
DeviceListMenuItem.unbind.hidden = true
} else {
DeviceListMenuItem.unbind.hidden = false
}
} else if device.deviceType == .NVR {
// DeviceListMenuItem.alarmMode.hidden = true
// DeviceListMenuItem.upgrade.hidden = true
guard let channelInfo = channel else {
DeviceListMenuItem.alarmMode.hidden = true
DeviceListMenuItem.upgrade.hidden = true
if device.listType == .local || device.factoryStatus != .yes || !device.online {
DeviceListMenuItem.unbind.hidden = true
} else {
DeviceListMenuItem.unbind.hidden = false
}
return
}
// 如果是分享的通道且没有管理权限, cell设为透明, 不许设置
if channelInfo.isSharedFromOthers && channelInfo.shareDevicePermissionInfo.deviceSettingWrite == false {
setDeviceListMenuItemAlpha(0.5, for: [.alarmMode, .upgrade, .unbind])
} else {
setDeviceListMenuItemAlpha(1, for: [.alarmMode, .upgrade, .unbind])
}
// 消息报警
let showMessage = (device.listType == .remote) && channelInfo.supportsMessagePush && channelInfo.online && device.displayOnline && !device.isSharedDevice && channelInfo.active
if !showMessage {
DeviceListMenuItem.alarmMode.hidden = true
} else {
DeviceListMenuItem.alarmMode.hidden = false
let messageEnable = channelInfo.messageEnable
DeviceListMenuItem.alarmMode.image = messageEnable ? TPImageLiteral("devicelist_alarm_on").withRenderingMode(.alwaysOriginal) : TPImageLiteral("devicelist_alarm_off")
DeviceListMenuItem.alarmMode.title = messageEnable ? LocalizedString(key: deviceListEventAlarmOn) : LocalizedString(key: deviceListEventAlarmOff)
}
if device.deviceSubType == .doorBellCamera {
DeviceListMenuItem.alarmMode.hidden = true
}
// 固件升级
if device.listType != .remote {
DeviceListMenuItem.upgrade.hidden = true
} else {
if let version = channelInfo.shortReleaseFirmwareVersion, channelInfo.hasNewFirmware && !device.isSharedDevice && channelInfo.active {
DeviceListMenuItem.upgrade.hidden = false
DeviceListMenuItem.upgrade.image = device.showUpdateForChannel(channel: channelInfo) ? TPImageLiteral("devicelist_update_reddot_nor") : TPImageLiteral("devicelist_update_nor")
DeviceListMenuItem.upgrade.subtitle = version
DeviceListMenuItem.upgrade.subtitleTextColor = .tpbRed
DeviceListMenuItem.upgrade.subtitleBackgroundColor = .tpbRedLight
} else {
DeviceListMenuItem.upgrade.hidden = true
}
}
//未初始化设备只有非本地设备首页可显示解绑按钮;!channelInfo.active仅针对初始化状态,channel都没设备,不显示解绑(非初始化状态device.factoryStatus != .yes直接隐藏unbind)
if device.listType == .local || device.factoryStatus != .yes || !device.online || !channelInfo.active {
DeviceListMenuItem.unbind.hidden = true
} else {
DeviceListMenuItem.unbind.hidden = false
}
}
}
}
最新发布