Move mf switch to core ui

This commit is contained in:
Pfeil, Scott Robert 2019-02-01 12:52:16 -05:00
parent 5e31a07316
commit 271d164cda
7 changed files with 422 additions and 0 deletions

View File

@ -15,6 +15,8 @@
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */; };
D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F1D220343560077CEC0 /* MVMCoreUICheckMarkView.m */; };
D22D1F46220496A30077CEC0 /* MVMCoreUISwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F44220496A30077CEC0 /* MVMCoreUISwitch.h */; settings = {ATTRIBUTES = (Public, ); }; };
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */; };
D28B4F8A21FF967C00712C7A /* MVMCoreUIObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D28B4F8821FF967C00712C7A /* MVMCoreUIObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */; };
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; };
@ -160,6 +162,8 @@
D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckBox.m; sourceTree = "<group>"; };
D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckMarkView.h; sourceTree = "<group>"; };
D22D1F1D220343560077CEC0 /* MVMCoreUICheckMarkView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckMarkView.m; sourceTree = "<group>"; };
D22D1F44220496A30077CEC0 /* MVMCoreUISwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUISwitch.h; sourceTree = "<group>"; };
D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUISwitch.m; sourceTree = "<group>"; };
D28B4F8821FF967C00712C7A /* MVMCoreUIObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIObject.h; sourceTree = "<group>"; };
D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIObject.m; sourceTree = "<group>"; };
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
@ -542,6 +546,8 @@
D22D1F1D220343560077CEC0 /* MVMCoreUICheckMarkView.m */,
D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */,
D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */,
D22D1F44220496A30077CEC0 /* MVMCoreUISwitch.h */,
D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */,
);
path = Views;
sourceTree = "<group>";
@ -683,6 +689,7 @@
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */,
D29DF2BC21E7BEA4003B2FB9 /* TopTabbar.h in Headers */,
D29DF25921E6A22D003B2FB9 /* MFButtonProtocol.h in Headers */,
D22D1F46220496A30077CEC0 /* MVMCoreUISwitch.h in Headers */,
D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */,
D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */,
D29DF2CE21E7C104003B2FB9 /* MFLoadingViewController.h in Headers */,
@ -854,6 +861,7 @@
D29DF25D21E6A2B6003B2FB9 /* DashLine.m in Sources */,
D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */,
D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */,
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,

View File

@ -0,0 +1,34 @@
//
// MVMSwitch.h
// myverizon
//
// Created by Tianhang Yang on 12/1/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import <UIKit/UIKit.h>
@import MVMCore.MVMCoreViewProtocol;
typedef void(^ValueChangeBlock)(void);
@interface MVMCoreUISwitch : UIControl <MVMCoreViewProtocol>
@property (assign, nonatomic, getter=isOn) BOOL on;
@property (nullable, strong, nonatomic) UIColor *onTintColor;
@property (nullable, strong, nonatomic) UIColor *offTintColor;
@property (nullable, strong, nonatomic) UIColor *onKnobTintColor;
@property (nullable, strong, nonatomic) UIColor *offKnobTintColor;
@property (nonatomic) BOOL shouldTouchToSwitch;
@property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock;
+ (nullable instancetype)mvmSwitchDefault;
+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block;
- (void)setState:(BOOL)state animated:(BOOL)animated;
// Sets the state without triggering the value changed block.
- (void)setState:(BOOL)stateWithoutBlock withoutBlockAnimated:(BOOL)animated;
@end

View File

