Skip to content

Commit 6e82a76

Browse files
author
Junius Gunaratne
committed
Add menu items and pan gesture recognizer to side view in Pesto demo app
Reviewers: featherless, traviskaufman, ajsecord, #material_components_ios_owners Reviewed By: ajsecord, #material_components_ios_owners Projects: #material_components_ios_owners Differential Revision: http://codereview.cc/D81
1 parent ad7d62b commit 6e82a76

File tree

3 files changed

+216
-9
lines changed

3 files changed

+216
-9
lines changed

demos/Pesto/Pesto/PestoDetailViewController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ - (void)layoutSubviews {
4545

4646
CGFloat lightHeight = 0.5f;
4747
UIView *lineView =
48-
[[UIView alloc] initWithFrame:CGRectMake(0, 0, contentView.bounds.size.width, lightHeight)];
48+
[[UIView alloc] initWithFrame:CGRectMake(0, 0, contentView.bounds.size.width, lightHeight)];
4949
[lineView.heightAnchor constraintEqualToConstant:lightHeight].active = YES;
5050
lineView.backgroundColor = [UIColor lightGrayColor];
5151

demos/Pesto/Pesto/PestoSideView.m

Lines changed: 212 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,196 @@
22

33
#import "MaterialShadowElevations.h"
44
#import "MaterialShadowLayer.h"
5+
#import "MaterialTypography.h"
56

67
static CGFloat kPestoSideViewAnimationDuration = 0.2f;
8+
static CGFloat kPestoSideViewAvatarDim = 64.f;
9+
static CGFloat kPestoSideViewCollectionViewInset = 5.f;
10+
static CGFloat kPestoSideViewHideThreshhold = 64.f;
11+
static CGFloat kPestoSideViewUserItemHeight = 200.f;
712
static CGFloat kPestoSideViewWidth = 240.f;
13+
static NSString *const kPestoSideViewWidthBaseURL =
14+
@"https://www.gstatic.com/angular/material-adaptive/pesto/";
815

9-
@interface PestoSideContentView : UIView
16+
@interface PestoSideViewCollectionViewCell : UICollectionViewCell
17+
18+
@property (nonatomic) NSString *title;
19+
20+
@end
21+
22+
@implementation PestoSideViewCollectionViewCell
23+
24+
- (id)initWithFrame:(CGRect)frame {
25+
self = [super initWithFrame:frame];
26+
if (self) {
27+
28+
}
29+
return self;
30+
}
31+
32+
- (void)layoutSubviews {
33+
[super layoutSubviews];
34+
35+
self.backgroundColor = [UIColor whiteColor];
36+
UILabel *title = [[UILabel alloc] initWithFrame:self.bounds];
37+
title.text = _title;
38+
title.font = [MDCTypography body1Font];
39+
title.textAlignment = NSTextAlignmentCenter;
40+
[self addSubview:title];
41+
}
42+
43+
- (void)prepareForReuse {
44+
[super prepareForReuse];
45+
46+
for (UIView *subview in [self.contentView subviews]) {
47+
[subview removeFromSuperview];
48+
}
49+
}
50+
51+
@end
52+
53+
@interface PestoSideContentView : UIView <UICollectionViewDataSource,
54+
UICollectionViewDelegateFlowLayout>
55+
56+
@property (nonatomic) NSArray *titles;
57+
@property (nonatomic) NSCache *imageCache;
58+
@property (nonatomic) UICollectionView *collectionView;
1059

1160
@end
1261

1362
@implementation PestoSideContentView
1463

64+
- (void)layoutSubviews {
65+
_titles = @[ @"Home", @"Favorite", @"Saved", @"Trending", @"Settings" ];
66+
67+
CGRect avatarRect = CGRectMake(0, 0, kPestoSideViewAvatarDim, kPestoSideViewAvatarDim);
68+
NSString *imageURL = [kPestoSideViewWidthBaseURL stringByAppendingString:@"avatar.jpg"];
69+
UIImageView *avatar = [self imageViewWithURL:imageURL];
70+
avatar.frame = avatarRect;
71+
avatar.layer.cornerRadius = avatar.bounds.size.width / 2.f;
72+
avatar.center = CGPointMake(self.bounds.size.width / 2.f,
73+
kPestoSideViewUserItemHeight / 2.f - 12.f);
74+
avatar.layer.masksToBounds = YES;
75+
[self addSubview:avatar];
76+
77+
CGRect cirlceRect = CGRectMake(-3.f,
78+
-3.f,
79+
kPestoSideViewAvatarDim + 6.f,
80+
kPestoSideViewAvatarDim + 6.f);
81+
UIColor *teal = [UIColor colorWithRed:0 green:0.67f blue:0.55f alpha:1];
82+
UIView *circleView = [[UIView alloc] initWithFrame:avatarRect];
83+
CAShapeLayer *circleLayer = [CAShapeLayer layer];
84+
[circleLayer setPath:[[UIBezierPath bezierPathWithOvalInRect:cirlceRect] CGPath]];
85+
[circleLayer setStrokeColor:teal.CGColor];
86+
[circleLayer setFillColor:[UIColor clearColor].CGColor];
87+
[circleLayer setLineWidth:2.f];
88+
[circleView.layer addSublayer:circleLayer];
89+
circleView.center = avatar.center;
90+
[self addSubview:circleView];
91+
92+
CGRect nameRect = CGRectMake(0,
93+
110.f,
94+
self.bounds.size.width,
95+
kPestoSideViewAvatarDim);
96+
UILabel *name = [[UILabel alloc] initWithFrame:nameRect];
97+
name.text = @"Jonathan";
98+
name.font = [MDCTypography titleFont];
99+
name.textAlignment = NSTextAlignmentCenter;
100+
[self addSubview:name];
101+
102+
CGFloat lightHeight = 0.5f;
103+
UIView *lineView =
104+
[[UIView alloc] initWithFrame:CGRectMake(15.f,
105+
180.f,
106+
self.bounds.size.width - 30.f,
107+
lightHeight)];
108+
[lineView.heightAnchor constraintEqualToConstant:lightHeight].active = YES;
109+
lineView.backgroundColor = [UIColor lightGrayColor];
110+
[self addSubview:lineView];
111+
112+
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
113+
layout.minimumInteritemSpacing = 0;
114+
[layout setSectionInset:UIEdgeInsetsMake(kPestoSideViewCollectionViewInset,
115+
kPestoSideViewCollectionViewInset,
116+
kPestoSideViewCollectionViewInset,
117+
kPestoSideViewCollectionViewInset)];
118+
CGRect collectionViewFrame = CGRectMake(0,
119+
kPestoSideViewUserItemHeight,
120+
self.bounds.size.width,
121+
self.bounds.size.height);
122+
_collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame
123+
collectionViewLayout:layout];
124+
_collectionView.contentSize = _collectionView.bounds.size;
125+
_collectionView.backgroundColor = [UIColor whiteColor];
126+
_collectionView.autoresizingMask =
127+
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
128+
[self addSubview:_collectionView];
129+
[_collectionView registerClass:[PestoSideViewCollectionViewCell class]
130+
forCellWithReuseIdentifier:@"PestoSideViewCollectionViewCell"];
131+
[_collectionView setDataSource:self];
132+
[_collectionView setDelegate:self];
133+
_collectionView.delegate = self;
134+
}
135+
136+
- (UIImageView *)imageViewWithURL:(NSString *)url {
137+
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
138+
dispatch_async(dispatch_get_global_queue(0, 0), ^{
139+
NSData *imageData = [_imageCache objectForKey:url];
140+
if (!imageData) {
141+
imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:url]];
142+
[_imageCache setObject:imageData forKey:url];
143+
}
144+
if (imageData == nil) {
145+
return;
146+
}
147+
dispatch_async(dispatch_get_main_queue(), ^{
148+
UIImage *image = [UIImage imageWithData:imageData];
149+
imageView.image = image;
150+
});
151+
});
152+
return imageView;
153+
}
154+
15155
+ (Class)layerClass {
16156
return [MDCShadowLayer class];
17157
}
18158

