写在最前面:
其实本文应该早在两个月之前就该写完的,由于当时找工作,种种原因搁置到现在才写完。
本文不可能把每一个点都能写到,如果真要一个点一个点的写,可能得写1w+字吧。再说时隔两个多月没碰这个项目了,多多少少都忘了一些。我尽可能把当时在写这个项目遇到的各种坑写详细。如果在看本文或者demo的时候有不明白的地方可以在Github上面提issue或者简书简信我也可以。
温馨提示:看文章的时候结合代码一起看,效果会更佳哟。
目前完成进度70%,由于时间的关系(临近期末,各种事情的原因…),剩下的30%未能完成,后面抽空完成吧。
项目采用MVC设计模式
本人还属于菜鸟级别,代码写得不规范,望见谅!
如果项目中同样的问题,你有更好的办法解决请告诉我,让我们一起学习。
废话说了一大堆,开始进入正题!!!
项目视频演练 -> 点我
Demo ->Timi 不要忘记star支持哟
高仿版本:3.6.1
使用语言:Objective-C
开发工具及调试神器:Xcode 7.3.1,Reveal 1.6.3
用到的三方库及扩展库
NAME | EXPLAIN |
---|---|
Masonry | 纯代码Autolayout |
MBProgressHUD | 未使用,后更改为使用SVProgressHUD |
MMDrawerController | 抽屉 |
SVProgressHUD | HUD |
YYText | 著名库YYKit下的一个富文本 |
iCarousel | 一个类似UIScrollView的控件 |
ColorCube | 图片颜色提取 |
UITextView_PlaceHolder | 给UITextView添加PlaceHolder |
SZCalendarPicker | 日历 |
TYPagerController | 左右滚动ViewController VTMagic |
Realm | 移动端数据库新王者 |
数据库设计
TMBill(账单)
KEY | IDENTITY | COLUMN | DATA TYPE | LENGTH | ALLOWED NULL | DEFAULT | DESCRIPTION |
---|---|---|---|---|---|---|---|
√ | √ | billID | NSString | 64 | 主键 | ||
dateStr | NSString | 10 | 当前年月日 | 时间 | |||
reMarks | NSString | 40 | nil | 备注 | |||
remarkPhoto | NSData | √ | nil | 图片备注 | |||
isIncome | BOOL | 1 | 0 | 类型(收支) | |||
money | float | 13 | 0 | 金额 | |||
FK | category | TMCategory | 类别 | ||||
FK | book | TMBooks | 账本 |
TMCategory(类别)
KEY | IDENTITY | COLUMN | DATA TYPE | LENGTH | ALLOWED NULL | DEFAULT | DESCRIPTION |
---|---|---|---|---|---|---|---|
√ | √ | categoryID | NSString | 64 | 主键 | ||
categoryImageFileNmae | NSString | 64 | 类别icon文件名 | ||||
categoryTitle | NSString | 3 | 类别标题 | ||||
isIncome | BOOL | 1 | 类型(收支) |
TMBook(账本)
KEY | IDENTITY | COLUMN | DATA TYPE | LENGTH | ALLOWED NULL | DEFAULT | DESCRIPTION |
---|---|---|---|---|---|---|---|
√ | √ | bookID | NSString | 64 | 主键 | ||
bookName | NSString | 6 | 账本标题 | ||||
imageIndex | int | 2 | 账本对应icon下标 | ||||
bookImageFileName | NSString | 64 | 类别icon文件名 |
TMAddCategory(新增类别)
KEY | IDENTITY | COLUMN | DATA TYPE | LENGTH | ALLOWED NULL | DEFAULT | DESCRIPTION |
---|---|---|---|---|---|---|---|
√ | √ | categoryID | NSString | 64 | 主键 | ||
√ | categoryImageFileNmae | NSString | 64 | 类别icon文件名 | |||
isIncome | BOOL | 1 | 类型(收支) |
TMCategory(类别),TMAddCategory(新增类别)都是采用plist表的方式先存储。当App每次启动的时候就会先检查数据库对应的表是否为空,为空则从plist表读取数据,存储到本地数据库。
项目整体结构
温馨提醒
项目里面95%都是使用的纯代码方式布局(Masonry),如果不懂的Masonry
纯代码布局的请先去了解一下。传送门=>串哥的深入讲解 AutoLayout 和 Masonry
时光轴界面(HomePageViewController)
![](http://file.zhishichong.com/images/article/20161028/005NFHyQgw1f7j48sysglg30a90i9nph.gif)
UI布局之header部分(TMHeaderView)
其实headerView部分没有什么好说的,那个饼图是用UIBezierPath
和CAShapeLayer
绘制而成,我把它单独封装出来了,因为在后面的饼图部分也用到了。关于饼图的加载数据时候的动画我是使用的CABasicAnimation
具体的操作可以看demo的对应文件(TMPieView
)
UI布局之数据显示部分(HomePageViewController | TMTimeLineCell)
数据的显示全部在一个section里面,并没有分section显示,而且cell也只有一个样式,我是通过收支类型来判断的该那边显示数据。
时间轴上面,相同时间(同一天)时间label和金额label以及时间点不显示出来,我是在模型层加了一个BOOL变量来判断,同时在获取数据之后进行数据的重置,具体的操作可以看HomePageViewController
的getDataAndResetBill
函数。
然后在自定义cell(TMTimeLineCell
)重写timeLineBill
属性,通过判断来显示数据。
下图应该清楚的看懂整个cell的布局
其实这种做法并不好,一个cell是能完成,但是代码看起来就有点乱糟糟的感觉,正确的做法是应该有两种样式的cell。分别是账单类型为收入,账单类型为支出两种样式。
很多人都应该碰到过,滑动tableView的时候Cell的数据会出现混乱,我是这样解决的,在自定义cell重写- (void)prepareForReuse
函数,将cell里面的控件元素的属性和对象统统置为nil。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//* 解决tableView滚动导致数据混乱 准备重用,防止滚动出现数据错乱 */ - (void)prepareForReuse { [super prepareForReuse]; self.timeLineBill = nil; self.categoryImageBtn.imageView.image = nil; self.leftCategoryNameLabel.text = nil; self.leftMoneyLabel.text = nil; self.leftRemarkLabel.text = nil; self.rightCategoryNameLabel.text = nil; self.rightMoneyLabel.text = nil; self.rightRemarkLabel.text = nil; self.lastBill = NO; } |
细心的人可能看到了我在下滑tableview的时候,中间的时光轴线也跟着变长。当我下滑到一定程度,然后松手就会push到新增账单界面,而且这个push动画不是系统自带的push动画。
下面我一一为大家解答:
时光轴的线条是怎么变长的?
第一步、我是新增的一个UIView,默认frame为(SCREEN_SIZE.width-1)/2,0 , 1, 0)
,将它加到tableview上面。
1 2 3 |
self.dropdownLineView = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_SIZE.width-1)/2,0 , 1, 0)]; self.dropdownLineView.backgroundColor = LineColor; [self.tableView addSubview:self.dropdownLineView]; |
第二步、在UIScrollViewDelegate的 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
代理函数里面获取滑动的y值。判断其方向并重新设置dropdownLineView
的frame即可
1 2 3 4 5 6 7 8 9 10 11 12 |
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { /** 当下拉的时候才有动画 y>0下拉,y0) { /** * 疑问:为什么是`y`是`-y`不是`0`,因为`dropdownLineView`是添加到`tableView`的,所以当`tabelView`拉下的时候`dropdownLineView`也会跟着向下移动。 * 当`y`是`-y`的时候`dropdownLineView`会向上移动`y`个单位,才会达到我们理想的效果 */ self.dropdownLineView.frame = CGRectMake((SCREEN_SIZE.width-1)/2, -y, 1, y); [self.tableView bringSubviewToFront:self.dropdownLineView]; /** 饼图+号按钮动画*/ [self.headerView animationWithCreateBtnDuration:1.0f angle:y]; } } |
时光轴界面到添加账单(修改账单)界面的转场动画(LYPushTransition,LYPopTransition)
使用的是自定义的转场动画,具体如何使用请看喵神 和 KittenYang 的blog,推荐几句代码快速集成自定义转场效果+全手势驱动
1.首先定一个class
,继承至NSObject
,遵守UIViewControllerAnimatedTransitioning
协议。
2.需要实现两个方法