Adding two new checkbox swift classes.

This commit is contained in:
Kevin G Christiano 2019-09-25 14:19:49 -04:00
parent 7722dc5619
commit 35f7024f8d
6 changed files with 587 additions and 465 deletions

View File

@ -18,8 +18,8 @@
01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */; };
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */; };
0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */; };
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; };
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; };
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E142280C4CF007245F4 /* ProgressBar.swift */; };
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8200E182281DC1A007245F4 /* CornerLabels.swift */; };
@ -205,8 +205,8 @@
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBox.swift; sourceTree = "<group>"; };
0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxWithLabel.swift; sourceTree = "<group>"; };
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = "<group>"; };
948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = "<group>"; };
B8200E142280C4CF007245F4 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
B8200E182281DC1A007245F4 /* CornerLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = "<group>"; };
@ -726,8 +726,8 @@
DB891E822253FA8500022516 /* Label.swift */,
0198F7A02256A80A0066C936 /* MFRadioButton.h */,
0198F7A22256A80A0066C936 /* MFRadioButton.m */,
0A7BAFA0232BE61800FB8E22 /* CheckBox.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckBoxWithLabel.swift */,
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -1042,6 +1042,7 @@
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */,
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */,
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
@ -1049,7 +1050,7 @@
D282AACB2243C61700C46919 /* ButtonView.swift in Sources */,
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
0A7BAFA1232BE61800FB8E22 /* CheckBox.swift in Sources */,
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */,
D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */,
D2E1FADD2268B25E00AEFD8C /* MoleculeTableViewCell.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
@ -1077,7 +1078,6 @@
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
0A7BAFA3232BE63400FB8E22 /* CheckBoxWithLabel.swift in Sources */,
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */,
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,

View File

@ -1,178 +0,0 @@
//
// CheckBox.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 9/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import MVMCore
class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
private var _lineColor: UIColor = .black
private var _lineWidth: CGFloat = 1.0
private var drawPercentage: Float = 0.0
private var animationTimer: Timer?
private var checkLayer: CAShapeLayer?
let startXOffset: Float = 42.0 / 124.0
let startYOffset: Float = 66.0 / 124.0
let pivotXOffset: Float = 58.0 / 124.0
let pivotYOffset: Float = 80.0 / 124.0
let endXOffset: Float = 83.0 / 124.0
let endYOffset: Float = 46.0 / 124.0
let pivotPercentage: Float = 0.34
let endPercentage = 0.66
let animationInterval: Float = 0.01
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
drawPercentage = 1.0
lineColor = .black
lineWidth = 1.0
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("Xib File is not implemented for CheckBox.")
}
var lineWidth: CGFloat {
get {
return _lineWidth
}
set(lineWidth) {
self.lineWidth = lineWidth
guard let checkLayer = checkLayer else { return }
checkLayer.removeFromSuperlayer()
checkLayer = nil
updateCheckSelected(isSelected, animated: false)
}
}
var lineColor: UIColor {
get {
return _lineColor
}
set(lineColor) {
_lineColor = lineColor
if let checkLayer = checkLayer {
checkLayer.strokeColor = lineColor.cgColor
updateCheckSelected(isSelected, animated: false)
}
}
}
//--------------------------------------------------
// MARK: - Draw
//--------------------------------------------------
func drawCheck() {
guard let checkLayer = checkLayer else { return }
layoutIfNeeded()
let path = UIBezierPath()
path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55))
path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85))
path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2))
checkLayer = CAShapeLayer()
checkLayer.frame = bounds
layer.addSublayer(checkLayer)
checkLayer.strokeColor = lineColor.cgColor
checkLayer.fillColor = UIColor.clear.cgColor
checkLayer.path = path.cgPath
checkLayer.lineWidth = lineWidth
CATransaction.begin()
CATransaction.setDisableActions(true)
checkLayer.strokeEnd = 0.0
CATransaction.commit()
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
func updateCheckSelected(_ selected: Bool, animated: Bool) {
DispatchQueue.main.async {
self.isSelected = selected
// animate this bar
self.drawCheck()
var layer: CAShapeLayer?
if self.checkLayer?.presentation() != nil && animated {
layer = self.checkLayer!.presentation()
} else {
layer = self.checkLayer
}
if animated {
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.fillMode = .both
animateStrokeEnd.isRemovedOnCompletion = false
animateStrokeEnd.duration = 0.3
animateStrokeEnd.fromValue = NSNumber(value: Float(layer?.strokeEnd ?? 0.0))
animateStrokeEnd.toValue = NSNumber(value: selected ? 1 : 0)
animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear)
layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation")
} else {
layer?.removeAllAnimations()
CATransaction.begin()
CATransaction.setDisableActions(true)
layer?.strokeEnd = selected ? 1.0 : 0.0
CATransaction.commit()
}
}
}
override func layoutSubviews() {
drawCheck()
}
private func defaultState() {
}
//--------------------------------------------------
// MARK: - Molecular
//--------------------------------------------------
open func reset() {
}
open func setAsMolecule() {
}
func updateView(_ size: CGFloat) {
}
func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
}
}

View File

@ -1,277 +0,0 @@
//
// CheckBoxWithLabel.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 9/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
class CheckBoxWithLabel: ViewConstrainingView {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
weak var checkMark: CheckBox?
private(set) var isSelected = false
var sizeObject: MFSizeObject?
//??????
var checkedColor: UIColor?
var unCheckedColor: UIColor?
// Label to the right of the check box.
weak var descriptionLabel: Label?
// Setter for the descriptionLabel.text. Also sets the accessibility text.
var descriptionText: String?
var descriptionAttributedText: NSAttributedString?
// A block that is called when the switch is selected.
var switchSelected: ((_ selected: Bool) -> ())?
//--------------------------------------------------
// MARK: - Life Cycle
//--------------------------------------------------
// TODO: MVMCoreUICheckBox.m
func needsToBeConstrained() -> Bool {
return true
}
func alignment() -> UIStackView.Alignment {
return .leading
}
func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
FormValidator.setupValidation(withMolecule: self, delegate: delegateObject?.formValidationProtocol)
delegate = delegateObject
fieldKey = json?.string(for: KeyFieldKey)
isRequired = json?.bool(forKey: KeyRequired)
let checkedColorHex = json?.string("checkedColor")
let unCheckedColorHex = json?.string("unCheckedColor")
let checkedColor = checkedColorHex != nil ? UIColor.mfGet(forHex: checkedColorHex) : UIColor.clear
let unCheckedColor = unCheckedColorHex != nil ? UIColor.mfGet(forHex: unCheckedColorHex) : UIColor.clear
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, label: json?.dict(KeyLabel), delegateObject: delegateObject, additionalData: additionalData)
}
class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return CGFloat(CheckBoxHeightWidth)
}
// MARK: - convenient class methods
class func mf() -> Self {
let checkBox = self.init(frame: CGRect.zero)
checkBox.translatesAutoresizingMaskIntoConstraints = false
return checkBox
}
class func mfCheckBoxWithRoundedRect() -> Self? {
let checkBox = self.init(roundRect: true)
checkBox.translatesAutoresizingMaskIntoConstraints = false
return checkBox
}
class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) -> Self {
let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, text: text)
checkBox?.translatesAutoresizingMaskIntoConstraints = false
return checkBox
}
class func mfCheckBox(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, atributedText attributedText: NSAttributedString?) -> Self {
let checkBox = self.init(checkedColor: checkedColor, unCheck: unCheckedColor, attributedText: attributedText)
checkBox?.translatesAutoresizingMaskIntoConstraints = false
return checkBox
}
// MARK: - FormValidationProtocol
func isValidField() -> Bool {
if isRequired {
return isSelected()
}
return true
}
func formFieldName() -> String? {
return fieldKey
}
func formFieldValue() -> Any? {
return NSNumber(value: isSelected())
}
// MARK: - inits
init() {
super.init()
setupView()
}
init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) {
super.init()
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text)
addAccessibleProperties()
}
init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) {
super.init()
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil)
descriptionAttributedText = attributedText
addAccessibleProperties()
}
init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) {
super.init()
checkMark = checkMarkView
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text)
addAccessibleProperties()
}
init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) {
super.init()
checkMark = checkMarkView
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil)
descriptionAttributedText = attributedText
addAccessibleProperties()
}
init(roundRect isRoundRect: Bool) {
super.init()
isRoundRectCheckMark = isRoundRect
setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil)
addAccessibleProperties()
setCheckMarkLayer()
}
//default inits
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil)
addAccessibleProperties()
}
init(frame: CGRect) {
super.init(frame: frame)
setupView()
setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil)
addAccessibleProperties()
}
func awakeFromNib() {
super.awakeFromNib()
setup(withCheckedColor: UIColor.white, unCheck: UIColor.white, text: nil)
}
func setupView() {
let containterView = MVMCoreUICommonViewsUtility.commonView()
containterView?.isUserInteractionEnabled = false
if !sizeObject {
sizeObject = MFSizeObject(standardSize: CheckBoxHeightWidth, standardiPadPortraitSize: Int(CheckBoxHeightWidth) + 6)
}
//checked circle
if !self.checkedSquare {
let checkedSquare = MVMCoreUICommonViewsUtility.commonView()
checkedSquare?.backgroundColor = UIColor.white
if let checkedSquare = checkedSquare {
containterView?.addSubview(checkedSquare)
}
let size = sizeObject.getValueBasedOnApplicationWidth()
let constraints = NSLayoutConstraint.constraintPinView(checkedSquare, heightConstraint: true, heightConstant: size, widthConstraint: true, widthConstant: size)
checkboxWidth = constraints[ConstraintWidth]
checkboxHeight = constraints[ConstraintHeight]
NSLayoutConstraint.constraintPinSubview(checkedSquare, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false)
checkboxRightPinConstraint = checkedSquare?.trailingAnchor.constraintEqual(to: containterView?.trailingAnchor)
NSLayoutConstraint.constraintPinSubview(checkedSquare, pinCenterX: false, pinCenterY: true)
self.checkedSquare = checkedSquare
self.checkBoxBorder = UIColor.black
}
// TODO: OBJC CODE
//check mark
if (!self.checkMark) {
MVMCoreUICheckMarkView *checkMark = [[MVMCoreUICheckMarkView alloc] initWithFrame:self.frame];
checkMark.lineWidth = 2.0;
self.checkMark = checkMark;
self.checkMark.translatesAutoresizingMaskIntoConstraints = NO;
[self.checkedSquare addSubview:self.checkMark];
[self.checkMark.widthAnchor constraintEqualToAnchor:self.checkedSquare.widthAnchor multiplier:.4].active = YES;
[self.checkMark.heightAnchor constraintEqualToAnchor:self.checkedSquare.heightAnchor multiplier:.4].active = YES;
[self.checkMark.centerXAnchor constraintEqualToAnchor:self.checkedSquare.centerXAnchor].active = YES;
[self.checkMark.centerYAnchor constraintEqualToAnchor:self.checkedSquare.centerYAnchor].active = YES;
}
//label
if (!self.descriptionLabel) {
Label *descriptionLabel = [Label commonLabelB2:YES];
[containterView addSubview:descriptionLabel];
[NSLayoutConstraint constraintPinSubview:descriptionLabel pinCenterX:NO pinCenterY:YES];
[NSLayoutConstraint constraintPinSubview:descriptionLabel pinTop:NO pinBottom:NO pinLeft:NO pinRight:YES];
self.descriptionLabelLeadingConstraint = [NSLayoutConstraint constraintWithItem:descriptionLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.checkedSquare attribute:NSLayoutAttributeTrailing multiplier:1 constant:11];
self.descriptionLabelLeadingConstraint.active = YES;
self.descriptionLabelLeadingConstraint.active = YES;
self.descriptionLabel = descriptionLabel;
[self setSelected:NO];
}
if (!self.containerView) {
[self addSubview:containterView];
self.containerView = containterView;
[NSLayoutConstraint constraintPinSubviewToSuperview:containterView];
}
}
func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?) {
if checkedColor != nil {
self.checkedColor = checkedColor
}
if unCheckedColor != nil {
self.unCheckedColor = unCheckedColor
}
}
func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) {
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor)
descriptionText = text ?? ""
}
func setup(withCheckedColor checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, label labelJson: [AnyHashable : Any]?, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) {
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor)
descriptionLabel.setWithJSON(labelJson, delegateObject: delegateObject, additionalData: additionalData)
}
@objc func updateView(_ size: CGFloat) {
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.descriptionLabel.updateView(size)
if self.checkMark.responds(to: #selector(updateView(_:))) {
let width = self.sizeObject.getValueBased(onSize: size)
self.checkboxWidth.constant = width
self.checkboxHeight.constant = width
self.checkMark.updateView(size)
}
})
}
func setCheckMarkLayer() {
checkedSquare.layer.cornerRadius = isRoundRectCheckMark ? 5.0 : 0
}
//--------------------------------------------------
// MARK: - Molecular
//--------------------------------------------------
override func updateView(_ size: CGFloat) {
}
override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
}
}

