网易新闻侧滑抽屉效果(利用父子控制器实现)

一:类似于网易的抽屉效果,启动有广告,进入主界面后,点击左上角按钮,侧滑左抽屉,点击右上角,侧滑出右抽屉。点击左抽屉按钮,对视图进行切换

 

 二代码:

1:启动图展示广告界面实现:先吧启动图控制器作为窗口的根视图控制器,展示完广告消失后,再切换窗口的根视图控制器为主控制器。其中窗口指的是项目中的主窗口也就是keyWindow,主窗口主要负责接收一些键盘事件,文本框输入事件,若是键盘文本框,textView或是textfield不能输入,则考虑是不是当前窗口是否是主窗口

@interface HMAdViewController ()

@end

@implementation HMAdViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.背景图片
    UIImageView *bg = [[UIImageView alloc] init];
    bg.image = [UIImage imageNamed:@"Default"];
    bg.frame = self.view.bounds;
    [self.view addSubview:bg];
    
    // 2.广告图片(真实的广告图片应该要先下载广告图片)
    UIImageView *ad = [[UIImageView alloc] init];
    ad.image = [UIImage imageNamed:@"ad"];
    ad.width = 280;
    ad.height = 300;
    ad.centerX = self.view.width * 0.5;
    ad.y = 60;
    [self.view addSubview:ad];
    
    // 3.2s后调到下一个主界面
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        UIWindow *window = [UIApplication sharedApplication].keyWindow;
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"Main"];
    });
}

@end

2:当启动图广告界面展示完毕后,切换窗口根视图控制器。

  1 #import "HMMainViewController.h"
  2 #import "HMLeftMenu.h"
  3 #import "HMRightMenuController.h"
  4 #import "HMNavigationController.h"
  5 #import "HMNewsViewController.h"
  6 #import "HMReadingViewController.h"
  7 #import "HMTitleView.h"
  8 
  9 #define HMNavShowAnimDuration 0.25
 10 #define HMCoverTag 100
 11 #define HMLeftMenuW 150
 12 #define HMLeftMenuH 300
 13 #define HMLeftMenuY 50
 14 
 15 @interface HMMainViewController () <HMLeftMenuDelegate>
 16 /**
 17  *  正在显示的导航控制器
 18  */
 19 @property (nonatomic, weak) HMNavigationController *showingNavigationController;
 20 @property (nonatomic, strong) HMRightMenuController *rightMenuVc;
 21 @property (nonatomic, weak) HMLeftMenu *leftMenu;
 22 @end
 23 
 24 @implementation HMMainViewController
 25 
 26 - (void)viewDidLoad
 27 {
 28     [super viewDidLoad];
 29     
 30     // 1.创建子控制器
 31     [self setupAllChildVcs];
 32     
 33     // 2.添加左菜单
 34     [self setupLeftMenu];
 35     
 36     // 3.添加右菜单
 37     [self setupRightMenu];
 38 }
 39 
 40 
 41 /**
 42  *  添加右菜单
 43  */
 44 - (void)setupRightMenu
 45 {
 46     HMRightMenuController *rightMenuVc = [[HMRightMenuController alloc] init];
 47     rightMenuVc.view.x = self.view.width - rightMenuVc.view.width;
 48     [self.view insertSubview:rightMenuVc.view atIndex:1];
 49     self.rightMenuVc = rightMenuVc;
 50 }
 51 
 52 /**
 53  *  添加左菜单
 54  */
 55 - (void)setupLeftMenu
 56 {
 57     HMLeftMenu *leftMenu = [[HMLeftMenu alloc] init];
 58     leftMenu.delegate = self;
 59     leftMenu.height = HMLeftMenuH;
 60     leftMenu.width = HMLeftMenuW;
 61     leftMenu.y = HMLeftMenuY;
 62     [self.view insertSubview:leftMenu atIndex:1];
 63     self.leftMenu = leftMenu;
 64 }
 65 
 66 /**
 67  *  创建子控制器
 68  */
 69 - (void)setupAllChildVcs
 70 {
 71     // 1.新闻控制器
 72     HMNewsViewController *news = [[HMNewsViewController alloc] init];
 73     [self setupVc:news title:@"新闻"];
 74     
 75     // 2.订阅控制器
 76     HMReadingViewController *reading = [[HMReadingViewController alloc] init];
 77     [self setupVc:reading title:@"订阅"];
 78     
 79     // 3.图片控制器
 80     UIViewController *photo = [[UIViewController alloc] init];
 81     [self setupVc:photo title:@"图片"];
 82     
 83     // 4.视频控制器
 84     UIViewController *video = [[UIViewController alloc] init];
 85     [self setupVc:video title:@"视频"];
 86     
 87     // 5.跟帖控制器
 88     UIViewController *comment = [[UIViewController alloc] init];
 89     [self setupVc:comment title:@"跟帖"];
 90     
 91     // 6.电台控制器
 92     UIViewController *radio = [[UIViewController alloc] init];
 93     [self setupVc:radio title:@"电台"];
 94 }
 95 
 96 - (UIStatusBarStyle)preferredStatusBarStyle
 97 {
 98     return UIStatusBarStyleLightContent;
 99 }
100 
101 /**
102  *  初始化一个控制器
103  *
104  *  @param vc      需要初始化的控制器
105  *  @param title   控制器的标题
106  */
107 - (void)setupVc:(UIViewController *)vc title:(NSString *)title
108 {
109     // 1.设置背景色
110     vc.view.backgroundColor = HMRandomColor;
111     
112     // 2.设置标题
113     HMTitleView *titleView = [[HMTitleView alloc] init];
114     titleView.title = title;
115     vc.navigationItem.titleView = titleView;
116     
117     // 3.设置左右按钮
118     vc.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"top_navigation_menuicon" target:self action:@selector(leftMenuClick)];
119     vc.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"top_navigation_infoicon" target:self action:@selector(rightMenuClick)];
120     
121     // 4.包装一个导航控制器
122     HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:vc];
123     // 让newsNav成为self(HMMainViewController)的子控制器,能保证:self在,newsNav就在
124     // 如果两个控制器互为父子关系,那么它们的view也应该互为父子关系
125     [self addChildViewController:nav];
126 }
127 
128 #pragma mark - 监听导航栏按钮点击
129 - (void)leftMenuClick
130 {
131     self.leftMenu.hidden = NO;
132     self.rightMenuVc.view.hidden = YES;
133     
134     [UIView animateWithDuration:HMNavShowAnimDuration animations:^{
135         // 取出正在显示的导航控制器的view
136         UIView *showingView = self.showingNavigationController.view;
137         
138         // 缩放比例
139         CGFloat navH = [UIScreen mainScreen].bounds.size.height - 2 * HMLeftMenuY;
140         CGFloat scale = navH / [UIScreen mainScreen].bounds.size.height;
141         
142         // 菜单左边的间距
143         CGFloat leftMenuMargin = [UIScreen mainScreen].bounds.size.width * (1 - scale) * 0.5;
144         CGFloat translateX = HMLeftMenuW - leftMenuMargin;
145         
146         CGFloat topMargin = [UIScreen mainScreen].bounds.size.height * (1 - scale) * 0.5;
147         CGFloat translateY = HMLeftMenuY - topMargin;
148         
149         // 缩放
150         CGAffineTransform scaleForm = CGAffineTransformMakeScale(scale, scale);
151         // 平移
152         CGAffineTransform translateForm = CGAffineTransformTranslate(scaleForm, translateX / scale, translateY / scale);
153         
154         showingView.transform = translateForm;
155         
156         // 添加一个遮盖
157         UIButton *cover = [[UIButton alloc] init];
158         cover.tag = HMCoverTag;
159         [cover addTarget:self action:@selector(coverClick:) forControlEvents:UIControlEventTouchUpInside];
160         cover.frame = showingView.bounds;
161         [showingView addSubview:cover];
162     }];
163 }
164 
165 - (void)coverClick:(UIView *)cover
166 {
167     [UIView animateWithDuration:HMNavShowAnimDuration animations:^{
168         self.showingNavigationController.view.transform = CGAffineTransformIdentity;
169     } completion:^(BOOL finished) {
170         [cover removeFromSuperview];
171     }];
172 }
173 
174 - (void)rightMenuClick
175 {
176     self.leftMenu.hidden = YES;
177     self.rightMenuVc.view.hidden = NO;
178     
179     [UIView animateWithDuration:HMNavShowAnimDuration animations:^{
180         // 取出正在显示的导航控制器的view
181         UIView *showingView = self.showingNavigationController.view;
182         
183         // 缩放比例
184         CGFloat navH = [UIScreen mainScreen].bounds.size.height - 2 * HMLeftMenuY;
185         CGFloat scale = navH / [UIScreen mainScreen].bounds.size.height;
186         
187         // 菜单左边的间距
188         CGFloat leftMenuMargin = [UIScreen mainScreen].bounds.size.width * (1 - scale) * 0.5;
189         CGFloat translateX = leftMenuMargin - self.rightMenuVc.view.width;
190         
191         CGFloat topMargin = [UIScreen mainScreen].bounds.size.height * (1 - scale) * 0.5;
192         CGFloat translateY = HMLeftMenuY - topMargin;
193         
194         // 缩放
195         CGAffineTransform scaleForm = CGAffineTransformMakeScale(scale, scale);
196         // 平移
197         CGAffineTransform translateForm = CGAffineTransformTranslate(scaleForm, translateX / scale, translateY / scale);
198         
199         showingView.transform = translateForm;
200         
201         // 添加一个遮盖
202         UIButton *cover = [[UIButton alloc] init];
203         cover.tag = HMCoverTag;
204         [cover addTarget:self action:@selector(coverClick:) forControlEvents:UIControlEventTouchUpInside];
205         cover.frame = showingView.bounds;
206         [showingView addSubview:cover];
207     } completion:^(BOOL finished) {
208         [self.rightMenuVc didShow];
209     }];
210 }
211 
212 #pragma mark - HMLeftMenuDelegate
213 - (void)leftMenu:(HMLeftMenu *)menu didSelectedButtonFromIndex:(int)fromIndex toIndex:(int)toIndex
214 {
215     // 0.移除旧控制器的view
216     HMNavigationController *oldNav = self.childViewControllers[fromIndex];
217     [oldNav.view removeFromSuperview];
218     
219     // 1.显示新控制器的view
220     HMNavigationController *newNav = self.childViewControllers[toIndex];
221     [self.view addSubview:newNav.view];
222     
223     // 2.设置新控制的transform跟旧控制器一样
224     newNav.view.transform = oldNav.view.transform;
225     // 设置阴影
226     newNav.view.layer.shadowColor = [UIColor blackColor].CGColor;
227     newNav.view.layer.shadowOffset = CGSizeMake(-3, 0);
228     newNav.view.layer.shadowOpacity = 0.2;
229     
230     // 一个导航控制器的view第一次显示到它的父控件上时,如果transform的缩放值被改了,上面的20高度当时是不会出来
231     
232     // 2.设置当前正在显示的控制器
233     self.showingNavigationController = newNav;
234     
235     // 3.点击遮盖
236     [self coverClick:[newNav.view viewWithTag:HMCoverTag]];
237 }
238 @end

3:封装NAV导航控制器

 1 #import "HMNavigationController.h"
 2 #import "HMNavigationBar.h"
 3 
 4 @interface HMNavigationController ()
 5 
 6 @end
 7 
 8 @implementation HMNavigationController
 9 
10 + (void)initialize
11 {
12     UINavigationBar *appearance = [UINavigationBar appearance];
13     
14     // 设置导航栏背景
15     [appearance setBackgroundImage:[UIImage imageNamed:@"top_navigation_background"] forBarMetrics:UIBarMetricsDefault];
16 }
17 
18 - (void)viewDidLoad
19 {
20     [super viewDidLoad];
21     
22     // 替换为自定义的导航栏
23     [self setValue:[[HMNavigationBar alloc] init] forKeyPath:@"navigationBar"];
24 }
25 
26 #pragma mark - 这个方法也是专门用来布局子控件(当控制器的view尺寸发生改变的时候会调用)
27 //- (void)viewDidLayoutSubviews
28 //{
29 //    [super viewDidLayoutSubviews];
30 //    
31 //    for (UIButton *button in self.navigationBar.subviews) {
32 //        if (![button isKindOfClass:[UIButton class]]) continue;
33 //
34 //        if (button.centerX < self.navigationBar.width * 0.5) { // 左边的按钮
35 //            button.x = 0;
36 //        } else if (button.centerX > self.navigationBar.width * 0.5) { // 右边的按钮
37 //            button.x = self.view.width - button.width;
38 //        }
39 //    }
40 //}
41 
42 @end

4:封装导航栏:目的是调整导航栏上左右item距离边框的位置.。左右按钮的背景图片,应该做成图片在中间,四周为镂空的图片

 1 #import "HMNavigationBar.h"
 2 
 3 @implementation HMNavigationBar
 4 
 5 - (id)initWithFrame:(CGRect)frame
 6 {
 7     self = [super initWithFrame:frame];
 8     if (self) {
 9         // Initialization code
10     }
11     return self;
12 }
13 
14 - (void)layoutSubviews
15 {
16     [super layoutSubviews];
17     
18     for (UIButton *button in self.subviews) {
19         if (![button isKindOfClass:[UIButton class]]) continue;
20 
21         if (button.centerX < self.width * 0.5) { // 左边的按钮
22             button.x = 0;
23         } else if (button.centerX > self.width * 0.5) { // 右边的按钮
24             button.x = self.width - button.width;
25         }
26     }
27 }
28 @end

5:封装titleView:titleView由图片和文字构成,可以用button来实现,既可以设置图片也可以设置文字

1 #import <UIKit/UIKit.h>
2 
3 @interface HMTitleView : UIButton
4 @property (nonatomic, copy) NSString *title;
5 @end
 1 #import "HMTitleView.h"
 2 
 3 @implementation HMTitleView
 4 
 5 - (id)initWithFrame:(CGRect)frame
 6 {
 7     self = [super initWithFrame:frame];
 8     if (self) {
 9         self.userInteractionEnabled = NO;
10         [self setImage:[UIImage imageNamed:@"navbar_netease"] forState:UIControlStateNormal];
11         [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
12         self.titleLabel.font = [UIFont boldSystemFontOfSize:22];
13         self.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 0);
14         self.height = self.currentImage.size.height;
15     }
16     return self;
17 }
18 
19 - (void)setTitle:(NSString *)title
20 {
21     _title = [title copy];
22     
23     [self setTitle:title forState:UIControlStateNormal];
24     
25     NSDictionary *attrs = @{NSFontAttributeName : self.titleLabel.font};
26     CGFloat titleW = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.width;
27     
28     self.width = titleW + self.titleEdgeInsets.left + self.currentImage.size.width;
29 }
30 @end

6:封装item,uiview,image分类

1 #import <UIKit/UIKit.h>
2 
3 @interface UIBarButtonItem (Extension)
4 + (UIBarButtonItem *)itemWithImageName:(NSString *)imageName target:(id)target action:(SEL)action;
5 @end
 1 #import "UIBarButtonItem+Extension.h"
 2 
 3 @implementation UIBarButtonItem (Extension)
 4 + (UIBarButtonItem *)itemWithImageName:(NSString *)imageName target:(id)target action:(SEL)action
 5 {
 6     UIButton *button = [[UIButton alloc] init];
 7     [button setBackgroundImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
 8     
 9     // 设置按钮的尺寸为背景图片的尺寸
10     button.size = button.currentBackgroundImage.size;
11     
12     // 监听按钮点击
13     [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
14     return [[UIBarButtonItem alloc] initWithCustomView:button];
15 }
16 @end
 1 #import <UIKit/UIKit.h>
 2 
 3 @interface UIView (Extension)
 4 @property (nonatomic, assign) CGFloat x;
 5 @property (nonatomic, assign) CGFloat y;
 6 @property (nonatomic, assign) CGFloat centerX;
 7 @property (nonatomic, assign) CGFloat centerY;
 8 @property (nonatomic, assign) CGFloat width;
 9 @property (nonatomic, assign) CGFloat height;
10 @property (nonatomic, assign) CGSize size;
11 @end
 1 #import "UIView+Extension.h"
 2 
 3 @implementation UIView (Extension)
 4 
 5 - (void)setX:(CGFloat)x
 6 {
 7     CGRect frame = self.frame;
 8     frame.origin.x = x;
 9     self.frame = frame;
10 }
11 
12 - (CGFloat)x
13 {
14     return self.frame.origin.x;
15 }
16 
17 - (void)setY:(CGFloat)y
18 {
19     CGRect frame = self.frame;
20     frame.origin.y = y;
21     self.frame = frame;
22 }
23 
24 - (CGFloat)y
25 {
26     return self.frame.origin.y;
27 }
28 
29 - (void)setCenterX:(CGFloat)centerX
30 {
31     CGPoint center = self.center;
32     center.x = centerX;
33     self.center = center;
34 }
35 
36 - (CGFloat)centerX
37 {
38     return self.center.x;
39 }
40 
41 - (void)setCenterY:(CGFloat)centerY
42 {
43     CGPoint center = self.center;
44     center.y = centerY;
45     self.center = center;
46 }
47 
48 - (CGFloat)centerY
49 {
50     return self.center.y;
51 }
52 
53 - (void)setWidth:(CGFloat)width
54 {
55     CGRect frame = self.frame;
56     frame.size.width = width;
57     self.frame = frame;
58 }
59 
60 - (CGFloat)width
61 {
62     return self.frame.size.width;
63 }
64 
65 - (void)setHeight:(CGFloat)height
66 {
67     CGRect frame = self.frame;
68     frame.size.height = height;
69     self.frame = frame;
70 }
71 
72 - (CGFloat)height
73 {
74     return self.frame.size.height;
75 }
76 
77 - (void)setSize:(CGSize)size
78 {
79 //    self.width = size.width;
80 //    self.height = size.height;
81     CGRect frame = self.frame;
82     frame.size = size;
83     self.frame = frame;
84 }
85 
86 - (CGSize)size
87 {
88     return self.frame.size;
89 }
90 
91 @end
1 #import <UIKit/UIKit.h>
2 
3 @interface UIImage (Extension)
4 + (UIImage *)imageWithColor:(UIColor *)color;
5 @end
 1 #import "UIImage+Extension.h"
 2 
 3 @implementation UIImage (Extension)
 4 + (UIImage *)imageWithColor:(UIColor *)color
 5 {
 6     CGFloat imageW = 100;
 7     CGFloat imageH = 100;
 8     // 1.开启基于位图的图形上下文
 9     UIGraphicsBeginImageContextWithOptions(CGSizeMake(imageW, imageH), NO, 0.0);
10     
11     // 2.画一个color颜色的矩形框
12     [color set];
13     UIRectFill(CGRectMake(0, 0, imageW, imageH));
14     
15     // 3.拿到图片
16     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
17     
18     // 4.关闭上下文
19     UIGraphicsEndImageContext();
20     
21     return image;
22 }
23 @end

7:封装左侧菜单

 1 #import <UIKit/UIKit.h>
 2 @class HMLeftMenu;
 3 
 4 @protocol HMLeftMenuDelegate <NSObject>
 5 @optional
 6 - (void)leftMenu:(HMLeftMenu *)menu didSelectedButtonFromIndex:(int)fromIndex toIndex:(int)toIndex;
 7 @end
 8 
 9 @interface HMLeftMenu : UIView
10 @property (nonatomic, weak) id<HMLeftMenuDelegate> delegate;
11 @end
  1 #import "HMLeftMenu.h"
  2 #import "HMLeftMenuButton.h"
  3 
  4 @interface HMLeftMenu()
  5 @property (nonatomic, weak) HMLeftMenuButton *selectedButton;
  6 @end
  7 
  8 @implementation HMLeftMenu
  9 
 10 #pragma mark - 初始化
 11 - (id)initWithFrame:(CGRect)frame
 12 {
 13     self = [super initWithFrame:frame];
 14     if (self) {
 15         self.backgroundColor = [UIColor clearColor];
 16         
 17         CGFloat alpha = 0.2;
 18         
 19         [self setupBtnWithIcon:@"sidebar_nav_news" title:@"新闻" bgColor:HMColorRGBA(202, 68, 73, alpha)];
 20         [self setupBtnWithIcon:@"sidebar_nav_reading" title:@"订阅" bgColor:HMColorRGBA(190, 111, 69, alpha)];
 21         [self setupBtnWithIcon:@"sidebar_nav_photo" title:@"图片" bgColor:HMColorRGBA(76, 132, 190, alpha)];
 22         [self setupBtnWithIcon:@"sidebar_nav_video" title:@"视频" bgColor:HMColorRGBA(101, 170, 78, alpha)];
 23         [self setupBtnWithIcon:@"sidebar_nav_comment" title:@"跟帖" bgColor:HMColorRGBA(170, 172, 73, alpha)];
 24         [self setupBtnWithIcon:@"sidebar_nav_radio" title:@"电台" bgColor:HMColorRGBA(190, 62, 119, alpha)];
 25     }
 26     return self;
 27 }
 28 
 29 - (void)setDelegate:(id<HMLeftMenuDelegate>)delegate
 30 {
 31     _delegate = delegate;
 32     
 33     // 默认选中新闻按钮
 34     [self buttonClick:[self.subviews firstObject]];
 35 //    [self buttonClick:self.subviews[1]];
 36 }
 37 
 38 /**
 39  *  添加按钮
 40  *
 41  *  @param icon  图标
 42  *  @param title 标题
 43  */
 44 - (HMLeftMenuButton *)setupBtnWithIcon:(NSString *)icon title:(NSString *)title bgColor:(UIColor *)bgColor
 45 {
 46     HMLeftMenuButton *btn = [[HMLeftMenuButton alloc] init];
 47     btn.tag = self.subviews.count;
 48     [btn addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown];
 49     [self addSubview:btn];
 50     
 51     // 设置图片和文字
 52     [btn setImage:[UIImage imageNamed:icon] forState:UIControlStateNormal];
 53     [btn setTitle:title forState:UIControlStateNormal];
 54     [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
 55     btn.titleLabel.font = [UIFont systemFontOfSize:17];
 56     
 57     // 设置按钮选中的背景
 58     [btn setBackgroundImage:[UIImage imageWithColor:bgColor] forState:UIControlStateSelected];
 59     
 60     // 设置高亮的时候不要让图标变色
 61     btn.adjustsImageWhenHighlighted = NO;
 62     
 63     // 设置按钮的内容左对齐
 64     btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
 65     
 66     // 设置间距
 67     btn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
 68     btn.contentEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 0);
 69     
 70     return btn;
 71 }
 72 
 73 - (void)layoutSubviews
 74 {
 75     [super layoutSubviews];
 76     
 77     // 设置按钮的frame
 78     int btnCount = self.subviews.count;
 79     CGFloat btnW = self.width;
 80     CGFloat btnH = self.height / btnCount;
 81     for (int i = 0; i<btnCount; i++) {
 82         HMLeftMenuButton *btn = self.subviews[i];
 83         btn.width = btnW;
 84         btn.height = btnH;
 85         btn.y = i * btnH;
 86     }
 87 }
 88 
 89 #pragma mark - 私有方法
 90 /**
 91  *  监听按钮点击
 92  */
 93 - (void)buttonClick:(HMLeftMenuButton *)button
 94 {
 95     // 0.通知代理
 96     if ([self.delegate respondsToSelector:@selector(leftMenu:didSelectedButtonFromIndex:toIndex:)]) {
 97         [self.delegate leftMenu:self didSelectedButtonFromIndex:self.selectedButton.tag toIndex:button.tag];
 98     }
 99     
100     // 1.控制按钮的状态
101     self.selectedButton.selected = NO;
102     button.selected = YES;
103     self.selectedButton = button;
104 }
105 @end

8:封装右侧菜单

1 #import <UIKit/UIKit.h>
2 
3 @interface HMRightMenuController : UIViewController
4 /**
5  *  右边菜单全部显示出来
6  */
7 - (void)didShow;
8 @end
 1 #import "HMRightMenuController.h"
 2 #import "HMRightMenuCenterViewRow.h"
 3 
 4 @interface HMRightMenuController ()
 5 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
 6 @property (weak, nonatomic) IBOutlet UIView *centerView;
 7 @property (weak, nonatomic) IBOutlet UIView *bottomView;
 8 @end
 9 
10 @implementation HMRightMenuController
11 - (void)viewDidLoad
12 {
13     [super viewDidLoad];
14     
15     // 1.填充中间的内容
16     [self setupCenterView];
17     
18     // 2.填充底部的内容
19     [self setupBottomView];
20 }
21 
22 /**
23  *  填充中间的内容
24  */
25 - (void)setupCenterView
26 {
27     HMRightMenuCenterViewRow *row =[self setupCenterViewRow:@"商城 能赚能花,土豪当家" icon:@"promoboard_icon_mall"];
28     [self setupCenterViewRow:@"活动 4.0发布会粉丝招募" icon:@"promoboard_icon_activities"];
29     [self setupCenterViewRow:@"应用 金币从来都是这送的" icon:@"promoboard_icon_apps"];
30     
31     self.centerView.height = self.centerView.subviews.count * row.height;
32 }
33 
34 - (HMRightMenuCenterViewRow *)setupCenterViewRow:(NSString *)title icon:(NSString *)icon
35 {
36     HMRightMenuCenterViewRow *row = [HMRightMenuCenterViewRow centerViewRow];
37     row.icon = icon;
38     row.title = title;
39     row.y = row.height * self.centerView.subviews.count;
40     [self.centerView addSubview:row];
41     return row;
42 }
43 
44 /**
45  *  填充底部的内容
46  */
47 - (void)setupBottomView
48 {
49     
50 }
51 
52 - (void)didShow
53 {
54     // 让头像旋转
55 //    [UIView animateWithDuration:1.0 animations:^{
56 //        self.iconView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 1, 0);
57 //    } completion:^(BOOL finished) {
58 //        self.iconView.image = [UIImage imageNamed:@"user_defaultgift"];
59 //        
60 //        [UIView animateWithDuration:1.0 animations:^{
61 //            self.iconView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
62 //        }];
63 //    }];
64 //    CATransition
65 //    CATransition *anim = [CATransition animation];
66 //    anim.duration = 1.0;
67 //    anim.type = @"rippleEffect";
68 //    [self.iconView.layer addAnimation:anim forKey:nil];
69     
70     [UIView transitionWithView:self.iconView duration:1.0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
71         self.iconView.image = [UIImage imageNamed:@"user_defaultgift"];
72     } completion:^(BOOL finished) {
73         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
74             [UIView transitionWithView:self.iconView duration:1.0 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
75                 self.iconView.image = [UIImage imageNamed:@"default_avatar"];
76             } completion:nil];
77         });
78     }];
79 }
80 
81 @end

 

