| Index: ios/chrome/browser/ui/util/transparent_link_button.mm
|
| diff --git a/ios/chrome/browser/ui/util/transparent_link_button.mm b/ios/chrome/browser/ui/util/transparent_link_button.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b0cb2f9da676ce76e202099a93f4f7ef1146644d
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/util/transparent_link_button.mm
|
| @@ -0,0 +1,192 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import "ios/chrome/browser/ui/util/transparent_link_button.h"
|
| +
|
| +#include "base/ios/ios_util.h"
|
| +#import "base/ios/weak_nsobject.h"
|
| +#import "base/logging.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#import "base/strings/sys_string_conversions.h"
|
| +#include "url/gurl.h"
|
| +
|
| +// Minimum tap area dimension, as specified by Apple guidelines.
|
| +const CGFloat kLinkTapAreaMinimum = 44.0;
|
| +
|
| +namespace {
|
| +// The corner radius of the highlight view.
|
| +const CGFloat kHighlightViewCornerRadius = 2.0;
|
| +// The alpha of the highlight view's background color (base color is black).
|
| +const CGFloat kHighlightViewBackgroundAlpha = 0.25;
|
| +}
|
| +
|
| +@interface TransparentLinkButton () {
|
| + // Backing objects for properties of the same name.
|
| + base::scoped_nsobject<UIView> _highlightView;
|
| + base::WeakNSObject<TransparentLinkButton> _previousLinkButton;
|
| + base::WeakNSObject<TransparentLinkButton> _nextLinkButton;
|
| +}
|
| +
|
| +// The link frame passed upon initialization.
|
| +@property(nonatomic, readonly) CGRect linkFrame;
|
| +
|
| +// Semi-transparent overlay that is shown to highlight the link text when the
|
| +// button's highlight state is set to YES.
|
| +@property(nonatomic, readonly) UIView* highlightView;
|
| +
|
| +// Links that span multiple lines require more than one TransparentLinkButton.
|
| +// These properties are used to populate the highlight state from one button to
|
| +// the other buttons corresponding with the same link.
|
| +@property(nonatomic, weak) TransparentLinkButton* previousLinkButton;
|
| +@property(nonatomic, weak) TransparentLinkButton* nextLinkButton;
|
| +
|
| +// Designated initializer. |linkFrame| is the frame of the link text; this may
|
| +// differ from the actual frame of the resulting TransparentLinkButton, which is
|
| +// guaranteed to be at least |kLinkTapAreaMinimum| in each dimension. |URL| is
|
| +// the URL for the associated link.
|
| +- (instancetype)initWithLinkFrame:(CGRect)linkFrame
|
| + URL:(const GURL&)URL NS_DESIGNATED_INITIALIZER;
|
| +
|
| +// Sets the properties, propogating state to its adjacent link buttons.
|
| +// |sender| is the TransparentLinkButon whose state is being propogated to
|
| +// |self|.
|
| +- (void)setHighlighted:(BOOL)highlighted sender:(TransparentLinkButton*)sender;
|
| +- (void)setSelected:(BOOL)selected sender:(TransparentLinkButton*)sender;
|
| +
|
| +// Updates the appearance of |highlightView| based on highlighted/selected
|
| +// state.
|
| +- (void)updateHighlightView;
|
| +
|
| +@end
|
| +
|
| +@implementation TransparentLinkButton
|
| +
|
| +@synthesize URL = _URL;
|
| +@synthesize debug = _debug;
|
| +@synthesize linkFrame = _linkFrame;
|
| +
|
| +- (instancetype)initWithLinkFrame:(CGRect)linkFrame URL:(const GURL&)URL {
|
| + CGFloat linkHeightExpansion =
|
| + MAX(0, (kLinkTapAreaMinimum - linkFrame.size.height) / 2.0);
|
| + CGFloat linkWidthExpansion =
|
| + MAX(0, (kLinkTapAreaMinimum - linkFrame.size.width) / 2.0);
|
| + // Expand the frame as necessary to meet the minimum tap area dimensions.
|
| + CGRect frame =
|
| + CGRectInset(linkFrame, -linkWidthExpansion, -linkHeightExpansion);
|
| + if ((self = [super initWithFrame:frame])) {
|
| + DCHECK(URL.is_valid());
|
| + self.contentEdgeInsets =
|
| + UIEdgeInsetsMake(linkHeightExpansion, linkWidthExpansion,
|
| + linkHeightExpansion, linkWidthExpansion);
|
| + self.backgroundColor = [UIColor clearColor];
|
| + _linkFrame = linkFrame;
|
| + _URL = URL;
|
| + // These buttons are positioned absolutely based on the the position of
|
| + // regions of text that is already correctly aligned for RTL if necessary.
|
| + self.semanticContentAttribute = UISemanticContentAttributeSpatial;
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +#pragma mark - Accessors
|
| +
|
| +- (void)setPreviousLinkButton:(TransparentLinkButton*)previousLinkButton {
|
| + _previousLinkButton.reset(previousLinkButton);
|
| +}
|
| +
|
| +- (TransparentLinkButton*)previousLinkButton {
|
| + return _previousLinkButton.get();
|
| +}
|
| +
|
| +- (void)setNextLinkButton:(TransparentLinkButton*)nextLinkButton {
|
| + _nextLinkButton.reset(nextLinkButton);
|
| +}
|
| +
|
| +- (TransparentLinkButton*)nextLinkButton {
|
| + return _nextLinkButton.get();
|
| +}
|
| +
|
| +- (void)setDebug:(BOOL)debug {
|
| + _debug = debug;
|
| + self.layer.borderWidth = _debug ? 1.0 : 0.0;
|
| + self.layer.borderColor =
|
| + _debug ? [UIColor greenColor].CGColor : [UIColor clearColor].CGColor;
|
| + self.backgroundColor = _debug ? [UIColor redColor] : [UIColor clearColor];
|
| + self.alpha = _debug ? 0.15 : 1.0;
|
| +}
|
| +
|
| +- (UIView*)highlightView {
|
| + if (!_highlightView) {
|
| + CGRect linkFrame =
|
| + [self convertRect:self.linkFrame fromView:self.superview];
|
| + linkFrame = CGRectInset(linkFrame, -kHighlightViewCornerRadius, 0);
|
| + _highlightView.reset([[UIView alloc] initWithFrame:linkFrame]);
|
| + [_highlightView
|
| + setBackgroundColor:[UIColor
|
| + colorWithWhite:0.0
|
| + alpha:kHighlightViewBackgroundAlpha]];
|
| + [_highlightView layer].cornerRadius = kHighlightViewCornerRadius;
|
| + [_highlightView setClipsToBounds:YES];
|
| + [self addSubview:_highlightView];
|
| + }
|
| + return _highlightView.get();
|
| +}
|
| +
|
| +- (void)setHighlighted:(BOOL)highlighted {
|
| + [self setHighlighted:highlighted sender:nil];
|
| +}
|
| +
|
| +- (void)setSelected:(BOOL)selected {
|
| + [self setSelected:selected sender:nil];
|
| +}
|
| +
|
| +#pragma mark -
|
| +
|
| ++ (NSArray*)buttonsForLinkFrames:(NSArray*)linkFrames
|
| + URL:(const GURL&)URL
|
| + accessibilityLabel:(NSString*)label {
|
| + if (!linkFrames.count)
|
| + return @[];
|
| + base::scoped_nsobject<NSMutableArray> buttons(
|
| + [[NSMutableArray alloc] initWithCapacity:linkFrames.count]);
|
| + for (NSValue* linkFrameValue in linkFrames) {
|
| + CGRect linkFrame = [linkFrameValue CGRectValue];
|
| + base::scoped_nsobject<TransparentLinkButton> button(
|
| + [[TransparentLinkButton alloc] initWithLinkFrame:linkFrame URL:URL]);
|
| + TransparentLinkButton* previousButton = [buttons lastObject];
|
| + previousButton.nextLinkButton = button;
|
| + [button setPreviousLinkButton:previousButton];
|
| + // Make buttons not accessible by default, but provide label for tests.
|
| + [button setIsAccessibilityElement:NO];
|
| + [button setAccessibilityLabel:label];
|
| + [buttons addObject:button];
|
| + }
|
| + // Make the first button accessible.
|
| + [buttons[0] setIsAccessibilityElement:YES];
|
| + return [NSArray arrayWithArray:buttons];
|
| +}
|
| +
|
| +- (void)setHighlighted:(BOOL)highlighted sender:(TransparentLinkButton*)sender {
|
| + [super setHighlighted:highlighted];
|
| + if (self.previousLinkButton != sender)
|
| + [self.previousLinkButton setHighlighted:highlighted sender:self];
|
| + if (self.nextLinkButton != sender)
|
| + [self.nextLinkButton setHighlighted:highlighted sender:self];
|
| + [self updateHighlightView];
|
| +}
|
| +
|
| +- (void)setSelected:(BOOL)selected sender:(TransparentLinkButton*)sender {
|
| + [super setSelected:selected];
|
| + if (self.previousLinkButton != sender)
|
| + [self.previousLinkButton setSelected:selected sender:self];
|
| + if (self.nextLinkButton != sender)
|
| + [self.nextLinkButton setSelected:selected sender:self];
|
| + [self updateHighlightView];
|
| +}
|
| +
|
| +- (void)updateHighlightView {
|
| + self.highlightView.hidden = !self.highlighted && !self.selected;
|
| +}
|
| +
|
| +@end
|
|
|