View File

@ -0,0 +1,288 @@
//
// Checkbox.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 9/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import MVMCore
@objcMembers open class Checkbox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static let defaultHeightWidth: CGFloat = 18.0
/*
//Offsets based on the 124x124 example checkmark
let startXOffset: Float = 42.0 / 124.0
let startYOffset: Float = 66.0 / 124.0
let pivotXOffset: Float = 58.0 / 124.0
let pivotYOffset: Float = 80.0 / 124.0
let endXOffset: Float = 83.0 / 124.0
let endYOffset: Float = 46.0 / 124.0
let pivotPercentage: Float = 0.34
let endPercentage = 1.0 - pivotPercentage
let animationInterval: Float = 0.01
*/
public var checkedColor: UIColor = .black
public var unCheckedColor: UIColor = .mfPaleGrey()
public var hasRoundBorder = false
private var shapeLayer: CAShapeLayer?
private var _lineColor: UIColor = .black
private var _borderColor: UIColor = .black
private var _lineWidth: CGFloat = 1.0
private var _cornerRadius: CGFloat = 5.0
public func setCheckMarkLayer() {
checkedSquare.layer.cornerRadius = checkbox.isRoundRectCheckMark ? 5.0 : 0
}
public var lineWidth: CGFloat {
get { return _lineWidth }
set (newLineWidth) {
_lineWidth = newLineWidth
if shapeLayer != nil {
shapeLayer?.removeFromSuperlayer()
shapeLayer = nil
updateCheckSelected(isSelected, animated: false)
}
}
}
public var lineColor: UIColor {
get { return _lineColor }
set (newLineColor) {
_lineColor = newLineColor
if let shapeLayer = shapeLayer {
shapeLayer.strokeColor = lineColor.cgColor
updateCheckSelected(isSelected, animated: false)
}
}
}
public var borderColor: UIColor {
get { return _borderColor }
set (newBorderColor) {
_borderColor = newBorderColor
if let shapeLayer = shapeLayer {
shapeLayer.strokeColor = borderColor.cgColor
updateCheckSelected(isSelected, animated: false)
}
}
}
override open var isSelected: Bool {
didSet {
if isSelected {
layer.addSublayer(shapeLayer!)
shapeLayer?.strokeEnd = 1
shapeLayer?.removeAllAnimations()
shapeLayer?.add(checkedAnimation, forKey: "strokeEnd")
} else {
shapeLayer?.strokeEnd = 0
shapeLayer?.removeAllAnimations()
shapeLayer?.add(uncheckedAnimation, forKey: "strokeEnd")
}
}
}
lazy private var checkedAnimation: CABasicAnimation = {
let check = CABasicAnimation(keyPath: "strokeEnd")
check.timingFunction = CAMediaTimingFunction(name: .linear)
check.fillMode = .both
check.duration = 0.33
check.fromValue = 0
check.toValue = 1
return check
}()
lazy private var uncheckedAnimation: CABasicAnimation = {
let unCheck = CABasicAnimation(keyPath: "strokeEnd")
unCheck.fillMode = .both
unCheck.duration = 0.33
unCheck.fromValue = 0
unCheck.toValue = 1
return unCheck
}()
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
override public init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
public convenience init() {
self.init(frame:.zero)
}
/// There is currently no intention on using xib files.
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("xib file is not implemented for CheckBox.")
}
public convenience init(checkedColor: UIColor, uncheckColor: UIColor, isChecked: Bool) {
self.init(frame: .zero)
isSelected = isChecked
// TODO: define the rest....
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
override open func layoutSubviews() {
super.layoutSubviews()
drawCheck()
}
public func setupView() {
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .white
lineColor = .black
lineWidth = 1.0
let path = UIBezierPath()
path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55))
path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85))
path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2))
let shapeLayer = CAShapeLayer()
self.shapeLayer = shapeLayer
shapeLayer.frame = bounds
layer.addSublayer(shapeLayer)
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.path = path.cgPath
shapeLayer.lineJoin = .bevel
shapeLayer.lineWidth = lineWidth
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
private func drawCheck() {
if shapeLayer == nil {
layoutIfNeeded()
let path = UIBezierPath()
path.move(to: CGPoint(x: lineWidth / 2, y: bounds.size.height * 0.55))
path.addLine(to: CGPoint(x: bounds.size.width * 0.45, y: bounds.size.height * 0.85))
path.addLine(to: CGPoint(x: bounds.size.width - lineWidth / 2, y: lineWidth / 2))
shapeLayer = CAShapeLayer()
shapeLayer?.frame = bounds
layer.addSublayer(shapeLayer!)
shapeLayer?.strokeColor = lineColor.cgColor
shapeLayer?.fillColor = UIColor.clear.cgColor
shapeLayer?.path = path.cgPath
shapeLayer?.lineJoin = .bevel
shapeLayer?.lineWidth = lineWidth
CATransaction.begin()
CATransaction.setDisableActions(true)
shapeLayer?.strokeEnd = 0.0
CATransaction.commit()
}
}
public func updateCheckSelected(_ selected: Bool, animated: Bool) {
DispatchQueue.main.async {
self.isSelected = selected
self.drawCheck()
var layer: CAShapeLayer?
if let presentation = self.shapeLayer?.presentation(), animated {
layer = presentation
} else {
layer = self.shapeLayer
}
if animated {
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.fillMode = .both
animateStrokeEnd.isRemovedOnCompletion = false
animateStrokeEnd.duration = 0.33
animateStrokeEnd.fromValue = layer?.strokeEnd ?? 0.0
animateStrokeEnd.toValue = selected ? 1 : 0
animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear)
layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation")
} else {
layer?.removeAllAnimations()
CATransaction.begin()
CATransaction.setDisableActions(true)
layer?.strokeEnd = selected ? 1 : 0
CATransaction.commit()
}
}
}
//--------------------------------------------------
// MARK: - Molecular
//--------------------------------------------------
open func needsToBeConstrained() -> Bool {
return true
}
open func reset() {
setupView()
}
open func setAsMolecule() {
setupView()
}
public func updateView(_ size: CGFloat) {
}
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
guard let dictionary = json else { return }
if let borderColor = dictionary["borderColor"] as? String {
layer.borderColor = UIColor.mfGet(forHex: borderColor).cgColor
}
if let checkColor = dictionary["lineColor"] as? String {
_lineColor = UIColor.mfGet(forHex: checkColor)
}
if let checkColor = dictionary["checkedColor"] as? String {
checkedColor = UIColor.mfGet(forHex: checkColor)
}
if let unCheckedColor = dictionary["unCheckedColor"] as? String {
uncheckedColor = UIColor.mfGet(forHex: unCheckedColor)
}
if let backroundColor = dictionary["backroundColor"] as? String {
self.backgroundColor = UIColor.mfGet(forHex: backroundColor)
}
if let borderWidth = dictionary["borderWidth"] as? CGFloat {
_lineWidth = borderWidth
}
if let cornerRadius = dictionary["cornerRadius"] as? CGFloat {
_cornerRadius = cornerRadius
}
}
}

