OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/util/transparent_link_button.h" |
| 6 |
| 7 #include "base/ios/ios_util.h" |
| 8 #import "base/ios/weak_nsobject.h" |
| 9 #import "base/logging.h" |
| 10 #import "base/mac/scoped_nsobject.h" |
| 11 #import "base/strings/sys_string_conversions.h" |
| 12 #include "url/gurl.h" |
| 13 |
| 14 // Minimum tap area dimension, as specified by Apple guidelines. |
| 15 const CGFloat kLinkTapAreaMinimum = 44.0; |
| 16 |
| 17 namespace { |
| 18 // The corner radius of the highlight view. |
| 19 const CGFloat kHighlightViewCornerRadius = 2.0; |
| 20 // The alpha of the highlight view's background color (base color is black). |
| 21 const CGFloat kHighlightViewBackgroundAlpha = 0.25; |
| 22 } |
| 23 |
| 24 @interface TransparentLinkButton () { |
| 25 // Backing objects for properties of the same name. |
| 26 base::scoped_nsobject<UIView> _highlightView; |
| 27 base::WeakNSObject<TransparentLinkButton> _previousLinkButton; |
| 28 base::WeakNSObject<TransparentLinkButton> _nextLinkButton; |
| 29 } |
| 30 |
| 31 // The link frame passed upon initialization. |
| 32 @property(nonatomic, readonly) CGRect linkFrame; |
| 33 |
| 34 // Semi-transparent overlay that is shown to highlight the link text when the |
| 35 // button's highlight state is set to YES. |
| 36 @property(nonatomic, readonly) UIView* highlightView; |
| 37 |
| 38 // Links that span multiple lines require more than one TransparentLinkButton. |
| 39 // These properties are used to populate the highlight state from one button to |
| 40 // the other buttons corresponding with the same link. |
| 41 @property(nonatomic, weak) TransparentLinkButton* previousLinkButton; |
| 42 @property(nonatomic, weak) TransparentLinkButton* nextLinkButton; |
| 43 |
| 44 // Designated initializer. |linkFrame| is the frame of the link text; this may |
| 45 // differ from the actual frame of the resulting TransparentLinkButton, which is |
| 46 // guaranteed to be at least |kLinkTapAreaMinimum| in each dimension. |URL| is |
| 47 // the URL for the associated link. |
| 48 - (instancetype)initWithLinkFrame:(CGRect)linkFrame |
| 49 URL:(const GURL&)URL NS_DESIGNATED_INITIALIZER; |
| 50 |
| 51 // Sets the properties, propogating state to its adjacent link buttons. |
| 52 // |sender| is the TransparentLinkButon whose state is being propogated to |
| 53 // |self|. |
| 54 - (void)setHighlighted:(BOOL)highlighted sender:(TransparentLinkButton*)sender; |
| 55 - (void)setSelected:(BOOL)selected sender:(TransparentLinkButton*)sender; |
| 56 |
| 57 // Updates the appearance of |highlightView| based on highlighted/selected |
| 58 // state. |
| 59 - (void)updateHighlightView; |
| 60 |
| 61 @end |
| 62 |
| 63 @implementation TransparentLinkButton |
| 64 |
| 65 @synthesize URL = _URL; |
| 66 @synthesize debug = _debug; |
| 67 @synthesize linkFrame = _linkFrame; |
| 68 |
| 69 - (instancetype)initWithLinkFrame:(CGRect)linkFrame URL:(const GURL&)URL { |
| 70 CGFloat linkHeightExpansion = |
| 71 MAX(0, (kLinkTapAreaMinimum - linkFrame.size.height) / 2.0); |
| 72 CGFloat linkWidthExpansion = |
| 73 MAX(0, (kLinkTapAreaMinimum - linkFrame.size.width) / 2.0); |
| 74 // Expand the frame as necessary to meet the minimum tap area dimensions. |
| 75 CGRect frame = |
| 76 CGRectInset(linkFrame, -linkWidthExpansion, -linkHeightExpansion); |
| 77 if ((self = [super initWithFrame:frame])) { |
| 78 DCHECK(URL.is_valid()); |
| 79 self.contentEdgeInsets = |
| 80 UIEdgeInsetsMake(linkHeightExpansion, linkWidthExpansion, |
| 81 linkHeightExpansion, linkWidthExpansion); |
| 82 self.backgroundColor = [UIColor clearColor]; |
| 83 _linkFrame = linkFrame; |
| 84 _URL = URL; |
| 85 // These buttons are positioned absolutely based on the the position of |
| 86 // regions of text that is already correctly aligned for RTL if necessary. |
| 87 self.semanticContentAttribute = UISemanticContentAttributeSpatial; |
| 88 } |
| 89 return self; |
| 90 } |
| 91 |
| 92 #pragma mark - Accessors |
| 93 |
| 94 - (void)setPreviousLinkButton:(TransparentLinkButton*)previousLinkButton { |
| 95 _previousLinkButton.reset(previousLinkButton); |
| 96 } |
| 97 |
| 98 - (TransparentLinkButton*)previousLinkButton { |
| 99 return _previousLinkButton.get(); |
| 100 } |
| 101 |
| 102 - (void)setNextLinkButton:(TransparentLinkButton*)nextLinkButton { |
| 103 _nextLinkButton.reset(nextLinkButton); |
| 104 } |
| 105 |
| 106 - (TransparentLinkButton*)nextLinkButton { |
| 107 return _nextLinkButton.get(); |
| 108 } |
| 109 |
| 110 - (void)setDebug:(BOOL)debug { |
| 111 _debug = debug; |
| 112 self.layer.borderWidth = _debug ? 1.0 : 0.0; |
| 113 self.layer.borderColor = |
| 114 _debug ? [UIColor greenColor].CGColor : [UIColor clearColor].CGColor; |
| 115 self.backgroundColor = _debug ? [UIColor redColor] : [UIColor clearColor]; |
| 116 self.alpha = _debug ? 0.15 : 1.0; |
| 117 } |
| 118 |
| 119 - (UIView*)highlightView { |
| 120 if (!_highlightView) { |
| 121 CGRect linkFrame = |
| 122 [self convertRect:self.linkFrame fromView:self.superview]; |
| 123 linkFrame = CGRectInset(linkFrame, -kHighlightViewCornerRadius, 0); |
| 124 _highlightView.reset([[UIView alloc] initWithFrame:linkFrame]); |
| 125 [_highlightView |
| 126 setBackgroundColor:[UIColor |
| 127 colorWithWhite:0.0 |
| 128 alpha:kHighlightViewBackgroundAlpha]]; |
| 129 [_highlightView layer].cornerRadius = kHighlightViewCornerRadius; |
| 130 [_highlightView setClipsToBounds:YES]; |
| 131 [self addSubview:_highlightView]; |
| 132 } |
| 133 return _highlightView.get(); |
| 134 } |
| 135 |
| 136 - (void)setHighlighted:(BOOL)highlighted { |
| 137 [self setHighlighted:highlighted sender:nil]; |
| 138 } |
| 139 |
| 140 - (void)setSelected:(BOOL)selected { |
| 141 [self setSelected:selected sender:nil]; |
| 142 } |
| 143 |
| 144 #pragma mark - |
| 145 |
| 146 + (NSArray*)buttonsForLinkFrames:(NSArray*)linkFrames |
| 147 URL:(const GURL&)URL |
| 148 accessibilityLabel:(NSString*)label { |
| 149 if (!linkFrames.count) |
| 150 return @[]; |
| 151 base::scoped_nsobject<NSMutableArray> buttons( |
| 152 [[NSMutableArray alloc] initWithCapacity:linkFrames.count]); |
| 153 for (NSValue* linkFrameValue in linkFrames) { |
| 154 CGRect linkFrame = [linkFrameValue CGRectValue]; |
| 155 base::scoped_nsobject<TransparentLinkButton> button( |
| 156 [[TransparentLinkButton alloc] initWithLinkFrame:linkFrame URL:URL]); |
| 157 TransparentLinkButton* previousButton = [buttons lastObject]; |
| 158 previousButton.nextLinkButton = button; |
| 159 [button setPreviousLinkButton:previousButton]; |
| 160 // Make buttons not accessible by default, but provide label for tests. |
| 161 [button setIsAccessibilityElement:NO]; |
| 162 [button setAccessibilityLabel:label]; |
| 163 [buttons addObject:button]; |
| 164 } |
| 165 // Make the first button accessible. |
| 166 [buttons[0] setIsAccessibilityElement:YES]; |
| 167 return [NSArray arrayWithArray:buttons]; |
| 168 } |
| 169 |
| 170 - (void)setHighlighted:(BOOL)highlighted sender:(TransparentLinkButton*)sender { |
| 171 [super setHighlighted:highlighted]; |
| 172 if (self.previousLinkButton != sender) |
| 173 [self.previousLinkButton setHighlighted:highlighted sender:self]; |
| 174 if (self.nextLinkButton != sender) |
| 175 [self.nextLinkButton setHighlighted:highlighted sender:self]; |
| 176 [self updateHighlightView]; |
| 177 } |
| 178 |
| 179 - (void)setSelected:(BOOL)selected sender:(TransparentLinkButton*)sender { |
| 180 [super setSelected:selected]; |
| 181 if (self.previousLinkButton != sender) |
| 182 [self.previousLinkButton setSelected:selected sender:self]; |
| 183 if (self.nextLinkButton != sender) |
| 184 [self.nextLinkButton setSelected:selected sender:self]; |
| 185 [self updateHighlightView]; |
| 186 } |
| 187 |
| 188 - (void)updateHighlightView { |
| 189 self.highlightView.hidden = !self.highlighted && !self.selected; |
| 190 } |
| 191 |
| 192 @end |
OLD | NEW |