@ -0,0 +1,364 @@
//
// MVMSwitch.m
// myverizon
//
// Created by Tianhang Yang on 12/1/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import "MVMCoreUISwitch.h"
@import MVMCore.NSDictionary_MFConvenience;
#import <MVMCoreUI/MFSizeObject.h>
#import <MVMCoreUI/MFStyler.h>
#import <MVMCoreUI/NSLayoutConstraint+MFConvenience.h>
#import <MVMCoreUI/UIColor+MFConvenience.h>
#import <MVMCoreUI/MVMCoreUICommonViewsUtility.h>
#import <MVMCoreUI/MVMCoreUIUtility.h>
const CGFloat SwitchWidth = 42;
const CGFloat SwitchHeight = 22;
const CGFloat SwitchKnobWidth = 20;
const CGFloat SwitchKnobHeight = 20;
const CGFloat SwitchShakeIntensity = 2;
@interface MVMCoreUISwitch ()
@property (weak, nonatomic) UIView *baseView;
@property (weak, nonatomic) UIView *knobView;
@property (strong, nonatomic) NSLayoutConstraint *knobLeftConstraint;
@property (strong, nonatomic) NSLayoutConstraint *knobRightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *knobHeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *knobWidthConstraint;
@property (weak, nonatomic) NSLayoutConstraint *height;
@property (weak, nonatomic) NSLayoutConstraint *width;
@property (assign, nonatomic) BOOL valueShouldChange;
@property (nonatomic) BOOL canChangeValue;
@end
@implementation MVMCoreUISwitch
- (void)updateView:(CGFloat)size {
self.height.constant = [MVMCoreUISwitch getSwitchHeight];
self.width.constant = [MVMCoreUISwitch getSwitchWidth];
self.baseView.layer.cornerRadius = [MVMCoreUISwitch getSwitchHeight]/2.f;
self.knobView.layer.cornerRadius = [MVMCoreUISwitch getSwitchKnobHeight]*0.5;
self.knobHeightConstraint.constant = [MVMCoreUISwitch getSwitchKnobHeight];
self.knobWidthConstraint.constant = [MVMCoreUISwitch getSwitchKnobWidth];
}
- (void)setupView {
self.onTintColor = [UIColor mfSwitchOnTintColor];
self.offTintColor = [UIColor mfSwitchOffTintColor];
self.canChangeValue = YES;
self.shouldTouchToSwitch = YES;
[self setUpViewWithState:self.on];
self.accessibilityLabel = [MVMCoreUIUtility hardcodedStringWithKey:@"MVMCoreUISwitch_buttonlabel"];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if ([super initWithCoder:coder]) {
[self setupView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if ([super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (instancetype)init {
if ([super init]) {
[self setupView];
}
return self;
}
+ (instancetype)mvmSwitchDefault {
MVMCoreUISwitch *mySwitch = [[self alloc] initWithFrame:CGRectZero];
mySwitch.translatesAutoresizingMaskIntoConstraints = NO;
return mySwitch;
}
+ (nullable instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block {
MVMCoreUISwitch *mySwitch = [[self alloc] initWithFrame:CGRectZero];
mySwitch.valueChangedBlock = block;
return mySwitch;
}
- (void)setUpViewWithState:(BOOL)on {
if (!self.baseView) {
self.userInteractionEnabled = YES;
self.valueShouldChange = YES;
UIView *baseView = [MVMCoreUICommonViewsUtility commonView];
[self addSubview:baseView];
[NSLayoutConstraint constraintPinSubviewToSuperview:baseView];
NSDictionary *constraints = [NSLayoutConstraint constraintPinView:baseView heightConstraint:YES heightConstant:[MVMCoreUISwitch getSwitchHeight] widthConstraint:YES widthConstant:[MVMCoreUISwitch getSwitchWidth]];
self.height = [constraints objectForKey:ConstraintHeight ofType:[NSLayoutConstraint class]];
self.width = [constraints objectForKey:ConstraintWidth ofType:[NSLayoutConstraint class]];
baseView.layer.cornerRadius = [MVMCoreUISwitch getSwitchHeight]/2.f;
self.onKnobTintColor = [UIColor whiteColor];
self.offKnobTintColor = [UIColor whiteColor];
UIView *knobView = [MVMCoreUICommonViewsUtility commonView];
knobView.backgroundColor = [UIColor whiteColor];
knobView.layer.cornerRadius = [MVMCoreUISwitch getSwitchKnobHeight]*0.5;
[baseView addSubview:knobView];
NSDictionary *heightWidth = [NSLayoutConstraint constraintPinView:knobView heightConstraint:YES heightConstant:[MVMCoreUISwitch getSwitchKnobHeight] widthConstraint:YES widthConstant:[MVMCoreUISwitch getSwitchKnobWidth]];
NSLayoutConstraint *height = [heightWidth objectForKey:ConstraintHeight ofType:[NSLayoutConstraint class]];
NSLayoutConstraint *width = [heightWidth objectForKey:ConstraintWidth ofType:[NSLayoutConstraint class]];
self.knobHeightConstraint = height;
self.knobWidthConstraint = width;
NSDictionary *leadingTrailingDic = [NSLayoutConstraint constraintPinSubview:knobView pinTop:NO topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:1 pinRight:YES rightConstant:1];
NSLayoutConstraint *left = [leadingTrailingDic objectForKey:ConstraintLeading ofType:[NSLayoutConstraint class]];
NSLayoutConstraint *right = [leadingTrailingDic objectForKey:ConstraintTrailing ofType:[NSLayoutConstraint class]];
[NSLayoutConstraint constraintPinSubview:knobView pinCenterX:NO centerXConstant:0 pinCenterY:YES centerYConstant:0];
right.constant = 15;
self.knobLeftConstraint = left;
self.knobRightConstraint = right;
[baseView bringSubviewToFront:knobView];
self.baseView = baseView;
self.knobView = knobView;
self.baseView.userInteractionEnabled = NO;
self.knobView.userInteractionEnabled = NO;
self.shouldTouchToSwitch = NO;
[self setState:on animated:NO];
self.shouldTouchToSwitch = YES;
}
}
#pragma mark - UIResponder overide
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self knobEnlargeAnimation];
[self sendActionsForControlEvents:UIControlEventTouchDown];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.shouldTouchToSwitch) {
if (self.valueShouldChange) {
[self changeValue];
}
}
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
[self knobMoveAnitmationToOn:self.isOn];
[self knobShakeAnitmationToOn:self.isOn];
[self knobReformAnimation:YES];
self.valueShouldChange = YES;
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.shouldTouchToSwitch) {
if ([self touchMovesToLeft:touches]) {
[self knobMoveAnitmationToOn:NO];
[self knobShakeAnitmationToOn:NO];
[self knobReformAnimation :YES];
} else {
[self knobMoveAnitmationToOn:YES];
[self knobShakeAnitmationToOn:YES];
[self knobReformAnimation :YES];
}
}
if ([self touchIsOutSide:touches]){
[self sendActionsForControlEvents:UIControlEventTouchDragOutside];
if (!self.shouldTouchToSwitch) {
[self knobReformAnimation:YES];
}
} else {
[self sendActionsForControlEvents:UIControlEventTouchDragInside];
}
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.shouldTouchToSwitch) {
[self knobReformAnimation :YES];
self.canChangeValue = YES;
}
[self sendActionsForControlEvents:UIControlEventTouchCancel];
}
#pragma mark - animation
- (void)knobEnlargeAnimation {
[UIView animateWithDuration:0.1 animations:^{
self.knobWidthConstraint.constant += PaddingOne;
[self layoutIfNeeded];
}];
}
- (void)knobReformAnimation :(BOOL)animated {
if(animated) {
[UIView animateWithDuration:0.1 animations:^{
self.knobWidthConstraint.constant = [MVMCoreUISwitch getSwitchKnobWidth];
[self layoutIfNeeded];
} completion:^(BOOL finished) {
}];
} else {
self.knobWidthConstraint.constant = [MVMCoreUISwitch getSwitchKnobWidth];
[self layoutIfNeeded];
}
}
- (void)knobMoveAnitmationToOn:(BOOL)toOn {
[UIView animateWithDuration:0.1 animations:^{
if (toOn) {
self.knobLeftConstraint.priority = 1;
self.knobRightConstraint.priority = 999;
self.knobRightConstraint.constant = 1;
} else {
self.knobLeftConstraint.priority = 999;
self.knobRightConstraint.priority = 1;
self.knobLeftConstraint.constant = 1;
}
[self setBaseColorToOn:toOn animated:YES];
self.knobWidthConstraint.constant = [MVMCoreUISwitch getSwitchKnobWidth]+PaddingOne;
self.valueShouldChange = (toOn != self.on);
[self layoutIfNeeded];
}];
}
- (void)setBaseColorToOn:(BOOL)toOn animated:(BOOL)animated {
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
if (toOn) {
self.knobView.backgroundColor = self.onKnobTintColor;
[self.baseView setBackgroundColor:self.onTintColor];
} else {
self.knobView.backgroundColor = self.offKnobTintColor;
[self.baseView setBackgroundColor:self.offTintColor];
}
[UIView commitAnimations];
} else if (self.on) {
self.knobView.backgroundColor = self.onKnobTintColor;
[self.baseView setBackgroundColor:self.onTintColor];
} else {
self.knobView.backgroundColor = self.offKnobTintColor;
[self.baseView setBackgroundColor:self.offTintColor];
}
}
//used after knob moving to match the behavior of default uiswitch
- (void)knobShakeAnitmationToOn:(BOOL)toOn {
[UIView animateWithDuration:0.1 delay:0.1 options:UIViewAnimationOptionCurveEaseIn animations:^{
if (toOn) {
self.knobRightConstraint.constant = SwitchShakeIntensity;
} else {
self.knobLeftConstraint.constant = SwitchShakeIntensity;
}
[self layoutIfNeeded];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.2 delay:0.1 options:0 animations:^{
if (toOn) {
self.knobRightConstraint.constant = 1;
} else {
self.knobLeftConstraint.constant = 1;
}
[self layoutIfNeeded];
} completion:^(BOOL finished) {
self.valueShouldChange = YES;
}];
}
#pragma mark - switch logic
- (void)setState:(BOOL)state animated:(BOOL)animated {
[self setState:state withoutBlockAnimated:animated];
if (self.valueChangedBlock) {
self.valueChangedBlock();
}
}
- (void)setState:(BOOL)state withoutBlockAnimated:(BOOL)animated {
self.on = state;
if (!self.shouldTouchToSwitch) {
[self knobEnlargeAnimation];
[self knobMoveAnitmationToOn:self.on];
[self knobShakeAnitmationToOn:self.on];
}
if (self.on) {
self.knobLeftConstraint.priority = 1;
self.knobRightConstraint.priority = 999;
self.knobRightConstraint.constant = 1;
}
else {
self.knobRightConstraint.priority = 1;
self.knobLeftConstraint.priority = 999;
self.knobLeftConstraint.constant = 1;
}
[self setBaseColorToOn:self.on animated:animated];
[self knobReformAnimation:animated];
self.accessibilityValue = state ? [MVMCoreUIUtility hardcodedStringWithKey:@"AccOn"] : [MVMCoreUIUtility hardcodedStringWithKey:@"AccOff"];
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (BOOL)changeValue{
self.on^=YES;
self.shouldTouchToSwitch = NO;
[self setState:self.on animated:YES];
self.shouldTouchToSwitch = YES;
[self sendActionsForControlEvents:UIControlEventValueChanged];
return self.on;
}
#pragma mark - helper
- (BOOL)touchIsOutSide:(NSSet<UITouch *> *)touches {
CGPoint location = [[touches anyObject] locationInView:self];
float x = location.x;
float y = location.y;
return (x<0 || x >self.frame.size.width || y <0 || y > self.frame.size.height);
}
- (BOOL)touchMovesToLeft:(NSSet<UITouch *> *)touches {
CGPoint location = [[touches anyObject] locationInView:self];
float x = location.x;
return (x< self.frame.size.width/2.f);
}
+ (CGFloat)getSwitchWidth {
return [[MFSizeObject sizeObjectWithStandardSize:SwitchWidth standardiPadPortraitSize:SwitchWidth * 1.5] getValueBasedOnApplicationWidth];
}
+ (CGFloat)getSwitchHeight {
return [[MFSizeObject sizeObjectWithStandardSize:SwitchHeight standardiPadPortraitSize:SwitchHeight * 1.5] getValueBasedOnApplicationWidth];
}
+ (CGFloat)getSwitchKnobWidth {
return [[MFSizeObject sizeObjectWithStandardSize:SwitchKnobWidth standardiPadPortraitSize:SwitchKnobWidth * 1.5] getValueBasedOnApplicationWidth];
}
+ (CGFloat)getSwitchKnobHeight {
return [[MFSizeObject sizeObjectWithStandardSize:SwitchKnobHeight standardiPadPortraitSize:SwitchKnobHeight * 1.5] getValueBasedOnApplicationWidth];
}
#pragma mark - Accessibility
- (BOOL)isAccessibilityElement{
return YES;
}
- (UIAccessibilityTraits)accessibilityTraits {
return UIAccessibilityTraitButton;
}
- (NSString *)accessibilityHint {
return [MVMCoreUIUtility hardcodedStringWithKey:@"AccToggleHint"];
}
@end

View File

@ -83,6 +83,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[];
#import <MVMCoreUI/MVMCoreUITextFieldView.h>
#import <MVMCoreUI/MVMCoreUICheckMarkView.h>
#import <MVMCoreUI/MVMCoreUICheckBox.h>
#import <MVMCoreUI/MVMCoreUISwitch.h>
#pragma mark Buttons
#import <MVMCoreUI/MFButtonProtocol.h>

View File

@ -34,3 +34,8 @@
"checkbox_checked_state" = "Checked";
"checkbox_unchecked_state" = "Unchecked";
"checkbox_desc_state" = "%@ CheckBox %@";
// Switch
"mfswitch_buttonlabel" = "Switch Button";
"AccOn" = "on";
"AccOff" = "off";
"AccToggleHint" = "double tap to toggle";

View File

@ -33,3 +33,8 @@
"checkbox_checked_state" = "Verificado";
"checkbox_unchecked_state" = "Sin marcar";
"checkbox_desc_state" = "%@ Casilla %@";
// Switch
"mfswitch_buttonlabel" = "Botón Cambiar";
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";

View File

@ -33,3 +33,8 @@
"checkbox_checked_state" = "Verificado";
"checkbox_unchecked_state" = "Sin marcar";
"checkbox_desc_state" = "%@ Casilla %@";
// Switch
"mfswitch_buttonlabel" = "Botón Cambiar";
"AccOn" = "encendido";
"AccOff" = "apagado";
"AccToggleHint" = "toca dos veces para alternar";