1 #import <UIKit/UIKit.h>
2 
3 @interface HMRightMenuCenterViewRow : UIView
4 + (instancetype)centerViewRow;
5 
6 @property (nonatomic, copy) NSString *icon;
7 @property (nonatomic, copy) NSString *title;
8 @end
 1 #import "HMRightMenuCenterViewRow.h"
 2 
 3 @interface HMRightMenuCenterViewRow()
 4 @property (weak, nonatomic) IBOutlet UIButton *titleView;
 5 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
 6 @end
 7 
 8 @implementation HMRightMenuCenterViewRow
 9 + (instancetype)centerViewRow
10 {
11     return [[[NSBundle mainBundle] loadNibNamed:@"HMRightMenuCenterViewRow" owner:nil options:nil] lastObject];
12 }
13 
14 - (void)setIcon:(NSString *)icon
15 {
16     _icon = [icon copy];
17     
18     self.iconView.image = [UIImage imageNamed:icon];
19 }
20 
21 - (void)setTitle:(NSString *)title
22 {
23     _title = [title copy];
24     
25     [self.titleView setTitle:title forState:UIControlStateNormal];
26 }
27 @end

 

三:知识点总结:

1:启动图的广告展示界面:1:创建启动图展示控制器,其中广告的图片一般是从服务器获取,搞个定时器,GCD延迟函数,经过一段时间后,再切换窗口的根视图控制器为主控制器。 UIWindow *window = [UIApplication sharedApplication].keyWindow;keyWindow为主窗口,负责键盘处理和文本框输入事件,若是textView,textField不能处理-输入事件,或是响应键盘则判断当前显示窗口是否是主窗口keyWindow。2:其中还可以通过keyWindow获取rootViewController,和当前显示的导航控制器,keyWindow.rootViewController, TabBarVC *tab =  keyWindow.rootViewController; NAV *nav = tab.selecteViewcontroller;得到当前显示的导航控制器,nav.viewControllers,得到当前导航控制器栈里的所有控制器。

