
正文
内外分离接口依赖及UIScrollView知识点
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
1:Class Extension 还能巧妙的解决一个接口暴露问题
有些属性或者方法对外可以提供,有些只针对内部的类进行调用;
// Sark.framework/Sark.h
@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *creditCardPassword; // secret!
@end// Sark.framework/PrivateSarkWife.h
@interface PrivateSarkWife : NSObject
- (void)robAllMoneyFromCreditCardOfSark:(Sark *)sark; // needs password!
@end
假设 Sark.h 是 Sark.framework 唯一暴露的 Header,而 framework 中的一个私有类需要获取这个公共类的某个属性(或方法)该怎么办?PrivateSarkWife为Sark.framework内部一个类;上面的 creditCardPassword 属性需要一个对外不可见而对内可见的地方声明,这时候可以利用 Class Extension:
// Sark.h
@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
@end// Sark+Internal.h <--- new
@interface Sark ()
@property (nonatomic, copy) NSString *creditCardPassword;
@end// Sark.m
#import "Sark.h"
#import "Sark+Internal.h" // <--- new
将对公业务和对私业务用 Class Extension 的形式拆到两个 Header 中,在Sark.m里把两个头文件都进行引用,CreditCardPassword被定义在Sark+Internal.h的头文件里面,这样私有类对私有属性的依赖就被成功隔离开了:
// PrivateSarkWife.m
#import "PrivateSarkWife.h"
#import "Sark+Internal.h" // <--- 私有依赖@implementation PrivateSarkWife
- (void)robAllMoneyFromCreditCardOfSark:(Sark *)sark {
NSString *password = sark.creditCardPassword; // oh yeah!
}
@end
2:UIScrollView知识点
- (void)viewDidLoad
{
[super viewDidLoad]; scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(, , , )];
scrollView.backgroundColor = [UIColor redColor];
// 是否支持滑动最顶端
// scrollView.scrollsToTop = NO;
scrollView.delegate = self;
// 设置内容大小
scrollView.contentSize = CGSizeMake(, *);
// 是否反弹
// scrollView.bounces = NO;
// 是否分页
// scrollView.pagingEnabled = YES;
// 是否滚动
// scrollView.scrollEnabled = NO;
// scrollView.showsHorizontalScrollIndicator = NO;
// 设置indicator风格
// scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
// 设置内容的边缘和Indicators边缘
// scrollView.contentInset = UIEdgeInsetsMake(0, 50, 50, 0);
// scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 50, 0, 0);
// 提示用户,Indicators flash
[scrollView flashScrollIndicators];
// 是否同时运动,lock
scrollView.directionalLockEnabled = YES;
[self.view addSubview:scrollView]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(, , , )];
label.backgroundColor = [UIColor yellowColor];
label.text = @"学习scrolleview";
[scrollView addSubview:label];
[label release];
}#pragma mark -
/*
// 返回一个放大或者缩小的视图
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{}
// 开始放大或者缩小
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:
(UIView *)view
{}// 缩放结束时
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{}// 视图已经放大或缩小
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidScrollToTop");
}
*/// 是否支持滑动至顶部
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
return YES;
}// 滑动到顶部时调用该方法
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidScrollToTop");
}// scrollView 已经滑动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidScroll");
}// scrollView 开始拖动
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(@"scrollViewWillBeginDragging");
}// scrollView 结束拖动
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
NSLog(@"scrollViewDidEndDragging");
}// scrollView 开始减速(以下两个方法注意与以上两个方法加以区别)
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
NSLog(@"scrollViewWillBeginDecelerating");
}// scrollview 减速停止
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidEndDecelerating");
}
3:仿网易滚动菜单及内容视图滚动效果
#import "NewsViewController.h"#import "VideoViewController.h"
#import "ReaderViewController.h"
#import "ScienceViewController.h"
#import "SocietyViewController.h"
#import "HotViewController.h"
#import "TopLineViewController.h"#import "TitleButton.h"#define ScreenW [UIScreen mainScreen].bounds.size.width
#define ScreenH [UIScreen mainScreen].bounds.size.height@interface NewsViewController ()<UIScrollViewDelegate>@property (nonatomic, strong) UIButton *selButton;@property (nonatomic, strong) NSMutableArray *titleBtns;// 标题滚动view
@property (weak, nonatomic) IBOutlet UIScrollView *titileScrollView;// 内容滚动view
@property (weak, nonatomic) IBOutlet UIScrollView *contentView;@end@implementation NewsViewController- (NSMutableArray *)titleBtns
{
if (_titleBtns == nil) {
_titleBtns = [NSMutableArray array];
}
return _titleBtns;
}// 头条,热点,视频,社会,订阅,科技(science)- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view. // 添加所有子控制器
[self setUpChildViewController]; // 设置标题
[self setUpTitle]; // iOS7之后,导航控制器下所有ScrollView都会添加额外滚动区域
self.automaticallyAdjustsScrollViewInsets = NO; // 初始化scrollView
[self setUpScrollView];}- (void)setUpScrollView
{
self.titileScrollView.showsHorizontalScrollIndicator = NO; self.contentView.contentSize = CGSizeMake(self.childViewControllers.count * [UIScreen mainScreen].bounds.size.width, ); self.contentView.showsHorizontalScrollIndicator = NO;
self.contentView.pagingEnabled = YES;
self.contentView.bounces = NO; self.contentView.delegate = self;
}- (void)setUpChildViewController
{ TopLineViewController *topLineVc = [[TopLineViewController alloc] init];
topLineVc.title = @"头条";
[self addChildViewController:topLineVc]; HotViewController *hotVc = [[HotViewController alloc] init];
hotVc.title = @"热点";
[self addChildViewController:hotVc]; VideoViewController *videoVc = [[VideoViewController alloc] init];
videoVc.title = @"视频";
[self addChildViewController:videoVc]; SocietyViewController *societyVc = [[SocietyViewController alloc] init];
societyVc.title = @"社会";
[self addChildViewController:societyVc]; ReaderViewController *readerVc = [[ReaderViewController alloc] init];
readerVc.title = @"订阅";
[self addChildViewController:readerVc]; ScienceViewController *scienceVc = [[ScienceViewController alloc] init];
scienceVc.title = @"科技";
[self addChildViewController:scienceVc];
}// 设置标题
- (void)setUpTitle
{
NSUInteger count = self.childViewControllers.count; CGFloat btnX = ;
CGFloat btnY = ;
CGFloat btnW = ;
CGFloat btnH = ; for (NSUInteger i = ; i < count; i++) {
btnX = i * btnW;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.tag = i;
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
UIViewController *vc = self.childViewControllers[i];
[btn setTitle:vc.title forState:UIControlStateNormal];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
[btn addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside]; [self.titileScrollView addSubview:btn]; [self.titleBtns addObject:btn];
// 默认选中第一个
if (i == ) {
[self titleClick:btn]; }
} self.titileScrollView.contentSize = CGSizeMake(btnW * count, );}// 点击标题按钮
- (void)titleClick:(UIButton *)btn
{ // 0.设置标题按钮居中
[self setUpTitleBtnMiddle:btn]; // 1.滚动到对应的界面
CGFloat offsetX = btn.tag * ScreenW; self.contentView.contentOffset = CGPointMake(offsetX, ); // 2.添加对应子控制器view到对应的位置
UIViewController *vc = self.childViewControllers[btn.tag]; vc.view.frame = CGRectMake(offsetX, , ScreenW, self.contentView.bounds.size.height);// NSLog(@"%@",NSStringFromCGRect(self.contentView.bounds));
[self.contentView addSubview:vc.view]; // 还原之前标题的形变
[self setSelectBtn:btn];}- (void)setSelectBtn:(UIButton *)btn
{
_selButton.transform = CGAffineTransformIdentity;
[_selButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
_selButton.selected = NO; btn.transform = CGAffineTransformMakeScale(1.3, 1.3);
btn.selected = YES; _selButton = btn;}#pragma mark - UIScrollViewDelegate
// 减速完成的时候
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// 获取当前的偏移量
CGFloat offsetX = scrollView.contentOffset.x;
// 获取页码
int page = offsetX / scrollView.bounds.size.width; UIButton *btn = self.titileScrollView.subviews[page]; // 选中按钮
[self setSelectBtn:btn]; // 设置按钮居中
[self setUpTitleBtnMiddle:btn]; // 添加对应子控制器到界面上
UIViewController *vc = self.childViewControllers[page]; // 已经加载的view就不需要添加了
if (vc.isViewLoaded) return; vc.view.frame = CGRectMake(offsetX , , self.contentView.bounds.size.width, self.contentView.bounds.size.height); [self.contentView addSubview:vc.view];
}// 设置标题按钮居中
- (void)setUpTitleBtnMiddle:(UIButton *)btn
{ // 计算偏移量
CGFloat offsetX = btn.center.x - ScreenW * 0.5; // 左边偏移多了,表示需要往左边看,可视范围往左边,偏移量就减少,最少应该是0
if (offsetX < ) offsetX = ;
CGFloat maxOffsetX = self.titileScrollView.contentSize.width - ScreenW; // 右边偏移多了,表示需要往右边看,可视范围往又边,偏移量就增加,最大不超过内容范围 - 屏幕宽度
if (offsetX > maxOffsetX) offsetX = maxOffsetX; [self.titileScrollView setContentOffset:CGPointMake(offsetX, ) animated:YES];}// 监听内容view滚动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat page = scrollView.contentOffset.x / scrollView.bounds.size.width; NSInteger leftIndex = page; // 右边缩放比例
CGFloat rightScale = (page - leftIndex);
// 左边缩放比例
CGFloat leftScale = ( - rightScale); NSInteger rightIndex = leftIndex + ; // 获取左边按钮
TitleButton *leftBtn = self.titleBtns[leftIndex]; NSInteger count = self.titleBtns.count; // 获取右边按钮
TitleButton *rightBtn; if (rightIndex < count) {
rightBtn = self.titleBtns[rightIndex];
} // 设置尺寸
CGFloat leftTransform = leftScale * 0.3 + ; // 1 ~ 1.3
CGFloat rightTransform = rightScale * 0.3 + ; // 1 ~ 1.3
leftBtn.transform = CGAffineTransformMakeScale(leftTransform, leftTransform);
rightBtn.transform = CGAffineTransformMakeScale(rightTransform, rightTransform); // 设置颜色
/*
RGB 红色: 1 0 0
黑色: 0 0 0
*/ UIColor *leftColor = [UIColor colorWithRed:leftScale green: blue: alpha:];
UIColor *rightColor = [UIColor colorWithRed:rightScale green: blue: alpha:]; [leftBtn setTitleColor:leftColor forState:UIControlStateNormal];
[rightBtn setTitleColor:rightColor forState:UIControlStateNormal];}@end
效果图如下:








