diff --git a/MVMCoreUI/Atoms/Views/CheckBox.swift b/MVMCoreUI/Atoms/Views/CheckBox.swift index a990aa90..ac6adf1a 100644 --- a/MVMCoreUI/Atoms/Views/CheckBox.swift +++ b/MVMCoreUI/Atoms/Views/CheckBox.swift @@ -8,14 +8,18 @@ import MVMCore + class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - - var lineWidth: CGFloat = 0.0 - var lineColor: UIColor? + 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 @@ -24,7 +28,7 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M 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 endPercentage = 0.66 let animationInterval: Float = 0.01 @@ -32,63 +36,73 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M // MARK: - Lifecycle //-------------------------------------------------- - private var drawPercentage: Float = 0.0 - private var animationTimer: Timer? - private var checkLayer: CAShapeLayer? - private var selected = false + override init(frame: CGRect) { + super.init(frame: frame) - func setupView() { - super.setupView() - backgroundColor = UIColor.clear - drawPercentage = 1.0 - lineColor = UIColor.black - lineWidth = 1.0 - } - - func update(_ size: CGFloat) { - super.update(size) - } + 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 super.lineWidth + return _lineWidth } set(lineWidth) { self.lineWidth = lineWidth - if checkLayer { - checkLayer.removeFromSuperlayer() - checkLayer = nil - updateCheckSelected(selected, animated: false) - } + 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() { - if !checkLayer { - 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 ?? UIColor.black.cgColor - checkLayer.fillColor = UIColor.clear.cgColor - checkLayer.path = path.cgPath - checkLayer.lineWidth = lineWidth - - CATransaction.begin() - CATransaction.setDisableActions(true) - checkLayer.strokeEnd = 0.0 - CATransaction.commit() - } + + 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() } //-------------------------------------------------- @@ -96,15 +110,17 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M //-------------------------------------------------- func updateCheckSelected(_ selected: Bool, animated: Bool) { - MVMCoreDispatchUtility.performBlock(onMainThread: { - self.selected = selected + + DispatchQueue.main.async { + + self.isSelected = selected // animate this bar self.drawCheck() var layer: CAShapeLayer? - if self.checkLayer.presentation() != nil && animated { - layer = self.checkLayer.presentation() + if self.checkLayer?.presentation() != nil && animated { + layer = self.checkLayer!.presentation() } else { layer = self.checkLayer } @@ -116,11 +132,8 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M animateStrokeEnd.duration = 0.3 animateStrokeEnd.fromValue = NSNumber(value: Float(layer?.strokeEnd ?? 0.0)) - if selected { - animateStrokeEnd.toValue = NSNumber(value: 1) - } else { - animateStrokeEnd.toValue = NSNumber(value: 0) - } + + animateStrokeEnd.toValue = NSNumber(value: selected ? 1 : 0) animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear) layer?.add(animateStrokeEnd, forKey: "strokeEndAnimation") @@ -128,38 +141,38 @@ class CheckBox: UIControl, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, M layer?.removeAllAnimations() CATransaction.begin() CATransaction.setDisableActions(true) - if selected { - layer?.strokeEnd = 1.0 - } else { - layer?.strokeEnd = 0.0 - } + layer?.strokeEnd = selected ? 1.0 : 0.0 + CATransaction.commit() } - }) - } - - - func setLineColor(_ lineColor: UIColor?) { - self.lineColor = lineColor - if checkLayer { - checkLayer.strokeColor = lineColor?.cgColor - updateCheckSelected(selected, animated: false) } } - func layoutSubviews() { + override func layoutSubviews() { drawCheck() } + private func defaultState() { + + } + //-------------------------------------------------- // MARK: - Molecular //-------------------------------------------------- + open func reset() { + + } + + open func setAsMolecule() { + + } + func updateView(_ size: CGFloat) { - <#code#> + } func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - <#code#> + } } diff --git a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift index 5e7c7739..972100d4 100644 --- a/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift +++ b/MVMCoreUI/Atoms/Views/CheckBoxWithLabel.swift @@ -32,6 +32,237 @@ class CheckBoxWithLabel: ViewConstrainingView { // 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 //-------------------------------------------------- diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m index 2cde1bc3..d219f2f3 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUICheckBox.m @@ -306,6 +306,8 @@ static const CGFloat CheckBoxHeightWidth = 18.0; self.checkedSquare.layer.cornerRadius = self.isRoundRectCheckMark ? 5.0f : 0; } +// TODO:..................................... + #pragma mark - XIB Helpers - (instancetype)awakeAfterUsingCoder:(NSCoder *)aDecoder {