2:sattic const 定义常量来代替宏定义: static const CGFloat HMNavShowAnimDuration = 0.25;来代替 #define HMNavShowAnimDuration 0.25 ,因为static const定义的常量在系统中只会开辟一份内存,而#define,所定义的每一个常量都会开辟一份临时的内存空间。用static修饰的全局变量,只能是全局变量,该变量才会限制在本类中使用,外部不可以访问,若不加static,则用ertern,就可以在其他类中访问该变量。const在前在后都是一样的,定义字符串变量时,static NSString * const name = @"name";则指针name不可改变。const修饰变量或是常量时,就看const右侧是什么,则const右侧的指针或是变量不可改变。

3:创建子控制器addChildViewController:苹果官方建议当控制器互为父子关系时,控制器上的view也应该为父子关系。1:将创建子控制器的代码封装起来,创建子控制器对象,将子控制对象和title作为参数传入。2:titleView的封装:1:因为titleView为图片和文字构成,所以用button去封装titleView,创建控件继承UIButton,设置自身属性,btn的ennable,或是userenable为NO,titleLable.font,titleColor,setImage,btn.adjustImageWhenHeighlight(当setImage时),titleEdgeInsets,imageEdgeInset,contentEdgeInset,继承UIcontrol的contentHorizanAliment(整个btn文本的对其方式),btn的高度,self.height =self.currentImage.size.height;self.currentImage获得当前的image,btn.currentBackgroundImage,获得背景图片 2:懒加载子控件,添加到父视图上,无 3:layoutSubView布局子控件 4:向外界提供model接口,重写model的set方法,外界提供title接口,重写title的set方法,btn要设置自身的宽度自适应,用boundingRectWithSize,如下:

 NSDictionary *attrs = @{NSFontAttributeName : self.titleLabel.font};    CGFloat titleW = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.width; self.width = titleW + self.titleEdgeInsets.left + self.currentImage.size.width;

 其中,只要赋值,就调用set方法,想获得此变量,就调用get方法,没必要再UIFont去设置,boundingRectWithSize,单行绘制文本时,两个参数都穿MAXFLOAT,基于基线绘制NSStringDrawingUsesLineFragmentOrigin,若是多行,则先设置lable.numberoflines = 0;再限制宽度或是高度,参数采用基线绘制,NSStringDrawingUsesLineFragmentOrigin,和行间距 NSStringDrawingUsesFontLeading。总的宽度就为,image的宽度+self.titleEdgeInsets.left+self.currentImage.size.width。其中titleEdgeInsets的设置,指的是距离左侧图片的距离,为正数,则指的是右侧距离