159+
# pragma mark - UICollectionViewDataSource
160+
161+
- (NSInteger)collectionView:(UICollectionView *)collectionView
162+
numberOfItemsInSection:(NSInteger)section {
163+
return _titles.count;
164+
}
165+
166+
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
167+
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
168+
PestoSideViewCollectionViewCell *cell =
169+
[collectionView dequeueReusableCellWithReuseIdentifier:@"PestoSideViewCollectionViewCell"
170+
forIndexPath:indexPath];
171+
NSInteger itemNum = indexPath.row;
172+
cell.title = _titles[itemNum];
173+
[cell setNeedsLayout];
174+
return cell;
175+
}
176+
177+
- (void)collectionView:(UICollectionView *)collectionView
178+
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
179+
}
180+
181+
# pragma mark - UICollectionViewDelegateFlowLayout
182+
183+
- (CGSize)collectionView:(UICollectionView *)collectionView
184+
layout:(UICollectionViewLayout*)collectionViewLayout
185+
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
186+
return CGSizeMake(collectionView.bounds.size.width, 40.f);
187+
}
188+
19189
@end
20190

21-
@interface PestoSideView ()
191+
@interface PestoSideView () <UIGestureRecognizerDelegate>
22192

193+
@property (nonatomic) CGFloat xDelta;
194+
@property (nonatomic) CGFloat xStart;
23195
@property (nonatomic) PestoSideContentView *contentView;
24196
@property (nonatomic) UIButton *dismissButton;
25197

