accessibility and formatting
This commit is contained in:
parent
f53526508c
commit
fd735b8139
@ -6,18 +6,21 @@
|
|||||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
@objcMembers open class LoadImageView: View {
|
@objcMembers open class LoadImageView: View {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public let loadingSpinner = MFLoadingSpinner(frame: .zero)
|
public let loadingSpinner = MFLoadingSpinner(frame: .zero)
|
||||||
public let imageView = MFTransparentGIFView(frame: .zero)
|
public let imageView = MFTransparentGIFView(frame: .zero)
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var addSizeConstraintsForAspectRatio = true
|
public var addSizeConstraintsForAspectRatio = true
|
||||||
public var shouldNotifyDelegateOnUpdate = true
|
public var shouldNotifyDelegateOnUpdate = true
|
||||||
var centerX: NSLayoutConstraint?
|
|
||||||
var centerY: NSLayoutConstraint?
|
|
||||||
var widthConstraint: NSLayoutConstraint?
|
|
||||||
var heightConstraint: NSLayoutConstraint?
|
|
||||||
var loadingSpinnerHeightConstraint: NSLayoutConstraint?
|
|
||||||
|
|
||||||
// Allows for a view to hardcode which height to use if there is none in the json.
|
// Allows for a view to hardcode which height to use if there is none in the json.
|
||||||
var imageWidth: CGFloat?
|
var imageWidth: CGFloat?
|
||||||
@ -35,6 +38,25 @@ import UIKit
|
|||||||
|
|
||||||
private var containerHelper = ContainerHelper()
|
private var containerHelper = ContainerHelper()
|
||||||
|
|
||||||
|
open override var accessibilityLabel: String? {
|
||||||
|
get { imageView.accessibilityLabel }
|
||||||
|
set { imageView.accessibilityLabel = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraint Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
var centerX: NSLayoutConstraint?
|
||||||
|
var centerY: NSLayoutConstraint?
|
||||||
|
var widthConstraint: NSLayoutConstraint?
|
||||||
|
var heightConstraint: NSLayoutConstraint?
|
||||||
|
var loadingSpinnerHeightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(pinnedEdges edge: UIRectEdge) {
|
public init(pinnedEdges edge: UIRectEdge) {
|
||||||
edges = edge
|
edges = edge
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
@ -60,45 +82,18 @@ import UIKit
|
|||||||
set(with: model, delegateObject, additionalData)
|
set(with: model, delegateObject, additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func pinEdges(_ edge: UIRectEdge) {
|
//--------------------------------------------------
|
||||||
edges = edge
|
// MARK: - MVMCoreViewProtocol
|
||||||
if edge == UIRectEdge.all {
|
//--------------------------------------------------
|
||||||
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.horizontal)
|
|
||||||
imageView.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.vertical)
|
|
||||||
} else {
|
|
||||||
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.horizontal)
|
|
||||||
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: NSLayoutConstraint.Axis.vertical)
|
|
||||||
}
|
|
||||||
|
|
||||||
if edge.contains(UIRectEdge.top) && edge.contains(UIRectEdge.bottom) {
|
|
||||||
containerHelper.alignVertical(.fill)
|
|
||||||
} else if edge.contains(UIRectEdge.top) {
|
|
||||||
containerHelper.alignVertical(.leading)
|
|
||||||
} else if edge.contains(UIRectEdge.bottom) {
|
|
||||||
containerHelper.alignVertical(.trailing)
|
|
||||||
} else {
|
|
||||||
containerHelper.alignVertical(.center)
|
|
||||||
}
|
|
||||||
|
|
||||||
if edge.contains(UIRectEdge.left) && edge.contains(UIRectEdge.right) {
|
|
||||||
containerHelper.alignHorizontal(.fill)
|
|
||||||
} else if edge.contains(UIRectEdge.left) {
|
|
||||||
containerHelper.alignHorizontal(.leading)
|
|
||||||
} else if edge.contains(UIRectEdge.right) {
|
|
||||||
containerHelper.alignHorizontal(.trailing)
|
|
||||||
} else {
|
|
||||||
containerHelper.alignHorizontal(.center)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func setupView() {
|
override open func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard subviews.count == 0 else {
|
|
||||||
return
|
guard subviews.count == 0 else { return }
|
||||||
}
|
|
||||||
clipsToBounds = true
|
clipsToBounds = true
|
||||||
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.horizontal)
|
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .horizontal)
|
||||||
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: NSLayoutConstraint.Axis.vertical)
|
setContentHuggingPriority(UILayoutPriority(rawValue: 950), for: .vertical)
|
||||||
|
|
||||||
// Setup image.
|
// Setup image.
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
imageView.translatesAutoresizingMaskIntoConstraints = false;
|
||||||
@ -125,8 +120,12 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open func defaultCompletionBlock() -> MVMCoreGetImageBlock {
|
open func defaultCompletionBlock() -> MVMCoreGetImageBlock {
|
||||||
return {image,gifData,_ in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
return { image, gifData,_ in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||||
if let image = image {
|
if let image = image {
|
||||||
self?.imageView.image = image
|
self?.imageView.image = image
|
||||||
self?.layoutIfNeeded()
|
self?.layoutIfNeeded()
|
||||||
@ -139,9 +138,8 @@ import UIKit
|
|||||||
|
|
||||||
open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool {
|
open func shouldLoadImage(withName imageName: String?, width: CGFloat) -> Bool {
|
||||||
// We should load a new image if there is no current image, the image names are different, the width is different, or we are using a fallback image.
|
// We should load a new image if there is no current image, the image names are different, the width is different, or we are using a fallback image.
|
||||||
guard let currentWidth = self.currentImageWidth else {
|
guard let currentWidth = self.currentImageWidth else { return true }
|
||||||
return true
|
|
||||||
}
|
|
||||||
return (imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || isFallbackImage
|
return (imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || !MVMCoreGetterUtility.cgfequal(width, currentWidth) || isFallbackImage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,22 +148,61 @@ import UIKit
|
|||||||
if ((imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || isFallbackImage) {
|
if ((imageView.image == nil && imageView.animatedImage == nil) || imageName != currentImageName || isFallbackImage) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// load new image if the width is different
|
// load new image if the width is different
|
||||||
if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) {
|
if let oldWidth = self.currentImageWidth, let newWidth = width, !MVMCoreGetterUtility.cgfequal(oldWidth, newWidth) {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
} else if (self.currentImageWidth == nil) != (width == nil) {
|
} else if (self.currentImageWidth == nil) != (width == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// load new image if the height is different
|
// load new image if the height is different
|
||||||
if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) {
|
if let oldHeight = self.currentImageHeight, let newHeight = height, !MVMCoreGetterUtility.cgfequal(oldHeight, newHeight) {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
} else if (self.currentImageHeight == nil) || (height == nil) {
|
} else if (self.currentImageHeight == nil) || (height == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Constraints
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraint Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public func pinEdges(_ edge: UIRectEdge) {
|
||||||
|
edges = edge
|
||||||
|
|
||||||
|
if edge == .all {
|
||||||
|
imageView.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||||
|
imageView.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||||
|
} else {
|
||||||
|
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
|
||||||
|
imageView.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .vertical)
|
||||||
|
}
|
||||||
|
|
||||||
|
if edge.contains(.top) && edge.contains(.bottom) {
|
||||||
|
containerHelper.alignVertical(.fill)
|
||||||
|
} else if edge.contains(.top) {
|
||||||
|
containerHelper.alignVertical(.leading)
|
||||||
|
} else if edge.contains(.bottom) {
|
||||||
|
containerHelper.alignVertical(.trailing)
|
||||||
|
} else {
|
||||||
|
containerHelper.alignVertical(.center)
|
||||||
|
}
|
||||||
|
|
||||||
|
if edge.contains(.left) && edge.contains(.right) {
|
||||||
|
containerHelper.alignHorizontal(.fill)
|
||||||
|
} else if edge.contains(.left) {
|
||||||
|
containerHelper.alignHorizontal(.leading)
|
||||||
|
} else if edge.contains(.right) {
|
||||||
|
containerHelper.alignHorizontal(.trailing)
|
||||||
|
} else {
|
||||||
|
containerHelper.alignHorizontal(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setHeight(_ height: CGFloat) {
|
func setHeight(_ height: CGFloat) {
|
||||||
if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) {
|
if let heightConstraint = heightConstraint, MVMCoreGetterUtility.cgfequal(heightConstraint.multiplier, 1) {
|
||||||
@ -187,9 +224,8 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool {
|
func layoutWillChange(width: CGFloat?, height: CGFloat?, size: CGSize?) -> Bool {
|
||||||
guard addSizeConstraintsForAspectRatio else {
|
guard addSizeConstraintsForAspectRatio else { return false }
|
||||||
return false
|
|
||||||
}
|
|
||||||
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
|
let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0)
|
||||||
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
|
let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0)
|
||||||
let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
|
let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false)
|
||||||
@ -199,11 +235,11 @@ import UIKit
|
|||||||
|
|
||||||
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
|
// Constrains the image view to be the size provided. Used to size it to the image to fix aspect fit defect.
|
||||||
func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) {
|
func addConstraints(width: NSNumber?, height: NSNumber?, size: CGSize?) {
|
||||||
|
|
||||||
widthConstraint?.isActive = false
|
widthConstraint?.isActive = false
|
||||||
heightConstraint?.isActive = false
|
heightConstraint?.isActive = false
|
||||||
guard addSizeConstraintsForAspectRatio else {
|
|
||||||
return
|
guard addSizeConstraintsForAspectRatio else { return }
|
||||||
}
|
|
||||||
|
|
||||||
if let width = width, let height = height {
|
if let width = width, let height = height {
|
||||||
setHeight(height.cgfloat())
|
setHeight(height.cgfloat())
|
||||||
@ -221,25 +257,34 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
self.delegateObject = delegateObject
|
self.delegateObject = delegateObject
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
guard let imageModel = model as? ImageViewModel else { return }
|
guard let imageModel = model as? ImageViewModel else { return }
|
||||||
|
|
||||||
if let accessibilityString = imageModel.accessibilityText {
|
if let accessibilityString = imageModel.accessibilityText {
|
||||||
imageView.accessibilityLabel = accessibilityString
|
imageView.accessibilityLabel = accessibilityString
|
||||||
imageView.accessibilityTraits = .staticText
|
imageView.accessibilityTraits = .staticText
|
||||||
imageView.isAccessibilityElement = true
|
imageView.isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = imageModel.width ?? imageWidth
|
let width = imageModel.width ?? imageWidth
|
||||||
let height = imageModel.height ?? imageHeight
|
let height = imageModel.height ?? imageHeight
|
||||||
|
|
||||||
// For smoother transitions, set constraints that we know immediately.
|
// For smoother transitions, set constraints that we know immediately.
|
||||||
if let width = width, addSizeConstraintsForAspectRatio {
|
if let width = width, addSizeConstraintsForAspectRatio {
|
||||||
setWidth(width)
|
setWidth(width)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let height = height, addSizeConstraintsForAspectRatio {
|
if let height = height, addSizeConstraintsForAspectRatio {
|
||||||
setHeight(height)
|
setHeight(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldLoadImage(withName: imageModel.image, width: width, height: height) {
|
if shouldLoadImage(withName: imageModel.image, width: width, height: height) {
|
||||||
imageView.image = nil
|
imageView.image = nil
|
||||||
imageView.animatedImage = nil
|
imageView.animatedImage = nil
|
||||||
@ -260,7 +305,10 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - load functions
|
//--------------------------------------------------
|
||||||
|
// MARK: - Load Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public func loadImage(withName imageName: String?, format: String? = nil, width: NSNumber? = nil, height: NSNumber? = nil, customFallbackImage: String? = nil, allowServerParameters: Bool = false, localBundle: Bundle? = nil, completionHandler: MVMCoreGetImageBlock? = nil) {
|
public func loadImage(withName imageName: String?, format: String? = nil, width: NSNumber? = nil, height: NSNumber? = nil, customFallbackImage: String? = nil, allowServerParameters: Bool = false, localBundle: Bundle? = nil, completionHandler: MVMCoreGetImageBlock? = nil) {
|
||||||
|
|
||||||
let completionBlock = completionHandler ?? defaultCompletionBlock()
|
let completionBlock = completionHandler ?? defaultCompletionBlock()
|
||||||
@ -275,7 +323,7 @@ import UIKit
|
|||||||
|
|
||||||
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
|
||||||
guard let self = self,
|
guard let self = self,
|
||||||
let loadingImageName = self.currentImageName, loadingImageName == imageName else { return }
|
let loadingImageName = self.currentImageName, loadingImageName == imageName else { return }
|
||||||
self.isFallbackImage = isFallbackImage
|
self.isFallbackImage = isFallbackImage
|
||||||
self.loadingSpinner.pause()
|
self.loadingSpinner.pause()
|
||||||
let layoutWillChange = self.shouldNotifyDelegateOnUpdate ? self.layoutWillChange(width: self.currentImageWidth, height: self.currentImageHeight, size: image?.size) : false
|
let layoutWillChange = self.shouldNotifyDelegateOnUpdate ? self.layoutWillChange(width: self.currentImageWidth, height: self.currentImageHeight, size: image?.size) : false
|
||||||
@ -298,7 +346,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func loadCroppedImage(withName imageName:
|
public func loadCroppedImage(withName imageName:
|
||||||
String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) {
|
String?, width: NSNumber?, height: NSNumber?, cropRect: CGRect, flipImage: Bool, customFallbackImage: String?) {
|
||||||
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
MVMCoreDispatchUtility.performBlock(onMainThread: { [unowned self] in
|
||||||
self.currentImageName = imageName
|
self.currentImageName = imageName
|
||||||
self.loadingSpinner.resumeSpinnerAfterDelay()
|
self.loadingSpinner.resumeSpinnerAfterDelay()
|
||||||
|
|||||||
@ -135,7 +135,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
open override func accessibilityActivate() -> Bool {
|
open override func accessibilityActivate() -> Bool {
|
||||||
|
|
||||||
return button.accessibilityActivate()
|
return button.accessibilityActivate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ open class HeadlineBody: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Setup
|
// MARK: - MVMCoreViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
@ -123,6 +123,13 @@ open class HeadlineBody: View {
|
|||||||
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor).isActive = true
|
view.bottomAnchor.constraint(equalTo: messageLabel.bottomAnchor).isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
headlineLabel.updateView(size)
|
||||||
|
messageLabel.updateView(size)
|
||||||
|
setSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Constraining
|
// MARK: - Constraining
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -139,13 +146,6 @@ open class HeadlineBody: View {
|
|||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
|
||||||
super.updateView(size)
|
|
||||||
headlineLabel.updateView(size)
|
|
||||||
messageLabel.updateView(size)
|
|
||||||
setSpacing()
|
|
||||||
}
|
|
||||||
|
|
||||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
return 58
|
return 58
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user