4:自定义导航栏上的左右item,自定义btn,btn setBackgroundImage,图片为按钮的背景图片,btn的大小为图片的大小, button.size = button.currentBackgroundImage.size;

5:封装导航控制器:1:继承系统导航控制器,因为设置全局导航栏的属性,只需设置一次就好,所以写在+ (void)initialize里,该方法只在该方法所在类第一个方法被调用之前被调用一次,只在整个项目中只会调用一次。先获得全局导航栏,item对象,利用settitleTextAttribute forState属性,可以设置不同状态下的属性 2:左右item距离屏幕左右边框的距离很大,想要调整,1:可遍历系统控件的子控件,找出左右按钮,再设置左右按钮的frame 2:自定义bar用kvc代替系统的bar:新建类继承系统的bar,在layoutSubView方法中,则子类继承了系统bar的属性,遍历子控件数组,self.subViews,在遍历时,要做条件过滤,不符合条件的直接return,或是continue。找到子控件的时候停止遍历,做性能优化。找到左右按钮后,判断左右按钮的btn的center与中点比较,看是哪个左右item。3:设置完frame之后,再在封装的nav控制器中创建对象,setValue forKeyPath ,kvc来代替系统的控件,第二个参数,就是nav控制器下属性定义的navBar,调用此方法,得是某个控制器下的某个属性

  // 替换为自定义的导航栏    [self setValue:[[HMNavigationBar alloc] init] forKeyPath:@"navigationBar"];4:其中:layoutSubView方法只适用于在UIView中,在控制器中调整子控件可以重写系统方法:- (void)viewDidLayoutSubviews,但是不要忘记调用super

6:[self addChildViewController:nav];1:添加子控制器,能则父控制器就对子控制器有一个强引用,只要父控制器在,则子控制器就在,而且控制器互为父子关系,则他们的view也应该互为父子关系。2:子控制器数组:self.childViewControllers,得到子控制器数组,只读,子控制器从父控制器移除,subNav removeFromParentViewController ,获得父控制器:subNav.parentViewController

 7:封装左侧菜单:1:有背景的话可以继承UIImageView,但要开启用户交互权限,也可以继承UIView,设置背景图片时,添加UIImageView,或是view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:]];,平铺图片,或有间隔线,或是调用drawInRect,画上一张图片 2:先设置自身的属性,clearcolor 3:懒加载控件,设置控件属性,添加到父视图上,创建相同的控件,例如button,可以采用for循环创建,也可以一个一个创建,传title,image,枚举tag值或是其他参数,封装一个button,创建对象,setImage,btn.adjust,setBackgroudImage,可以设枚举tag值,也可以通过设置self.subViews.count为tag值,也可以设置titleEdgeInset,ImageEdgeInset,contentEdgeInset,继承UIcontrol的也可以用contentHorizanAliment(文本的对齐方式),在layoutSubView里设置控件的frame,1:属性,成员变量 ,通过tag值取出,若是有多个子控件,可以设置tag值,遍历子控件数组,通过tag值将子控件取出2:放在大数组里,从数组里取出,若是又有button又有其他控件,则两两分别放在数组里,分别从数组里取出,设置frame 3:遍历subView,从subViews的数组里取出。4:设置按钮的回调:1:可通过协议代理,通知 ,block ,协议代理,block适用于层级较浅的回调,通知,多播委托适用于层级较深的结构 2 :若是监听系统的控件:继承UIControl的可以addTarget,可以系统的代理,系统通知,子类若没有查看父类,也可以重写系统的方法,不要忘记调用super方法,来实现监听 3:按钮的协议代理,传枚举tag值是为了在控制器实现监听点击,传fromIndex,传toIndex,是为了从数组取出旧的移除,并添加新的 4:按钮的回调方法,两个按钮状态的判断,btn.selected = !btn.isSelected,三个按钮切换状态则用按钮三部曲,若是传index则把代理方法放前面 5:设置按钮默认选中:1:直接设哪个按钮被选中,再设seletedBtn 2:返回按钮,调用按钮的点击方法,要考虑需不需要重写代理的setDelegate方法在该方法中设置按钮的默认选中。

8:transform属性:1:当点击左上角按钮的时候,先进行缩放,在进行平移,在缩放的基础上进行平移,求缩放比例:缩放后的高度 = 屏幕高度 - 上下间距 ,用缩放的高度与原高度的比值就是缩放比例,在UIView的动画中先进行缩放,再在缩放的基础上进行平移,平移的距离,1-缩放比例,就为剩下的长度比例,0.5倍,就是缩放后的view的实际距屏宽度。2:在动画结束的时候设置一个遮盖效果,遮盖效果:1:可以为一个view,添加手势,2:也可以另遮盖为一个button,监听button的点击事件,button在此处不能为成员变量,button的点击事件中,动画先将transform清空,完成时,将button从父视图移除。3:监听点击事件:1:继承UIControl的可以addTarget 2:添加手势监听器 3:实现touch beagn,touch end,touch cancle 方法,配合UITouch,使用,UITouch *touch = [UITouch anyObject]; touch.view可以获得触摸点点击的view,CGPoint point = [touch locationInView:touch.view];此方法可获得触摸点,其中触摸点的是基于touch.view来计算的,如果此参数填父视图view,则是基于整个父视图来计算的。然后一般是遍历数组,做条件过滤,利用CGRectContainPoint方法,根据触摸点求出矩形框的rect,找到结果后停止遍历 4:transform是二维旋转,view的图层layer是三维动画,view.layer.transform = CAAFfitransform(,,,,);最后三个参数为xyz轴,若是010,则是绕着y轴上1点与原点连线的的向量旋转,第一个参数为旋转的角度。5:动画效果:1:二维动画:UIView + transform 2:三维动画:UIView +view.layer.transform  = CAAFi ,注意三个参数  3:转场动画:也就是翻转动画,[UIView transition...];翻转动画有各种参数值 4:三维动画也可以用CATranstion,CATranstion *ad = [CATranstion animation];ad.duration 动画时间,ad.type,动画的方式,字符串,[self.iconaImageView.layer addAnimation: ad forkey:nil];

9:监听左侧菜单按钮的回调事件:效果是,点击左侧按钮,切换视图,动画清空transform。将旧的控制器取出,view从父视图上移除,再将新控制器取出,将新控制器的view添加到父视图上,此时可以不必设置新view的frame,默认为父视图的bounds。将旧控制器的transform赋值给新的控制器的transform,更新当前的控制器,动画回去,此时就是清空新控制器的transform,相当于点击了旧控制器的遮盖,将按钮从父视图上取出,调用按钮点击方法。

10:在使用xib绘制界面的时候,有时明明尺寸设置正确,但是就不能正常显示,1:此时可以禁用autoLayout 2:setNeedsLayOut ,layOutIfNeed配合使用,异步调用layoutSubView,重新计算尺寸。3:当xib加载完毕后会调用awakeFromNib,在此方法中可以设置xib中控件的一些属性,当xib中已经设置了控件的尺寸,在外部依然可以修改xib中控件的尺寸

11:右侧菜单的封装设计:1:对于控制器和view来说,要采取分层封装的思想,就是将view和或是控制器切分成一个个模块,将零散的控件封装在一个整体内,然后再考虑整个项目中其他地方有没有用到,若用到则考虑继承关心A继承B,或是B继承A,或是将AB公共部分抽成父类C,AB分别继承父类C,不同的部分在AB中单独实现 2:右侧的菜单封装,可以采取三种封装方法:1:看成是一个tableView,table的headerView,tableView,table的footerView 但是没有cell的复用,且按钮的回调监听,太复杂 2:还可以考虑封装一个大view,再将上中下封装为三个小view添加到大view上,但是同样涉及的问题就是按钮的监听回调太麻烦 3:考虑用一个控制器,在控制器内实现按钮的监听,在控制器内再将整体封装为上中下三个view。2:对于顶部view的封装以及动画,顶部view中的头像的翻转就用转场动画,每执行一次转场动画,转360度,并更换图片,动画完成时,执行GCD延迟函数,在执行一个转场动画转回来,再更改frame 3:中间View的封装,按钮会点亮,调用的是button的btn.showTouchWhenHeighlight。此方法若是button有图片,则只在button的图片处点亮,再将每一行封装为一个View,点图片和箭头都会亮,则其肯定为一个整体,所以可以考虑button为整个背景,将图片和箭头添加到button上,因为当点击图片和箭头时,默认没有开启用户的交互权限,通过的事件的传递可以找到触摸点所在的view,但是该view不能处理事件,则事件会又子控件传递给父控件去处理,也就是交给button去处理,buttonn能处理所以点击图片箭头都会被点亮 4:设置每个封装view的y值,view.y = self.subViews.count *height;总高度,self.subViews.count *height

 

posted on 2016-08-01 00:53  Hello_IOS  阅读(1296)  评论(1编辑  收藏  举报

导航