@@ -36,10 +208,16 @@ - (id)initWithFrame:(CGRect)frame {
36208
_contentView.backgroundColor = [UIColor whiteColor];
37209
[self addSubview:_contentView];
38210

39-
UITapGestureRecognizer *tap =
211+
UITapGestureRecognizer *tapRecognizer =
40212
[[UITapGestureRecognizer alloc] initWithTarget:self
41213
action:@selector(hideSideView)];
42-
[self addGestureRecognizer:tap];
214+
[self addGestureRecognizer:tapRecognizer];
215+
UIPanGestureRecognizer *panRecognizer =
216+
[[UIPanGestureRecognizer alloc] initWithTarget:self
217+
action:@selector(panGestureRecognized:)];
218+
panRecognizer.minimumNumberOfTouches = 1;
219+
panRecognizer.delegate = self;
220+
[self addGestureRecognizer:panRecognizer];
43221
}
44222
return self;
45223
}
@@ -72,6 +250,36 @@ - (void)hideSideView {
72250
}];
73251
}
74252

253+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
254+
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
255+
return YES;
256+
}
257+
258+
- (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer {
259+
CGPoint tappedPoint = [recognizer locationInView:self];
260+
CGFloat xCoordinate = tappedPoint.x;
261+
switch (recognizer.state) {
262+
case UIGestureRecognizerStateBegan:
263+
_xStart = xCoordinate;
264+
break;
265+
case UIGestureRecognizerStateChanged:
266+
_xDelta = kPestoSideViewWidth - (_xStart - xCoordinate);
267+
if (_xDelta > kPestoSideViewWidth) {
268+
_xDelta = kPestoSideViewWidth;
269+
}
270+
_contentView.transform = CGAffineTransformMakeTranslation(_xDelta, 0);
271+
break;
272+
case UIGestureRecognizerStateEnded:
273+
if (_xDelta > kPestoSideViewWidth - kPestoSideViewHideThreshhold) {
274+
[self showSideView];
275+
} else {
276+
[self hideSideView];
277+
}
278+
default:
279+
break;
280+
}
281+
}
282+
75283
+ (CGAffineTransform)showTransform {
76284
return CGAffineTransformMakeTranslation(kPestoSideViewWidth, 0);
77285
}

demos/Pesto/Pesto/PestoViewController.m

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
#import "MaterialShadowElevations.h"
99
#import "MaterialShadowLayer.h"
1010
#import "MaterialSpritedAnimationView.h"
11-
#import "MaterialTypography.h"
1211

1312
static CGFloat kPestoViewControllerAnimationDuration = 0.33f;
1413
static CGFloat kPestoViewControllerDefaultHeaderHeight = 240.f;
1514
static CGFloat kPestoViewControllerInset = 5.f;
1615
static CGFloat kPestoViewControllerSmallHeaderHeight = 100.f;
1716
static NSString *const kPestoDetailViewControllerBackMenu = @"mdc_sprite_menu__arrow_back";
1817
static NSString *const kPestoDetailViewControllerMenuBack = @"mdc_sprite_arrow_back__menu";
18+
static NSString *const kPestoDetailViewControllerBaseURL =
19+
@"https://www.gstatic.com/angular/material-adaptive/pesto/";
1920

2021
@interface PestoHeaderView : UIView
2122

@@ -68,7 +69,6 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
6869
}
6970

7071
- (void)setupData {
71-
_baseURL = @"https://www.gstatic.com/angular/material-adaptive/pesto/";
7272
_images = @[ @"image2-01.png",
7373
@"blue-potato.jpg",
7474
@"image1-01.png",
@@ -164,7 +164,6 @@ - (void)viewDidLoad {
164164
self.cellSize = CGSizeMake(cellDim, cellDim);
165165

166166
UIColor *teal = [UIColor colorWithRed:0 green:0.67f blue:0.55f alpha:1];
167-
168167
_initialCollectionViewHeight =
169168
self.view.frame.size.height - kPestoViewControllerDefaultHeaderHeight;
170169

@@ -367,7 +366,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
367366
forIndexPath:indexPath];
368367

369368
NSInteger itemNum = indexPath.row;
370-
NSString *imageURL = [_baseURL stringByAppendingString:_images[itemNum]];
369+
NSString *imageURL = [kPestoDetailViewControllerBaseURL stringByAppendingString:_images[itemNum]];
371370
cell.title = _titles[itemNum];
372371
cell.author = _authors[itemNum];
373372
cell.imageURL = imageURL;

0 commit comments

Comments
 (0)