Commit 628cb5c4 authored by Jérôme Lebel's avatar Jérôme Lebel Committed by Commit Bot

[iOS] Update UI constraints for UserSigninViewController

Adding consent insets for buttons.
Adding max constraints for the user consent view (600x600px).
Centering the user consent on iPad.
Changing the button size between iPad and iPhone.
Attaching the gradient view to the bottom of user consent view.

Screenshots:
https://drive.google.com/open?id=17Eh7k968on1pifk0nJSRCArmgs9Csb98
(blue and yellow colors are just for debug reasons).

Bug: 971989
Change-Id: I3c767d717538a1d5de53eb66f33cf20db4336261
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2139723
Commit-Queue: Jérôme Lebel <jlebel@chromium.org>
Reviewed-by: default avatarNohemi Fernandez <fernandex@chromium.org>
Cr-Commit-Position: refs/heads/master@{#757786}
parent 247b96bf
...@@ -22,32 +22,40 @@ ...@@ -22,32 +22,40 @@
namespace { namespace {
// Button corner radius. // Button corner radius.
const CGFloat kButtonCornerRadius = 8; const CGFloat kButtonCornerRadius = 8;
// Inset between button contents and edge. // Gradient height.
const CGFloat kButtonTitleContentInset = 8.0; const CGFloat kGradientHeight = 40.;
// Max size for the user consent view.
const CGFloat kUserConsentMaxSize = 600.;
// Layout constants for buttons. // Layout constants for buttons.
struct AuthenticationViewConstants { struct AuthenticationViewConstants {
CGFloat GradientHeight; CGFloat PrimaryFontSize;
CGFloat SecondaryFontSize;
CGFloat ButtonHeight; CGFloat ButtonHeight;
CGFloat ButtonHorizontalPadding; CGFloat ButtonHorizontalPadding;
CGFloat ButtonTopPadding; CGFloat ButtonVerticalPadding;
CGFloat ButtonBottomPadding; CGFloat ButtonTitleContentHorizontalInset;
CGFloat ButtonTitleContentVerticalInset;
}; };
const AuthenticationViewConstants kCompactConstants = { const AuthenticationViewConstants kCompactConstants = {
40, // GradientHeight 24, // PrimaryFontSize
14, // SecondaryFontSize
36, // ButtonHeight 36, // ButtonHeight
16, // ButtonHorizontalPadding 16, // ButtonHorizontalPadding
16, // ButtonTopPadding 16, // ButtonVerticalPadding
16, // ButtonBottomPadding 16, // ButtonTitleContentHorizontalInset
8, // ButtonTitleContentVerticalInset
}; };
const AuthenticationViewConstants kRegularConstants = { const AuthenticationViewConstants kRegularConstants = {
kCompactConstants.GradientHeight, 1.5 * kCompactConstants.PrimaryFontSize,
1.5 * kCompactConstants.SecondaryFontSize,
1.5 * kCompactConstants.ButtonHeight, 1.5 * kCompactConstants.ButtonHeight,
32, // ButtonHorizontalPadding 32, // ButtonHorizontalPadding
32, // ButtonTopPadding 32, // ButtonVerticalPadding
32, // ButtonBottomPadding 16, // ButtonTitleContentInset
16, // ButtonTitleContentInset
}; };
// The style applied to a button type. // The style applied to a button type.
...@@ -60,6 +68,9 @@ enum AuthenticationButtonType { ...@@ -60,6 +68,9 @@ enum AuthenticationButtonType {
@interface UserSigninViewController () @interface UserSigninViewController ()
// Container view used to center vertically the user consent view between the
// top of the controller view and the top of the button view.
@property(nonatomic, strong) UIView* containerView;
// Activity indicator used to block the UI when a sign-in operation is in // Activity indicator used to block the UI when a sign-in operation is in
// progress. // progress.
@property(nonatomic, strong) MDCActivityIndicator* activityIndicator; @property(nonatomic, strong) MDCActivityIndicator* activityIndicator;
...@@ -73,12 +84,22 @@ enum AuthenticationButtonType { ...@@ -73,12 +84,22 @@ enum AuthenticationButtonType {
@property(nonatomic, assign) BOOL hasUnifiedConsentScreenReachedBottom; @property(nonatomic, assign) BOOL hasUnifiedConsentScreenReachedBottom;
// Gradient used to hide text that is close to the bottom of the screen. This // Gradient used to hide text that is close to the bottom of the screen. This
// gives users the hint that there is more to scroll through. // gives users the hint that there is more to scroll through.
@property(nonatomic, strong) GradientView* gradientView; @property(nonatomic, strong, readonly) GradientView* gradientView;
// Lists of constraints that need to be activated when the view is in
// compact size class.
@property(nonatomic, strong, readonly) NSArray* compactSizeClassConstraints;
// Lists of constraints that need to be activated when the view is in
// regular size class.
@property(nonatomic, strong, readonly) NSArray* regularSizeClassConstraints;
@end @end
@implementation UserSigninViewController @implementation UserSigninViewController
@synthesize gradientView = _gradientView;
@synthesize compactSizeClassConstraints = _compactSizeClassConstraints;
@synthesize regularSizeClassConstraints = _regularSizeClassConstraints;
#pragma mark - Public #pragma mark - Public
- (void)markUnifiedConsentScreenReachedBottom { - (void)markUnifiedConsentScreenReachedBottom {
...@@ -138,52 +159,86 @@ enum AuthenticationButtonType { ...@@ -138,52 +159,86 @@ enum AuthenticationButtonType {
self.view.backgroundColor = self.systemBackgroundColor; self.view.backgroundColor = self.systemBackgroundColor;
[self addConfirmationButton]; [self addConfirmationButton];
[self embedUserConsentView];
[self addSkipSigninButton]; [self addSkipSigninButton];
[self embedUserConsentView];
[self.view addSubview:self.gradientView]; [NSLayoutConstraint activateConstraints:@[
// Contraints for the container view. The bottom constraint has to be set
// The layout constraints should be added at the end once all of the views // according to the size class.
// have been created. [self.containerView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
AuthenticationViewConstants constants = self.authenticationViewConstants; [self.containerView.leadingAnchor
constraintEqualToAnchor:self.view.leadingAnchor],
// Embedded view constraints. [self.containerView.trailingAnchor
AddSameConstraintsWithInsets( constraintEqualToAnchor:self.view.trailingAnchor],
self.unifiedConsentViewController.view, self.view.safeAreaLayoutGuide, ]];
ChromeDirectionalEdgeInsetsMake(0, 0,
constants.ButtonHeight + [self.containerView addSubview:self.gradientView];
constants.ButtonBottomPadding +
constants.ButtonTopPadding,
0));
// Skip sign-in button constraints.
AddSameConstraintsToSidesWithInsets(
self.skipSigninButton, self.view.safeAreaLayoutGuide,
LayoutSides::kBottom | LayoutSides::kLeading,
ChromeDirectionalEdgeInsetsMake(0, constants.ButtonHorizontalPadding,
constants.ButtonBottomPadding, 0));
// Confirmation button constraints.
AddSameConstraintsToSidesWithInsets(
self.confirmationButton, self.view.safeAreaLayoutGuide,
LayoutSides::kBottom | LayoutSides::kTrailing,
ChromeDirectionalEdgeInsetsMake(0, 0, constants.ButtonBottomPadding,
constants.ButtonHorizontalPadding));
// Gradient layer constraints.
self.gradientView.translatesAutoresizingMaskIntoConstraints = NO; self.gradientView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
// The gradient view needs to be attatched to the bottom of the user
// consent view which contains the scroll view.
[self.gradientView.bottomAnchor [self.gradientView.bottomAnchor
constraintEqualToAnchor:self.unifiedConsentViewController.view constraintEqualToAnchor:self.unifiedConsentViewController.view
.bottomAnchor], .bottomAnchor],
[self.gradientView.leadingAnchor [self.gradientView.leadingAnchor
constraintEqualToAnchor:self.view.leadingAnchor], constraintEqualToAnchor:self.unifiedConsentViewController.view
.leadingAnchor],
[self.gradientView.trailingAnchor [self.gradientView.trailingAnchor
constraintEqualToAnchor:self.view.trailingAnchor], constraintEqualToAnchor:self.unifiedConsentViewController.view
.trailingAnchor],
[self.gradientView.heightAnchor constraintEqualToConstant:kGradientHeight],
]];
[self updateViewsAndConstraints];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self updateViewsAndConstraints];
}
[self.gradientView.heightAnchor #pragma mark - Constraints
constraintEqualToConstant:constants.GradientHeight],
// Generate default constraints based on the constants.
- (NSMutableArray*)generateConstraintsWithConstants:
(AuthenticationViewConstants)constants {
NSMutableArray* constraints = [NSMutableArray array];
// Confirmation button constraints
[constraints addObjectsFromArray:@[
[self.view.safeAreaLayoutGuide.trailingAnchor
constraintEqualToAnchor:self.confirmationButton.trailingAnchor
constant:constants.ButtonHorizontalPadding],
[self.view.safeAreaLayoutGuide.bottomAnchor
constraintEqualToAnchor:self.confirmationButton.bottomAnchor
constant:constants.ButtonVerticalPadding],
]]; ]];
// Skip button constraints
[constraints addObjectsFromArray:@[
[self.skipSigninButton.leadingAnchor
constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor
constant:constants.ButtonHorizontalPadding],
[self.view.safeAreaLayoutGuide.bottomAnchor
constraintEqualToAnchor:self.skipSigninButton.bottomAnchor
constant:constants.ButtonVerticalPadding],
]];
return constraints;
}
// Updates view sizes and constraints.
- (void)updateViewsAndConstraints {
BOOL isRegularSizeClass = IsRegularXRegularSizeClass(self.traitCollection);
UIFontTextStyle fontStyle;
if (isRegularSizeClass) {
[NSLayoutConstraint deactivateConstraints:self.compactSizeClassConstraints];
[NSLayoutConstraint activateConstraints:self.regularSizeClassConstraints];
fontStyle = UIFontTextStyleTitle2;
} else {
[NSLayoutConstraint deactivateConstraints:self.regularSizeClassConstraints];
[NSLayoutConstraint activateConstraints:self.compactSizeClassConstraints];
fontStyle = UIFontTextStyleSubheadline;
}
[self applyDefaultSizeWithButton:self.confirmationButton fontStyle:fontStyle];
[self applyDefaultSizeWithButton:self.skipSigninButton fontStyle:fontStyle];
} }
#pragma mark - Properties #pragma mark - Properties
...@@ -221,9 +276,6 @@ enum AuthenticationButtonType { ...@@ -221,9 +276,6 @@ enum AuthenticationButtonType {
return isRegularSizeClass ? kRegularConstants : kCompactConstants; return isRegularSizeClass ? kRegularConstants : kCompactConstants;
} }
// Sets up gradient that masks text when the iOS device size is a compact size.
// This is to hint to the user that there is additional text below the end of
// the screen.
- (UIView*)gradientView { - (UIView*)gradientView {
if (!_gradientView) { if (!_gradientView) {
_gradientView = [[GradientView alloc] init]; _gradientView = [[GradientView alloc] init];
...@@ -231,6 +283,79 @@ enum AuthenticationButtonType { ...@@ -231,6 +283,79 @@ enum AuthenticationButtonType {
return _gradientView; return _gradientView;
} }
- (NSArray*)compactSizeClassConstraints {
if (!_compactSizeClassConstraints) {
NSMutableArray* constraints =
[self generateConstraintsWithConstants:kCompactConstants];
[constraints addObjectsFromArray:@[
// Constraints for the user consent view inside the container view.
[self.unifiedConsentViewController.view.topAnchor
constraintEqualToAnchor:self.containerView.topAnchor],
[self.unifiedConsentViewController.view.bottomAnchor
constraintEqualToAnchor:self.containerView.bottomAnchor],
[self.unifiedConsentViewController.view.leadingAnchor
constraintEqualToAnchor:self.containerView.leadingAnchor],
[self.unifiedConsentViewController.view.trailingAnchor
constraintEqualToAnchor:self.containerView.trailingAnchor],
// Constraint between the container view and the confirmation button.
[self.confirmationButton.topAnchor
constraintEqualToAnchor:self.containerView.bottomAnchor
constant:kCompactConstants.ButtonVerticalPadding],
]];
_compactSizeClassConstraints = constraints;
}
return _compactSizeClassConstraints;
}
- (NSArray*)regularSizeClassConstraints {
if (!_regularSizeClassConstraints) {
NSMutableArray* constraints =
[self generateConstraintsWithConstants:kRegularConstants];
[constraints addObjectsFromArray:@[
// Constraints for the user consent view inside the container view, to
// make sure it is never bigger than the container view.
[self.unifiedConsentViewController.view.topAnchor
constraintGreaterThanOrEqualToAnchor:self.containerView.topAnchor],
[self.unifiedConsentViewController.view.bottomAnchor
constraintLessThanOrEqualToAnchor:self.containerView.bottomAnchor],
[self.unifiedConsentViewController.view.leadingAnchor
constraintGreaterThanOrEqualToAnchor:self.containerView
.leadingAnchor],
[self.unifiedConsentViewController.view.trailingAnchor
constraintLessThanOrEqualToAnchor:self.containerView.trailingAnchor],
// The user consent view needs to be centered if the container view is
// bigger than the max size authorized for the user consent view.
[self.unifiedConsentViewController.view.centerXAnchor
constraintEqualToAnchor:self.containerView.centerXAnchor],
[self.unifiedConsentViewController.view.centerYAnchor
constraintEqualToAnchor:self.containerView.centerYAnchor],
// Constraint between the container view and the confirmation button.
[self.confirmationButton.topAnchor
constraintEqualToAnchor:self.containerView.bottomAnchor
constant:kRegularConstants.ButtonVerticalPadding],
]];
// Adding constraints to ensure the user consent view has a limited size
// on iPad. If the screen is bigger than the max size, those constraints
// limit the user consent view.
// If the screen is smaller than the max size, those constraints are ignored
// since they have a lower priority than the constraints set aboved.
NSArray* lowerPriorityConstraints = @[
[self.unifiedConsentViewController.view.heightAnchor
constraintEqualToConstant:kUserConsentMaxSize],
[self.unifiedConsentViewController.view.widthAnchor
constraintEqualToConstant:kUserConsentMaxSize],
];
for (NSLayoutConstraint* constraints in lowerPriorityConstraints) {
// We do not use |UILayoutPriorityDefaultHigh| because it makes some
// multiline labels on one line and truncated on iPad.
constraints.priority = UILayoutPriorityRequired - 1;
}
[constraints addObjectsFromArray:lowerPriorityConstraints];
_regularSizeClassConstraints = constraints;
}
return _regularSizeClassConstraints;
}
#pragma mark - Subviews #pragma mark - Subviews
// Sets up activity indicator properties and adds it to the user sign-in view. // Sets up activity indicator properties and adds it to the user sign-in view.
...@@ -254,9 +379,11 @@ enum AuthenticationButtonType { ...@@ -254,9 +379,11 @@ enum AuthenticationButtonType {
self.unifiedConsentViewController.view self.unifiedConsentViewController.view
.translatesAutoresizingMaskIntoConstraints = NO; .translatesAutoresizingMaskIntoConstraints = NO;
self.containerView = [[UIView alloc] init];
self.containerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.containerView];
[self addChildViewController:self.unifiedConsentViewController]; [self addChildViewController:self.unifiedConsentViewController];
[self.view insertSubview:self.unifiedConsentViewController.view [self.containerView addSubview:self.unifiedConsentViewController.view];
belowSubview:self.confirmationButton];
[self.unifiedConsentViewController didMoveToParentViewController:self]; [self.unifiedConsentViewController didMoveToParentViewController:self];
} }
...@@ -269,9 +396,6 @@ enum AuthenticationButtonType { ...@@ -269,9 +396,6 @@ enum AuthenticationButtonType {
[self addSubviewWithButton:self.confirmationButton]; [self addSubviewWithButton:self.confirmationButton];
// Note that the button style will depend on the user sign-in state. // Note that the button style will depend on the user sign-in state.
[self updatePrimaryButtonStyle]; [self updatePrimaryButtonStyle];
self.confirmationButton.contentEdgeInsets =
UIEdgeInsetsMake(kButtonTitleContentInset, kButtonTitleContentInset,
kButtonTitleContentInset, kButtonTitleContentInset);
} }
// Sets up skip sign-in button properties and adds it to the user sign-in view. // Sets up skip sign-in button properties and adds it to the user sign-in view.
...@@ -286,15 +410,15 @@ enum AuthenticationButtonType { ...@@ -286,15 +410,15 @@ enum AuthenticationButtonType {
[self.skipSigninButton addTarget:self [self.skipSigninButton addTarget:self
action:@selector(onSkipSigninButtonPressed:) action:@selector(onSkipSigninButtonPressed:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
self.skipSigninButton.contentEdgeInsets =
UIEdgeInsetsMake(kButtonTitleContentInset, kButtonTitleContentInset,
kButtonTitleContentInset, kButtonTitleContentInset);
} }
// Sets up button properties and adds it to view. // Sets up button properties and adds it to view.
- (void)addSubviewWithButton:(UIButton*)button { - (void)addSubviewWithButton:(UIButton*)button {
button.titleLabel.font = [button
[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; setContentCompressionResistancePriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisVertical];
[button setContentHuggingPriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisVertical];
[self.view addSubview:button]; [self.view addSubview:button];
button.translatesAutoresizingMaskIntoConstraints = NO; button.translatesAutoresizingMaskIntoConstraints = NO;
} }
...@@ -325,6 +449,19 @@ enum AuthenticationButtonType { ...@@ -325,6 +449,19 @@ enum AuthenticationButtonType {
[self setSkipSigninStylingWithButton:button]; [self setSkipSigninStylingWithButton:button];
} }
// Applies font and inset to |button| according to the current size class.
- (void)applyDefaultSizeWithButton:(UIButton*)button
fontStyle:(UIFontTextStyle)fontStyle {
const AuthenticationViewConstants& constants =
self.authenticationViewConstants;
CGFloat horizontalContentInset = constants.ButtonTitleContentHorizontalInset;
CGFloat verticalContentInset = constants.ButtonTitleContentVerticalInset;
button.contentEdgeInsets =
UIEdgeInsetsMake(verticalContentInset, horizontalContentInset,
verticalContentInset, horizontalContentInset);
button.titleLabel.font = [UIFont preferredFontForTextStyle:fontStyle];
}
#pragma mark - Events #pragma mark - Events
- (void)onSkipSigninButtonPressed:(id)sender { - (void)onSkipSigninButtonPressed:(id)sender {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment