由于一直做公司项目,所以有些技能没有去实践过,所以一直想做一个项目练练手,然后找到了MONO这个软件,里面的内容界面都做的很精致,用charles抓了一下,发现接口都是可以获取的,于是就开始做了.目前只做了一部分,记录了过程中一些觉得值得记录的问题,然后分享给大家.
如果大家觉得这篇文章对你有帮助,希望大家能给个star,你们的鼓励是我前进的动力 --项目地址.
注意这里只是给出个简单思路,详细过程还请看源码.
一.全屏拖拽效果

首先导入FDFullscreenPopGesture和RTRootNavigationController这两个库,然后在tabbar中将RTRootNavigationController设为你每个视图控制器的根视图就可以实现这种push效果了.FDFullscreenPopGesture是实现全屏拖拽手势,RTRootNavigationController是改变导航栏的动画效果.
二.导航栏视图填充满


本身导航栏左侧是始终有一个返回按钮的位置的,如果直接设置view为titleview的话并不能填充满,我的做法是在view上放一个backview再在backview上放控件,backview的x设为-25,这样的话就可以将导航栏填充满了.
三.简化UITableViewDelegate,UITableViewDataSource代理方法 首先注册cell
[self.tableView registerClass:[RecommendImageBgCell class] forCellReuseIdentifier:NSStringFromClass([RecommendImageBgCell class])];
[self.tableView registerClass:[RecommendReadCell class] forCellReuseIdentifier:NSStringFromClass([RecommendReadCell class])];
[self.tableView registerClass:[RecommendImagesCell class] forCellReuseIdentifier:NSStringFromClass([RecommendImagesCell class])];
[self.tableView registerClass:[RecommendMusicCell class] forCellReuseIdentifier:NSStringFromClass([RecommendMusicCell class])];
[self.tableView registerClass:[RecommendVideoCell class] forCellReuseIdentifier:NSStringFromClass([RecommendVideoCell class])];
[self.tableView registerClass:[RecommendPicturesCell class] forCellReuseIdentifier:NSStringFromClass([RecommendPicturesCell class])];
[self.tableView registerClass:[RecommendTeaCell class] forCellReuseIdentifier:NSStringFromClass([RecommendTeaCell class])];
高度的计算因为我用的是SDAutolayout进行布局,所以只用一行代码就可以将所有的cell的高度计算下来.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RecommendModel *model = _dataArray[indexPath.row];
return [self.tableView cellHeightForIndexPath:indexPath model:model keyPath:@"recommendModel" cellClass:NSClassFromString(model.cellIdentifier) contentViewWidth:SCREEN_WIDTH];
}
这里注意所有cell的model名字需要一直,而且他们都是可以共用同样的model. 接下来就是设置cell了,这里我给出了详细的注释
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RecommendModel *model = _dataArray[indexPath.row];//获取model
//MNBaseTableViewCell为所有cell的父类
MNBaseTableViewCell *cell;
NSString *cellIdentifier;
//后台会根据内容的不同给出不同的object_type,根据这个来设置不同cell的identifier.
cellIdentifier = model.cellIdentifier;
//因为给每个cell注册过了,所以这里拿到identifier就可以找到具体的cell
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
//这里用kvc给cell赋值
[cell setValue:_dataArray[indexPath.row] forKey:@"recommendModel"];
return cell;
}
四.文字闪烁出现
效果是下面这样的,当拖动到一定位置的时候图片上面的文字闪烁出现,之后就不再闪烁了.

//cell将要被加载
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//判断是否是需要闪烁文字的cell
if ([cell isKindOfClass:[RecommendImageBgCell class]]) {
RecommendImageBgCell *bgCell = (RecommendImageBgCell *)cell;
_bgCell = bgCell;
//如果tableview刚刷新出来,这个cell就在界面上的话就执行闪烁方法
if (tableView.contentOffset.y <= 0 && bgCell.y <= 0) {
[_bgCell shineText];
return;
}
//给一个全局变量来监视cell滑动情况
_bgCellY = bgCell.y;
}
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//当cell滑动到一定位置的时候就闪烁
if ((_bgCellY - scrollView.contentOffset.y <= (SCREEN_HEIGHT / 4 + KTabBarHeight)) && _bgCellY > 0) {
[_bgCell shineText];
_bgCellY = -10;
}
}
五.音乐播放效果
效果如下所示,当点击cell播放音乐的时候,CD会转起来,导航栏最右侧的CD按钮也会转起来.

