Swift-高仿半糖App

IOS-Swift2.0 高仿半糖App


写在前面的话

--少年我是去年毕业做IOS开发的,这个项目大概是2016年1月份到现在做完的,项目刚开始没学过Swift语言,但想着不会就该去挑战,于是边学习边做这个项目,现在对Swift也有了一定的了解
,在此感谢维尼的小熊的指导

关于项目(GitHub地址在文章最下方)

--这个开源项目为半糖,官网➡,类似于美丽说,一款电商App,使用语言:Swift2.0,开发工具: Xcode 7.1,纯代码开发,耗时两个多月,数据为本地数据,用Charles进行抓包。
--项目测试机为5S,UI没有对6/6S进行适配
--因为开发时间有限,APP里面的各种分类相当繁多,因此首页中测试的话点第一个分类,第一个cell,一般都是有数据的,没有也会提示。
--我是个新手,Bug是难免的嘛。如果发现有Bug和疑问,请向我联系,QQ、简书、微博都可以
--Tips:首页支持3D Touch,可以试试哦~

项目效果图

首页展示

首页轮播图加展示.gif
首页-清单展示
首页-清单展示.gif
首页-搜索分类展示
首页-搜索展示.gif

3D Touch展示(用6S及6S以上测试)

3DTouch展示.gif

广场展示

首页-广场展示.gif

秀我展示.gif

消息(这一部分😂,我没好友,没粉丝,抓包木有数据,所以就按照自己的想法做咯)

消息.gif

个人中心(换头像请用真机测试~)

个人中心.gif

项目详细讲解 (按APP的启动顺序来)

启动页面

启动页面.gif

主要代码如下:
1.在appDelegate中
self.window?.rootViewController = mainViewController()

//MARK: App首次启动显示 app的简介
    func mainViewController() -> UIViewController{
        //firstStart不为空,不是是第一次启动
        if  NSUserDefaults.standardUserDefaults().objectForKey("FirstStart") != nil {
            return self.tabbarController
        }else {
            //是第一次启动
            NSUserDefaults.standardUserDefaults().setObject(false, forKey: "FirstStart")
            let firstVC = FirstStartViewController()

            return firstVC
        }
    }

Tips: 用户第一次启动App的时候self.window.rootViewController = FirstStartViewController() 使用户进入引导页,动画完成后,点击『开启App之旅』,引导页发出 通知,appDelegate接受通知,再将self.window?.rootViewController = self.tabBarController

首页-展示

①最好的设计思路应该是这样的:
tmp4c68a801.png

Tips:以下的思路 在个人中心很完整,前去看看哈

1.红色部分设计为 collectionHeaderView

方法: 初始化collecitonView时 在其layout参数中设置
layout.headerReferenceSize = CGSizeMake(width, height)
然后collectionView 注册这个headerView

public func registerClass(viewClass: AnyClass?, forSupplementaryViewOfKind elementKind: String, withReuseIdentifier identifier: String)`
然后 在collectionView代理方法
`func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
        var reuseView = UICollectionReusableView()
        if kind == UICollectionElementKindSectionHeader {
            let headView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "collectionViewHeaderView", forIndexPath: indexPath)
            
            headView.addSubview(collectionHeadView)
            reuseView = headView
        }
        return reuseView
    }
2.绿色部分为collectionView 只作为容器使用
3.蓝色部分为显示的tableview,添加到collectionView的cell.contentView进行显示

Tips:现在很多App的启动页面也是这个思路,整体为一个UICollectionView,每一个cell都添加UITableView进行显示

②关于cell 动态高度的问题,上图:

tmp3734bf84.png

蓝色的这一部分是清单详情中的描述内容,JSON中的描述文字都不一样,所以导致整个cell的高度都是动态不定的
Tips:
1.在cell所有的model中添加cellHeight字段,在tableView代理方法heightForRowAtIndexPath中,判断model中的cellHeight字段是不是为空,有值则返回该值,类似

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       //model为对应cell的model
      if model.cellHeight != nil {
             return model.cellHeight
       }
    return 30
}

2.cell中的属性model 重写set方法,类似

var model: YourModel{
  didSet{
        //--------
            做你的操作
        //-------
        if model.cellHeight == nil {
        model.cellHeight = 你计算后的高度
        }
    }
}
③ 3D Touch

Tips:其实App中应用最多的也就是不用点进去看。可以预览下一级显示的内容,比如 微信

3D Touch通用.gif

上代码:
viewDidLoad()self.add3DTouch()

//MARK: 添加 3D touch功能
    func add3DTouch() {
        //1.检测 3D touch 是否可用
        if traitCollection.forceTouchCapability == .Available {
            //3DTouch可用,
            registerForPreviewingWithDelegate(self, sourceView: view)
        }else {
            //不可用
            TipView.showMessage("不支持3Dtouch,换个6S吧,不谢😂")    
        }
    }

Tips:
1 registerForPreviewingWithDelegate(delegate: UIViewControllerPreviewingDelegate, sourceView: UIView)方法中delegate即为当前控制器self,sourceView即为感应3DTouch功能的View,当前控制器中,我选择的是self.view
2.控制器上添加代理UIViewControllerPreviewingDelegate,实现方func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController?func previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController),
看代码:

①这一部分其实就两个步骤

  • 1.给3D Touch 你要预览的ViewController
  • 2.设定3D Touch预览控制器的尺寸大小
func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        
        
        //-----这一过程这么繁琐  说白了就是找到当前手指点到的 tableviewCell,后面 3Dtouch 预览的时候会用到 原尺寸 cell.frame
        let index = Int( showCollectionView.contentOffset.x / SCREEN_WIDTH )
        let collectionViewCell = showCollectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 0, inSection: index))
        var tableView = UITableView()
        for aview in collectionViewCell!.contentView.subviews {
            if aview.isKindOfClass(UITableView.self) {
                tableView = aview as! UITableView
            }
        }
        //*******
        
        let indexPath = tableView.indexPathForRowAtPoint(location)
        let cell = tableView.cellForRowAtIndexPath(indexPath!) as! HomeCell
        
        let detailListContrller = ListDetailViewController(listId: "1872",transImage: cell.imgView.image!)
        
    
        //预显示的尺寸
        detailListContrller.preferredContentSize = CGSizeMake(SCREEN_WIDTH, 600)
        //源尺寸
        previewingContext.sourceRect = cell.frame
        
        return detailListContrller
    }

②对即将预览的ViewController,做一些操作,比如隐藏tabbar,隐藏导航栏等等,然后显示出来

func previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController) {
        showViewController(viewControllerToCommit, sender: self)
    }

广场-展示

设计思路如图:

tmp4c3452b2.png
与首页相似,红色部分View是蓝色 mainCollectionView的headerView,红色View中又包含着一个collectionView
下拉刷新控件:
下拉刷新控件.gif

Tips:下拉刷新控件 使用SVPullToRefresh 框架,然后在它的文件中修改了一个方法,把自己想要出现的动图加了进去

- (SVPullToRefreshArrow *)arrow {
    if(!_arrow) {
        _arrow = [[SVPullToRefreshArrow alloc]initWithFrame:CGRectMake(0, self.bounds.size.height-54, 22, 48)];
        _arrow.backgroundColor = [UIColor clearColor];
              //将框架自带的刷新箭头屏蔽掉
//      [self addSubview:_arrow];
        
        //这一部分是我自定义显示的View
        UIImageView *gifImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.bounds.size.height-54, 125, 125)];
        self.clipsToBounds = YES;
        gifImgView.backgroundColor = [UIColor whiteColor];
        gifImgView.image = [UIImage sd_animatedGIFNamed:@"refreshGif"];
        //设置刷新动图只在Loading状态下显示
        [self setCustomView:gifImgView forState:SVPullToRefreshStateLoading];

    }
    return _arrow;
}

秀出自我

这一部分的实现思路比较简单
1.在appdelegate中,实现tabbarControllerDelegate方法,shouldSelectViewController中,判断每次点击的是不是ShowMeController,如果是,则返回false,然后在当前的控制器viewController.presentViewController(ShowMeViewController, animated: true, completion: nil)

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
        
        
        let childArray = tabbarController.childViewControllers
        let index = childArray.indexOf(viewController)
        if index == 2 {
            print("Show me!")
            presentShowMeViewController(viewController)
            return false
        }else if index == 3 {
            //点击 '消息中心' 延迟5s 后发出通知
            //模拟网络刷新
            viewController.tabBarItem.title = nil
            postNotificationCenter(tabbarController.viewControllers!)
        }
        
        return true
    }

2.对于调用照相机的方法,首先判断有没有摄像头

if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
            imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
            presentViewController(imagePicker, animated: true, completion: nil)
        }else {
            TipView.showMessage("骚年,找个有摄像头的手机吧。。")
        }

然后viewController中添加代理 UIImagePickerControllerDelegate,UINavigationControllerDelegate
在代理方法中可以获取到刚拍好的图片进行处理

func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            picker.dismissViewControllerAnimated(true, completion: nil)
            self.topView.headerImage = image
        }
        
    }

消息这一部分就很少东西了,因为我没有粉丝,没有消息😂,

为了模拟后台发送消息,在tabBarController的"shouldSelectViewController"中,当点击该控制器时,appdelegate发出通知,MessageViewController中接收通知,提示用户收到消息
//接受 模拟后台的推送、、、、 NSNotificationCenter.defaultCenter().addObserver(self, selector: "hasNewMessage", name: UserHasNewMessage, object: nil)

收到通知以后执行的方法:

func hasNewMessage(){
        print("收到通知了。")
        TipView.showMessage("您有新的消息。但是你看不见😜")
    }

个人中心

这一部分设计思路与广场类似,也都是上面是HeaderView,下面是UICollectionView,不同的是个人中心最上面有一个背景图片,会随着collectionView的contentOffSet变化而放大
设计思路:


tmp2ae3bf03.png

1.黄色View为 UIImageView,处于整个View的下层,collectionView和它的headerView的backgroundColor = UIColor.clearColor()
最后在func scrollViewDidScroll(scrollView: UIScrollView)中调整 backImageView的transform属性即可
2.关于停靠问题,

停靠问题.gif

上图
tmp19a4b2b9.png

,姑且叫它titleView, titleView滚到设定位置时会停靠到导航栏底下,思路如下:

  1. titleView是添加到headerView中的,在scrollViewDidScroll方法中,监听collectionView的contentOffset.y的变化,当titleView到达设定的位置时,titleView.removeFromSuperview(),然后计算frame,将其添加到View上,这样就做除了停靠的效果,这样做比较简单
    😥: 刚开始我单独将titleView添加到view上,collectionView滑动时还得一直更改titleView.frame

聊聊感想哈

其实从OC转向Swift非常简单,这个项目不难,很适合从OC转向swift,或swift初学者。
少年也是第一次发布自己的项目,忘老鸟轻拍,新手共勉,有什么问题或bug联系我哈,欢迎来我的GitHub上赏个Star🌟

GitHub 代码下载地址

代码下载地址,给个star再走🙏
直接打开运行工程

tmp1cbb03b9.png

收到有童鞋反应说,会遇到这样的Bug导致无法运行

tmp788532b0.png

Tips:由于GitHub上传的问题,解决办法如下:

tmp44a0f1ff.png

项目编写中用的切图、标注、及本地数据在我的百度云

切图、数据下载地址-ManoBpp的百度云

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容