開源項(xiàng)目鏈接:https://github.com/RocketsChen/CDDStore
項(xiàng)目介紹

首頁
項(xiàng)目還是經(jīng)典的 MVC + UITabbarController+UINavigationController架構(gòu)組件而成
展示部分代碼:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
//點(diǎn)擊tabBarItem動(dòng)畫
[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 - 點(diǎn)擊動(dòng)畫
- (void)tabBarButtonClick:(UIControl *)tabBarButton
{
for (UIView *imageView in tabBarButton.subviews) {
if ([imageView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
//需要實(shí)現(xiàn)的幀動(dòng)畫,這里根據(jù)自己需求改動(dòng)
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;
//添加動(dòng)畫
[imageView.layer addAnimation:animation forKey:nil];
}
}
}
整個(gè)Demo的數(shù)據(jù)都是通過Charles攔截商品鏈接手寫Plist,然后利用MJExtension字典轉(zhuǎn)模型如下截圖名字起得很隨意勿怪

部分Plist
目前主要實(shí)現(xiàn)的功能
1.初始化項(xiàng)目骨架搭建,首頁、分類、購物車、我的四大模塊的界面
2.本地?cái)?shù)據(jù)庫我的數(shù)據(jù)本地儲(chǔ)存,支持改動(dòng)保存
3.點(diǎn)擊商品分類,進(jìn)入數(shù)據(jù)界面可切換視圖形態(tài),搜索懸停處理,足跡和返回頂部
4.點(diǎn)擊進(jìn)入詳情界面,數(shù)據(jù)傳入,分為商品、詳情、評(píng)價(jià)三大模塊,并在商品界面細(xì)分詳情如果推薦商品,展示部分用戶評(píng)價(jià)(類似國美在線)

分類

詳情
詳情界面分析:主要還是利用UICollectionview來完成商品詳情界面的需求界面原型可參考國美商品詳情,提一句,整個(gè)項(xiàng)目復(fù)雜界面幾乎都是用UICollectionview來完成,95%以上View都是采用純代碼來實(shí)現(xiàn)的(考慮后期重構(gòu))

詳情文件夾截圖
代碼展示:
#pragma mark - 接受通知
- (void)acceptanceNote
{
//滾動(dòng)到詳情
__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]]; //跳轉(zhuǎn)詳情
}];
_dcObserve = [[NSNotificationCenter defaultCenter]addObserverForName:@"scrollToCommentsPage" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
[weakSlef topBottonClick:weakSlef.bgView.subviews[2]]; //跳轉(zhuǎn)到評(píng)論界面
}];
}
######代碼展示:
#pragma mark - 頭部View
- (void)setUpTopButtonView
{
NSArray *titles = @[@"商品",@"詳情",@"評(píng)價(jià)"];
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]; //默認(rèn)選擇第一個(gè)
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" //商品標(biāo)題價(jià)格介紹
#import "DCDetailShowTypeCell.h" //種類
#import "DCShowTypeOneCell.h" //種類01
#import "DCShowTypeTwoCell.h" //種類02
#import "DCShowTypeThreeCell.h" //種類03
#import "DCShowTypeFourCell.h" //種類04
#import "DCDetailServicetCell.h" //服務(wù)
#import "DCDetailLikeCell.h" //猜你喜歡
#import "DCDetailOverFooterView.h" //尾部結(jié)束
#import "DCDetailPartCommentCell.h" //部分評(píng)論
#import "DCDeatilCustomHeadView.h" //自定義頭部
注冊(cè)
//注冊(cè)header
[_collectionView registerClass:[DCDetailShufflingHeadView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDetailShufflingHeadViewID];
[_collectionView registerClass:[DCDeatilCustomHeadView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:DCDeatilCustomHeadViewID];
//注冊(cè)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];
//注冊(cè)Footer
[_collectionView registerClass:[DCDetailOverFooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:DCDetailOverFooterViewID];
[_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"UICollectionElementKindSectionFooter"]; //間隔
實(shí)現(xiàn)
#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(@"點(diǎn)擊了分享");
};
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 = @"紅色 全網(wǎng)通 1個(gè)";
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 = @[@"以舊換新",@"可選增值服務(wù)"];
NSArray *btnImages = @[@"detail_xiangqingye_yijiuhuanxin",@"ptgd_icon_zengzhifuwu"];
NSArray *titles = @[@"以舊換新再送好禮",@"為商品保價(jià)護(hù)航"];
[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);
}

我的
總結(jié)一下
- 上個(gè)月可能真的有點(diǎn)閑,所以想寫個(gè)開源商城類的Demo,原本以為半個(gè)月左右就能ok了結(jié)果越寫越多,最近想著可能不能一直更新的東西所以先把初步版本開源出來!
- 項(xiàng)目幾乎是全代碼實(shí)現(xiàn)的,寫得很簡單邏輯也不算復(fù)雜但肯定也會(huì)有很多不足,后續(xù)在更新的同時(shí)會(huì)逐步重構(gòu)!
- 項(xiàng)目中有問題,Bug等歡迎Issues我!