View File

@ -0,0 +1,289 @@
//
// CheckboxWithLabelView.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 9/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
@objcMembers open class CheckboxWithLabelView: ViewConstrainingView {
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
let checkbox = Checkbox()
let label = Label.commonLabelB2(true)
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0)
var checkboxWidthConstraint: NSLayoutConstraint?
var checkboxHeightConstraint: NSLayoutConstraint?
// Setter for the descriptionLabel.text. Also sets the accessibility text.
var labelText: String?
var labelAttributedText: NSAttributedString?
// A block that is called when the switch is selected.
public var checkBoxAction: ((_ selected: Bool) -> ())?
func setDescriptionAttributedText(_ descriptionAttributedText: NSAttributedString?) {
descriptionLabel?.text = nil
descriptionLabel?.attributedText = descriptionAttributedText
self.valueForAccessibilityText = descriptionAttributedText?.string
}
var descriptionText: String {
get { return super.descriptionText }
set(descriptionText) {
descriptionLabel?.attributedText = nil
descriptionLabel.text = descriptionText
self.valueForAccessibilityText = descriptionText
}
}
var isRequired = false
var fieldKey: String?
var delegate: DelegateObject?
//--------------------------------------------------
// MARK: - Life Cycle
//--------------------------------------------------
override open func setupView() {
super.setupView()
guard subviews.isEmpty else { return }
translatesAutoresizingMaskIntoConstraints = false
addSubview(checkbox)
let dimension = sizeObject?.getValueBasedOnApplicationWidth() ?? Checkbox.defaultHeightWidth
checkboxWidthConstraint = checkbox.heightAnchor.constraint(equalToConstant: dimension)
checkboxWidthConstraint?.isActive = true
checkboxHeightConstraint = checkbox.widthAnchor.constraint(equalToConstant: dimension)
checkboxHeightConstraint?.isActive = true
NSLayoutConstraint.constraintPinSubview(checkbox, pinTop: true, pinBottom: true, pinLeft: true, pinRight: false)
checkbox.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
checkbox.lineWidth = 2.0
addSubview(label)
NSLayoutConstraint.constraintPinSubview(label, pinCenterX: false, pinCenterY: true)
NSLayoutConstraint.constraintPinSubview(label, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true)
label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
//default inits
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("xib file is not implemented for CheckboxWithLabelView")
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
addAccessibleProperties()
}
convenience init() {
self.init(frame: .zero)
}
init(checkedColor: UIColor?, unCheckedColor: UIColor?, text: String?) {
super.init(frame: .zero)
checkbox.checkedColor = checkedColor
checkbox.unCheckedColor = unCheckedColor
label.text = text
addAccessibleProperties()
}
init(checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) {
super.init(frame: .zero)
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil)
descriptionAttributedText = attributedText
addAccessibleProperties()
}
init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, text: String?) {
super.init(frame: .zero)
checkMark = checkMarkView
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: text)
addAccessibleProperties()
}
init?(checkMarkView: MVMCoreUICheckMarkView?, checkedColor: UIColor?, unCheck unCheckedColor: UIColor?, attributedText: NSAttributedString?) {
super.init(frame: .zero)
checkMark = checkMarkView
setup(withCheckedColor: checkedColor, unCheck: unCheckedColor, text: nil)
descriptionAttributedText = attributedText
addAccessibleProperties()
}
init(roundRect isRoundRect: Bool) {
super.init(frame: .zero)
isRoundRectCheckMark = isRoundRect
setup(withCheckedColor: .white, unCheck: .white, text: nil)
addAccessibleProperties()
setCheckMarkLayer()
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return CGFloat(CheckBoxHeightWidth)
}
// MARK: - control methods
func setSelected(_ selected: Bool) {
setSelected(selected, animated: true)
checkbox?.is
}
func setSelected(_ selected: Bool, animated: Bool) {
setSelected(selected, animated: animated, runBlock: true)
}
func setSelected(_ selected: Bool, animated: Bool, runBlock: Bool) {
addAccessibilityLabel(selected)
isSelected = selected
if (switchSelected != nil) && runBlock {
switchSelected(selected)
}
if selected {
UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: {
self.checkedSquare.backgroundColor = self.checkedColor
})
checkMark.updateCheckSelected(true, animated: animated)
} else {
UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: {
self.checkedSquare.backgroundColor = self.unCheckedColor
})
checkMark?.updateCheckSelected(false, animated: animated)
}
if delegate && delegate.responds(to: #selector(formValidationProtocol)) && delegate.perform(#selector(formValidationProtocol)).responds(to: #selector(Unmanaged<AnyObject>.formValidatorModel)) {
let formValidator = delegate.perform(#selector(formValidationProtocol)).perform(#selector(Unmanaged<AnyObject>.formValidatorModel)) as? FormValidator
formValidator?.enableByValidation()
}
}
//--------------------------------------------------
// MARK: - UITouch
//--------------------------------------------------
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
if touchIsOutside(touches.first) {
sendActions(for: .touchUpOutside)
} else {
self.selected = !isSelected()
sendActions(for: .touchUpInside)
}
}
func touchIsOutside(_ touch: UITouch?) -> Bool {
let endLocation = touch?.location(in: self)
let x = endLocation?.x ?? 0.0
let y = endLocation?.y ?? 0.0
let faultTolerance: CGFloat = 20.0
let widthLimit = CGFloat(frame.size.width + faultTolerance)
let heightLimt = CGFloat(frame.size.height + faultTolerance)
return x < -faultTolerance || y < -faultTolerance || x > widthLimit || y > heightLimt
}
}
// MARK: - Molecular
extension CheckboxWithLabelView {
@objc override open func updateView(_ size: CGFloat) {
DispatchQueue.main.async {
self.label.updateView(size)
if self.checkbox.responds(to: #selector(self.updateView(_:))) {
if let dimension = self.sizeObject?.getValueBased(onSize: size) {
self.checkboxWidthConstraint?.constant = dimension
self.checkboxHeightConstraint?.constant = dimension
self.checkbox.updateView(size)
}
}
}
}
override open func alignment() -> UIStackView.Alignment {
return .leading
}
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
delegate = delegateObject
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
guard let dictionary = json else { return }
fieldKey = dictionary.string(for: KeyFieldKey)
isRequired = dictionary.bool(forKey: KeyRequired)
checkbox.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
label.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
}
// MARK:- FormValidationProtocol
extension CheckboxWithLabelView: FormValidationProtocol {
public func isValidField() -> Bool {
return isRequired ? checkbox.isSelected : true
}
public func formFieldName() -> String? {
return fieldKey
}
public func formFieldValue() -> Any? {
return NSNumber(value: checkbox.isSelected)
}
}
// MARK:- Accessibility
extension CheckboxWithLabelView {
func addAccessibleProperties() {
accessibilityTraits = .none
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint")
}
func addAccessibilityLabel(_ selected: Bool) {
let state = selected ? MVMCoreUIUtility.hardcodedString(withKey: "checkbox_checked_state") : MVMCoreUIUtility.hardcodedString(withKey: "checkbox_unchecked_state")
let description = accessibilityText.length ? accessibilityText : ""
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state"), description, state)
}
func hideDescriptionLabelAndPinCheckboxToRight() {
descriptionLabel?.hidden = true
checkboxRightPinConstraint.active = true
descriptionLabelLeadingConstraint.constant = 0
}
}

View File

@ -38,11 +38,11 @@
@"caretButton": CaretButton.class,
@"textField" : MFTextField.class,
@"digitTextField" : MFDigitTextField.class,
@"checkbox" : MVMCoreUICheckBox.class,
@"checkbox" : Checkbox.class,
@"cornerLabels" : CornerLabels.class,
@"progressBar": ProgressBar.class,
@"multiProgressBar": MultiProgress.class,
@"checkbox": MVMCoreUICheckBox.class,
@"checkboxWithLabelView": CheckboxWithLabelView.class,
@"listItem": MoleculeTableViewCell.class,
@"accordionListItem": AccordionMoleculeTableViewCell.class,
@"switch": MVMCoreUISwitch.class,