开源项目链接:https://github.com/RocketsChen/CDDStore
项目介绍
项目还是经典的 MVC + UITabbarController+UINavigationController架构组件而成
展示部分代码:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
//点击tabBarItem动画
[self tabBarButtonClick:[self getTabBarButton]];
}
- (UIControl *)getTabBarButton{
NSMutableArray *tabBarButtons = [[NSMutableArray alloc]initWithCapacity:0];
for (UIView *tabBarButton in self.tabBar.subviews) {
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]){
[tabBarButtons addObject:tabBarButton];
}
}
UIControl *tabBarButton = [tabBarButtons objectAtIndex:self.selectedIndex];
return tabBarButton;
}
#pragma mark - 点击动画
- (void)tabBarButtonClick:(UIControl *)tabBarButton
{
for (UIView *imageView in tabBarButton.subviews) {
if ([imageView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
//需要实现的帧动画,这里根据自己需求改动
CAKeyframeAnimation *animation = [CAKeyframeAnimation
animation];
animation.keyPath = @"transform.scale";
animation.values = @[@1.0,@1.1,@0.9,@1.0];
animation.duration = 0.3;
animation.calculationMode = kCAAnimationCubic;
//添加动画
[imageView.layer addAnimation:animation forKey:nil];
}
}
}
整个Demo的数据都是通过Charles拦截商品链接手写Plist,然后利用MJExtension字典转模型如下截图名字起得很随意勿怪
目前主要实现的功能
1.初始化项目骨架搭建,首页、分类、购物车、我的四大模块的界面
2.本地数据库我的数据本地储存,支持改动保存
3.点击商品分类,进入数据界面可切换视图形态,搜索悬停处理,足迹和返回顶部
4.点击进入详情界面,数据传入,分为商品、详情、评价三大模块,并在商品界面细分详情如果推荐商品,展示部分用户评价(类似国美在线)
详情界面分析:主要还是利用UICollectionview来完成商品详情界面的需求界面原型可参考国美商品详情,提一句,整个项目复杂界面几乎都是用UICollectionview来完成,95%以上View都是采用纯代码来实现的(考虑后期重构)
代码展示:
#pragma mark - 接受通知
- (void)acceptanceNote
{
//滚动到详情
__weak typeof(self)weakSlef = self;
_dcObserve = [[NSNotificationCenter defaultCenter]addObserverForName:@"scrollToDetailsPage" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[weakSlef topBottonClick:weakSlef.bgView.subviews[1]]; //跳转详情
}];
_dcObserve = [[NSNotificationCenter defaultCenter]addObserverForName:@"scrollToCommentsPage" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[weakSlef topBottonClick:weakSlef.bgView.subviews[2]]; //跳转到评论界面
}];
}
######代码展示:
#pragma mark - 头部View
- (void)setUpTopButtonView
{
NSArray *titles = @[@"商品",@"详情",@"评价"];
CGFloat margin = 5;
_bgView = [[UIView alloc] init];
_bgView.dc_centerX = ScreenW * 0.5;
_bgView.dc_height = 44;
_bgView.dc_width = (_bgView.dc_height + margin) * titles.count;
_bgView.dc_y = 0;
self.navigationItem.titleView = _bgView;
CGFloat buttonW = _bgView.dc_height;
CGFloat buttonH = _bgView.dc_height;
CGFloat buttonY = _bgView.dc_y;
for (NSInteger i = 0; i < titles.count; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:titles[i] forState:0];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.tag = i;
button.titleLabel.font = PFR15Font;
[button addTarget:self action:@selector(topBottonClick:) forControlEvents:UIControlEventTouchUpInside];
CGFloat buttonX = i * (buttonW + margin);
button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
[_bgView addSubview:button];
}
UIButton *firstButton = _bgView.subviews[0];
[self topBottonClick:firstButton]; //默认选择第一个
UIView *indicatorView = [[UIView alloc]init];
self.indicatorView = indicatorView;
indicatorView.backgroundColor = [firstButton titleColorForState:UIControlStateSelected];
indicatorView.dc_height = 2;
indicatorView.dc_y = _bgView.dc_height - indicatorView.dc_height;
[firstButton.titleLabel sizeToFit];
indicatorView.dc_width = firstButton.titleLabel.dc_width;
indicatorView.dc_centerX = firstButton.dc_centerX;
[_bgView addSubview:indicatorView];
}
声明
#import "DCDetailShufflingHeadView.h" //头部轮播
#import "DCDetailGoodReferralCell.h" //商品标题价格介绍
#import "DCDetailShowTypeCell.h" //种类
#import "DCShowTypeOneCell.h" //种类01
#import "DCShowTypeTwoCell.h" //种类02
#import "DCShowTypeThreeCell.h" //种类03
#import "DCShowTypeFourCell.h" //种类04
#import "DCDetailServicetCell.h" //服务
#import "DCDetailLikeCell.h" //猜你喜欢
#import "DCDetailOverFooterView.h" //尾部结束
#import "DCDetailPartCommentCell.h" //部分评论
#import "DCDeatilCustomHeadView.h" //自定义头部
注册
//注册header
[_collectionView registerClass:[DCDetailShufflingHeadView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDetailShufflingHeadViewID];
[_collectionView registerClass:[DCDeatilCustomHeadView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDeatilCustomHeadViewID];
//注册Cell
[_collectionView registerClass:[DCDetailGoodReferralCell class] forCellWithReuseIdentifier:DCDetailGoodReferralCellID];
[_collectionView registerClass:[DCShowTypeOneCell class] forCellWithReuseIdentifier:DCShowTypeOneCellID];
[_collectionView registerClass:[DCShowTypeTwoCell class] forCellWithReuseIdentifier:DCShowTypeTwoCellID];
[_collectionView registerClass:[DCShowTypeThreeCell class] forCellWithReuseIdentifier:DCShowTypeThreeCellID];
[_collectionView registerClass:[DCShowTypeFourCell class] forCellWithReuseIdentifier:DCShowTypeFourCellID];
[_collectionView registerClass:[DCDetailLikeCell class] forCellWithReuseIdentifier:DCDetailLikeCellID];
[_collectionView registerClass:[DCDetailPartCommentCell class] forCellWithReuseIdentifier:DCDetailPartCommentCellID];
[_collectionView registerClass:[DCDetailServicetCell class] forCellWithReuseIdentifier:DCDetailServicetCellID];
//注册Footer
[_collectionView registerClass:[DCDetailOverFooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:DCDetailOverFooterViewID];
[_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"UICollectionElementKindSectionFooter"]; //间隔
实现
#pragma mark - <UICollectionViewDataSource>
- (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 6;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return (section == 0 ||section == 2 || section == 3) ? 2 : 1;
}
#pragma mark - <UICollectionViewDelegate>
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *gridcell = nil;
DCUserInfo *userInfo = UserInfoData;
if (indexPath.section == 0) {
if (indexPath.row == 0) {
DCDetailGoodReferralCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCDetailGoodReferralCellID forIndexPath:indexPath];
cell.goodTitleLabel.text = _goodTitle;
cell.goodPriceLabel.text = [NSString stringWithFormat:@"¥ %@",_goodPrice];
cell.goodSubtitleLabel.text = _goodSubtitle;
[DCSpeedy dc_setUpLabel:cell.goodTitleLabel Content:_goodTitle IndentationFortheFirstLineWith:cell.goodPriceLabel.font.pointSize * 2];
cell.shareButtonClickBlock = ^{
NSLog(@"点击了分享");
};
gridcell = cell;
}else if (indexPath.row == 1){
DCShowTypeFourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCShowTypeFourCellID forIndexPath:indexPath];
gridcell = cell;
}
}else if (indexPath.section == 1 || indexPath.section == 2 ){
if (indexPath.section == 1) {
DCShowTypeOneCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCShowTypeOneCellID forIndexPath:indexPath];
cell.contentLabel.text = @"红色 全网通 1个";
gridcell = cell;
}else{
if (indexPath.row == 0) {
DCShowTypeTwoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCShowTypeTwoCellID forIndexPath:indexPath];
cell.contentLabel.text = userInfo.defaultAddress; //地址
gridcell = cell;
}else{
DCShowTypeThreeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCShowTypeThreeCellID forIndexPath:indexPath];
gridcell = cell;
}
}
}else if (indexPath.section == 3){
DCDetailServicetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCDetailServicetCellID forIndexPath:indexPath];
NSArray *btnTitles = @[@"以旧换新",@"可选增值服务"];
NSArray *btnImages = @[@"detail_xiangqingye_yijiuhuanxin",@"ptgd_icon_zengzhifuwu"];
NSArray *titles = @[@"以旧换新再送好礼",@"为商品保价护航"];
[cell.serviceButton setTitle:btnTitles[indexPath.row] forState:UIControlStateNormal];
[cell.serviceButton setImage:[UIImage imageNamed:btnImages[indexPath.row]] forState:UIControlStateNormal];
cell.serviceLabel.text = titles[indexPath.row];
if (indexPath.row == 0) {//分割线
[DCSpeedy dc_setUpLongLineWith:cell WithColor:[[UIColor lightGrayColor]colorWithAlphaComponent:0.4] WithHightRatio:0.6];
}
gridcell = cell;
}else if (indexPath.section == 4){
DCDetailPartCommentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCDetailPartCommentCellID forIndexPath:indexPath];
cell.backgroundColor = [UIColor orangeColor];
gridcell = cell;
}else if (indexPath.section == 5){
DCDetailLikeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:DCDetailLikeCellID forIndexPath:indexPath];
gridcell = cell;
}
return gridcell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *reusableview = nil;
if (kind == UICollectionElementKindSectionHeader){
if (indexPath.section == 0) {
DCDetailShufflingHeadView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDetailShufflingHeadViewID forIndexPath:indexPath];
headerView.shufflingArray = _shufflingArray;
reusableview = headerView;
}else if (indexPath.section == 5){
DCDeatilCustomHeadView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDeatilCustomHeadViewID forIndexPath:indexPath];
reusableview = headerView;
}
}else if (kind == UICollectionElementKindSectionFooter){
if (indexPath.section == 5) {
DCDetailOverFooterView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:DCDetailOverFooterViewID forIndexPath:indexPath];
reusableview = footerView;
}else{
UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"UICollectionElementKindSectionFooter" forIndexPath:indexPath];
footerView.backgroundColor = DCBGColor;
reusableview = footerView;
}
}
return reusableview;
;
}
#pragma mark - item宽高
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) { //商品详情
return (indexPath.row == 0) ? CGSizeMake(ScreenW, [DCSpeedy dc_calculateTextSizeWithText:_goodTitle WithTextFont:16 WithMaxW:ScreenW - DCMargin * 6].height + [DCSpeedy dc_calculateTextSizeWithText:_goodPrice WithTextFont:20 WithMaxW:ScreenW - DCMargin * 6].height + [DCSpeedy dc_calculateTextSizeWithText:_goodSubtitle WithTextFont:12 WithMaxW:ScreenW - DCMargin * 6].height + DCMargin * 4) : CGSizeMake(ScreenW, 35);
}else{
return (indexPath.section == 1 || indexPath.section == 2) ? CGSizeMake(ScreenW, 60) : (indexPath.section == 3) ? CGSizeMake(ScreenW / 2, 60) : (indexPath.section == 4) ?CGSizeMake(ScreenW, 270) :CGSizeMake(ScreenW, (ScreenW / 3 + 60) * 2 + 20);
}
}
#pragma mark - foot宽高
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
return (section == 5) ? CGSizeMake(ScreenW, 35) : CGSizeMake(ScreenW, DCMargin);
}
总结一下
- 上个月可能真的有点闲,所以想写个开源商城类的Demo,原本以为半个月左右就能ok了结果越写越多,最近想着可能不能一直更新的东西所以先把初步版本开源出来!
- 项目几乎是全代码实现的,写得很简单逻辑也不算复杂但肯定也会有很多不足,后续在更新的同时会逐步重构!
- 项目中有问题,Bug等欢迎Issues我!