首先音频播放这块我用的是FreeStreamer,写一个单例类MNMusicPlayer继承自FSAudioStream,里面除了初始化和单独的一些方法外还为音乐播放的各种状态添加了通知.通过通知来决定动画的显示或消失. 好,接下来就在cell上自定义2个view,一个是旋转的MusicCDView,一个是下面歌曲进度的MusicProgressView. 在MusicCDView中,先创建一个CABasicAnimation,再通过给self.layer添加或移除动画来实现CD旋转和隐藏效果.
//创建一个全局的动画
_anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
_anim.fromValue = [NSNumber numberWithFloat:0.f];
_anim.toValue = [NSNumber numberWithFloat: M_PI *2];
_anim.duration = 10;
_anim.autoreverses = NO;
_anim.fillMode = kCAFillModeForwards;
_anim.repeatCount = MAXFLOAT;
动画效果
//播放音乐
-(void)playMusic
{
if (self.alpha != 1) {
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 1;
}];
}
[self.layer addAnimation:_anim forKey:@"rotaion"];
}
//暂停音乐
-(void)stopMusic
{
if (self.alpha != 0) {
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
}];
}
[self.layer removeAnimationForKey:@"rotaion"];
}
最后在收到通知的时候执行就行了.
@weakify(self)
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"stopMusic" object:nil] subscribeNext:^(NSNotification *notification) {
@strongify(self)
[self stopMusic];
}];
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"playMusic" object:nil] subscribeNext:^(NSNotification *notification) {
@strongify(self)
//播放音乐的URL和此URL地址相同时才播放
if ([notification.object isEqualToString:self.model.music_url]) {
[self playMusic];
}
}];
同时别忘了给他的父视图设置.clipsToBounds = YES属性,不然CD盘就全部显示出来了.
六.图片裁剪
在图片浏览中,小图的ImageView的宽高比都是1:1的比例,而原图的比例并不是,所以需要截取图片正中间1:1的部分,这样点击浏览图片效果就会很舒服,效果如下:




imageView.layer.contentsRect = CGRectMake((1- 0.5)/2, 0, 0.5, 1);
好了,现在我们假设一张图片它的宽和高分别是width和height,且width > height.那么我们要截取正中间1:1的部分就可以写成这样了:
imageView.layer.contentsRect = CGRectMake((1 -(float)height / width) / 2, 0, (float)height / width, 1);
同理,高图就写成这样:
imageView.layer.contentsRect = CGRectMake(0, (1- (float)width / height) / 2, 1, (float)width / height);
在代码中判断是宽图还是高图再用具体的方法来截取就可以了.
七.收藏动画

八.网页滑动隐藏导航栏和状态栏.

-(BOOL)prefersStatusBarHidden
{
return hiddenStatusBar;
}
hiddenStatusBar是一个全局Bool变量,在滑动的时候判断滑动方向后来改变hiddenStatusBar的值,再调用[self setNeedsStatusBarAppearanceUpdate]方法来刷新状态栏的显示或隐藏.导航栏的隐藏和显示就用[self.navigationController setNavigationBarHidden:BOOL animated:YES];因为最开始不知道setNeedsStatusBarAppearanceUpdate方法,所以绕了些弯路.
九.网页阅读模式

十.加载失败与重新加载

//加载失败显示失败按钮与文字,参数为点击按钮执行方法
-(void)showPageLoadingFailedWithReloadTarget:(id)target action:(SEL)action
{
if (!pageLoadingView) {
pageLoadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NaviH - KTabBarHeight)];
pageLoadingView.backgroundColor = [UIColor colorWithRed:0.86 green:0.89 blue:0.91 alpha:1];
}
[pageLoadingView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self.view addSubview:pageLoadingView];
UIButton *reloadImageBtn = [UIButton buttonWithType:UIButtonTypeCustom];
reloadImageBtn.frame = CGRectMake(0, 0, 40, 40);
reloadImageBtn.center = CGPointMake(pageLoadingView.width/2, pageLoadingView.height/2);
[pageLoadingView addSubview:reloadImageBtn];
[reloadImageBtn setImage:[UIImage imageNamed:@"refresh_btn"] forState:UIControlStateNormal];
UIButton *reloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
reloadBtn.frame = CGRectMake(0, reloadImageBtn.bottom + 20, 200, 30);
reloadBtn.centerX = pageLoadingView.width/2;
[pageLoadingView addSubview:reloadBtn];
reloadBtn.titleLabel.font = [UIFont systemFontOfSize:12];
[reloadBtn setTitleColor:[UIColor colorWithRed:0.66 green:0.66 blue:0.66 alpha:1] forState:UIControlStateNormal];
[reloadBtn setTitle:@"加载失败,请点击重试" forState:UIControlStateNormal];
if (target){
[reloadImageBtn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
[reloadBtn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
}
}
//显示正在加载背景图片
#pragma mark - 正在加载动画
-(void)showPageLoadingProgress
{
if (!pageLoadingView) {
pageLoadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - NaviH - KTabBarHeight)];
pageLoadingView.backgroundColor = [UIColor colorWithRed:0.86 green:0.89 blue:0.91 alpha:1];
}
[pageLoadingView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self.view addSubview:pageLoadingView];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 25, 25)];
imageView.center = CGPointMake(pageLoadingView.width/2, pageLoadingView.height/2);
[pageLoadingView addSubview:imageView];
imageView.image = [UIImage imageNamed:@"head-mask-bg"];
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
animation.duration = 1;// 动画时间
NSMutableArray *values = [NSMutableArray array];
[values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.8, 0.8, 1.0)]];
[values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)]];
[values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.8, 0.8, 1.0)]];
animation.values = values;
animation.repeatCount = FLT_MAX;
[imageView.layer addAnimation:animation forKey:nil];
}
结尾
这个项目也是费了一些时间和精力,现在整理其中有遇到的或学习到的一些知识来分享给大家,希望能够帮助到大家,目前只做了一部分,剩下的会慢慢做下去,然后再把过程中的知识点整理出来分享给大家.希望大家能给个star,你们的鼓励是我前进的动力,谢谢大家. ##github地址,欢迎star