高仿小日子Swift2.0

作者: Top_熊 | 来源:发表于2015-09-21 18:40 被阅读20862次

    不知不觉十一马上到了,承诺给大家分享的Swift项目也该兑现了,本次项目为高仿小日子,废话不多说,先看效果吧


    探店效果图探店效果图
    探店详情页效果图探店详情页效果图
    附近地图效果图附近地图效果图
    体验效果图体验效果图
    分类效果图分类效果图
    我的效果图我的效果图
    搜索效果图搜索效果图
    摇一摇效果图摇一摇效果图

    更多效果请用Xcode7.0正式版运行程序查看

    此项目相对来说比较简单,之前用Swift1.2编写的,9月18号,苹果发布了Xcdoe7.0正式版,小熊也将代码更新到了Swift2.0,由于Swift语言还不稳定,每个版本都会出现语法修改,本项目用最新的Xcode7正式版编写,建议使用Xcode7正式版运行工程,项目的接口依然有加密,抱着学习的态度,小熊截取了网络请求返回数据,并且将数据写入到了本地,所以读者用到的数据都是固定的

    本来想挑一个复杂点的项目分享给大家,考虑到公司的项目要在十一前上线,时间比较紧,以及自己对Swift语言还处于摸索阶段,经常也是连蒙加猜的,很多写法还是沿用OC的套路,不过相信对于大家学习Swift语言还是有一定帮助的.很多时候,小熊都是被一个很简单的语法卡住很久,比如如何动态实例化AnyClass对象,还有升级到2.0后,通过NSStringFromClass:方法创建对象是需要追加命名空间的前缀,我记忆很深刻...

    此次写代码的过程中吸取了读者的提议,用的源代码管理工具是git,大家可以在项目的历史版本回退查看项目的从无到有是如何一步一步完善的,由于白天上班,晚上写这个项目,所以中间博客没有怎么更新,读者也可以从代码提交时间看出...都是半夜1 . 2点左右

    在学习Swift语言中,自己也断断续续的总结了一些OC和Swift语法的区别,以及Swift于OC中相同方法的不用写法,我也会在后续时间发布到博客里,让大家避免不必要的麻烦,请持续关注小熊的博客


    下面来介绍此项目的每个模块的思路,这里就按照程序运行展示的页面的顺序逐一与大家分析吧

    引导页(新特性页面)

    • 引导页只在用户第一次运行程序,或者APP升级后第一次运行程序时候出现,为了是提示用户APP的新功能以及改变如下图所展示的效果

      引导页引导页
    • 目前比较主流的方法是使用UICollectionview来实现引导页可以直接复用,如果只是单纯的图片和简单的动画建议使用UICollectionview,如果有比较复杂的动画,也可以用ScrollView来实现,根据项目的不同需求来选择,这里的引导页只有一页,我就直接用的View

    • 在程序启动成功的方法中,首先判断用户是否是第一次运行当前版本的APP,我的做法是用版本号来判断,首先在info中拿出当前程序的版本号,在从UserDefaults取出上次用户运行程序的版本号对比,如果相等,说明没有新版本,直接进入,如果不相等则显示导引页,并且将当前版本写入UserDefaults中,以便下次用户运行APP判断.具体代码如下,返回的控制器作为keyWindow的rootViewController,如果是引导页,并且用户点击了体验按钮,可以发出通知,将KeyWindow的rootViewController切换即可

    privete func showLeadpage() -> UIViewController {
        let versionStr = "CFBundleShortVersionString"
        let cureentVersion = NSBundle.mainBundle().infoDictionary![versionStr] as! String
        let oldVersion = (NSUserDefaults.standardUserDefaults().objectForKey(versionStr) as? String) ?? ""
    
        if cureentVersion.compare(oldVersion) == NSComparisonResult.OrderedDescending {
        NSUserDefaults.standardUserDefaults().setObject(cureentVersion, forKey: versionStr)
        NSUserDefaults.standardUserDefaults().synchronize()
        return LeadpageViewController()
        }
    

    UITabbarController(KeyWindow.rootViewController)

    • 这里小熊自己定义的MainTabBarController继承至UITabBarController,里面装了四个MainNavigationController继承UINavigationController作为子控制器
    • MainNavigationController继承UINavigationController,重写了pushViewController方法,方便统一管理返回按钮和每次Push出新的控制器,自动隐藏底部的TabBar,具体代码如下
     override func pushViewController(viewController: UIViewController, animated: Bool) {
    
        if self.childViewControllers.count > 0 {
            let vc = self.childViewControllers[0]
    
            if self.childViewControllers.count == 1 {
                backBtn.setTitle(vc.tabBarItem.title!, forState: .Normal)
            } else {
                backBtn.setTitle("返回", forState: .Normal)
            }
    
            viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBtn)
            viewController.hidesBottomBarWhenPushed = true
        }
    
        super.pushViewController(viewController, animated: animated)
    }
    

    左上角的城市

    • 由于探店, 体验, 分类都有城市选择按钮,并且一个改变,其余的也都会改变,我的做法是提供一个父类,MainViewController继承至UIViewController,设置navigationItem.leftBarButtonItem为自定义的按钮,并且在viewDidLoad:方法中,添加通知,监听city的改变,一旦监听到当前城市发生改变的通知后,对应的控制器就可以执行对应的操作,需要注意的是每次要将改变后的城市写入到本地持久化存储,以便程序被关闭后再次运行时,可以保留上次用户所选择的城市
    • 选择城市的控制器是CityViewController如下图,城市的展示小熊用的UICollectionview来展示的,需要注意每次ViewController弹出后,用户上一次选择的城市都会自动进入选中状态,具体实现是拿出上一次用户选择的城市,遍历城市列表取出所属的indexPath,然后执行下面方法
        let lastSelectedCityIndexPaht = selectedCurrentCity()
        collView.selectItemAtIndexPath(lastSelectedCityIndexPaht, animated: true, scrollPosition: UICollectionViewScrollPosition.None)
    
    城市选择控制器城市选择控制器
    • 当用户再次选择城市后,将城市写入到本地保存,并且发出城市改变的通知,通知监听者做出相应的操作

    探店如下图所示

    探店效果图探店效果图
    • 导航条上的美天和美辑是将navigationItem.titleView 设置为自定义的DoubleTextView来实现,内部封装好功能,并且通过设置代理将点击事件传递给控制器,顺便提一嘴,Swift中的代理和OC中的一样,也是采用软引用即:weak var delegate: <Delegate>?,提供一个方法便于在scrollView的offsetX发生改变时更新内部控件状态具体实现请参考项目中的代码

    • 在view的最底层添加一个scrollView,设置scorllView的contentSize为屏幕的宽度的2倍,在scrollView上添加俩个TableView,分别是美天的TableView和美辑的TabelView,注意观察,美天tableViewCell有一种cell的样式于美辑的样式是一样的,所以这里只用了两种cell,参考下图,这里是根据服务器返回数据来判断加载哪一种cell,美天的tableView采用的是样式是Group样式,每一组有一个或者多个cell


      EventCell样式效果图EventCell样式效果图
      ThemeCell样式效果图ThemeCell样式效果图
    • 在TableView的代理方法中,根据服务器返回的数据创建对应的cell,喜欢专研的朋友可以查看项目中CustomData文件中的events.json文件查看规律

    • 这里提一下Swift的闭包方法中,需要像OC中一样创建一个weak的指针weak var tmpSelf = self,在闭包方法中调用tmpSelf,直接调用self会引起循环引用,照成内存泄露,控制器无法被销毁问题

    • 点击EventCell弹出的详情页我着重讲一下,先看效果图


      美天详情效果图美天详情效果图
    • 顶部的导航条是自定义的view,在EventViewController的viewWillAppaer方法中,将系统的导航条隐藏掉,添加定义的view作为导航条,按钮也是如此,根据scrollView的偏移量计算透明度,图片的拉伸和按钮的图片改变,由于有俩个scrollView,有些效果需要判断不同scrollView来执行,需要注意的是适当添加标记来防止重复判断,消耗内存

    • 店发现和店详情掌握之前提的导航条titelView也可以轻松搞定,位置也是根据scrollView的Y轴的偏移量来计算,代码并不复杂,具体代码如下

    
    extension EventViewController: UIScrollViewDelegate {
    
        func scrollViewDidScroll(scrollView: UIScrollView) {
    
            // 解决弹出新的控制器后返回后contentSize自动还原的问题
            if loadFinishScrollHeihgt > webView.scrollView.contentSize.height && scrollView === webView.scrollView {
                webView.scrollView.contentSize.height = loadFinishScrollHeihgt
            }
    
            let offsetY: CGFloat = scrollView.contentOffset.y
            // 判断顶部自定义导航条的透明度,以及图片的切换
            customNav.alpha = 1 + (offsetY + NavigationH + EventViewController_ShopView_Height) / scrollShowNavH
            if offsetY + EventViewController_ShopView_Height >= -NavigationH && showBlackImage == false {
                backBtn.setImage(UIImage(named: "back_1"), forState: .Normal)
                likeBtn.setImage(UIImage(named: "collect_1"), forState: .Normal)
                sharedBtn.setImage(UIImage(named: "share_1"), forState: .Normal)
                showBlackImage = true
            } else if offsetY < -NavigationH - EventViewController_ShopView_Height && showBlackImage == true {
                backBtn.setImage(UIImage(named: "back_0"), forState: .Normal)
                likeBtn.setImage(UIImage(named: "collect_0"), forState: .Normal)
                sharedBtn.setImage(UIImage(named: "share_0"), forState: .Normal)
                showBlackImage = false
            }
    
            // 顶部imageView的跟随动画
            if offsetY <= -DetailViewController_TopImageView_Height - EventViewController_ShopView_Height {
                topImageView.frame.origin.y = 0
                topImageView.frame.size.height = -offsetY - EventViewController_ShopView_Height
                topImageView.frame.size.width = AppWidth - offsetY - DetailViewController_TopImageView_Height
                topImageView.frame.origin.x = (0 + DetailViewController_TopImageView_Height + offsetY) * 0.5
            } else {
                topImageView.frame.origin.y = -offsetY - DetailViewController_TopImageView_Height - EventViewController_ShopView_Height
            }
    
            // 处理shopView
            if offsetY >= -(EventViewController_ShopView_Height + NavigationH) {
                shopView.frame = CGRect(x: 0, y: NavigationH, width: AppWidth, height: EventViewController_ShopView_Height)
            } else {
                shopView.frame = CGRect(x: 0, y: CGRectGetMaxY(topImageView.frame), width: AppWidth, height: EventViewController_ShopView_Height)
            }
    
            // 记录scrollView最后的偏移量,用于切换scrollView时同步俩个scrollView的偏移值
            lastOffsetY = offsetY
        }
    }
    
    
    • 店发现 这里相对来说有点麻烦,这里服务器返回的是好长的一串htmlString,由于没有css的布局文件,直接加载htmlStr的话图片是超级的大,有的像素达到4480*3000,直接用webView.loadHTMLString:的方法很不现实,这里我放一段服务器返回的字符串给读者看一下如下图

      html返回的字符串html返回的字符串
    • 由于没有css的布局文件,只能靠自己来约束图片的大小,我采用的方法是通过正则语句过滤出所有图片的宽和高,然后按照屏幕的宽度等比例计算图片的大小,在将修改过的宽和高替换插入到原有的htmlStr中,观察服务器返回的htmlStr是没有title和tag的,也就意味这展示的内容没有标题和标签,所以再动态的将title以及tag的标签插入到字符串中插入代码如下

                    if model?.title != nil {
                        titleStr = String(format: "<p style='font-size:20px;'> %@</p>", model!.title!)
                    }
    
                    if model?.tag != nil {
                        titleStr = titleStr?.stringByAppendingFormat("<p style='font-size:13px; color: gray';>%@</p>", model!.tag!)
                    }
    
    • 再加载修改过图片宽高的htmlStr,然后webViewDidFinishLoad的方法中,通过JS代码将内容的背景色修改,此种方法瑕疵很多,代码如下
    webView.stringByEvaluatingJavaScriptFromString("document.getElementsByTagName('body')[0].style.background='#F5F5F5';")
    
    • 对webView图片的处理,小熊感觉还有一个更好的思路可以尝试,不过在项目中没有实现成功,这里我觉得可以动态的将所有的的htmlStr中image都拦截掉,不让webView自己加载图片,并且通过条件过滤保留图片的url地址,动态的计算出图片的位置和大小,用本地加载图片的方法加载图片,放到对应webView.scrollView的位置,这样就可以实现缓存,以及点击等事件,不过需要于js端的配合,这个以后我一定会再尝试的,可行的话我会将demo分享给大家

    • 在webView的最底部,也会根据服务器返回的数据动态的加入猜你喜欢的cell,这里只需要在webView加载完毕后,确认webView.scrollView.contentSize.height后面添加对应的moreView即可!需要注意的是,添加内容后,也要相应的增加webView.scrollView.height的高度用来显示新添加的控件

    附近(效果如下图所示)

    附近地图效果图附近地图效果图
    • 在程序启动成功的方法中,首先会获取用户授权使用定位功能,这里我封装了一个管理用户位置的单例,当用户授权App可以使用定位后,获取用户当前的经纬度并且将用户位置的经纬度保存,当用户点击附近按钮弹出控制器时,发送网络请求给服务器,服务器通过用户当前的经纬度返回附近店铺的信息,由于没有数据,所以每次返回的都是小熊写在本地的数据,解析对应的数据加载到tableView显示,通过用户的位置以及店铺的位置可以计算出距离给label设置用户当前距离店铺的距离KM
    • 翻转动画,根据右上角按钮的状态使用下面方法完成翻转动画
            if sender.selected {
                UIView.transitionFromView(nearTableView, toView: mapView, duration: 1.0, options: UIViewAnimationOptions.TransitionFlipFromLeft, completion: nil)
            } else {
                UIView.transitionFromView(mapView, toView: nearTableView, duration: 1.0, options: UIViewAnimationOptions.TransitionFlipFromRight, completion: nil)
            }
    
    • mapView中,有一个UICollectionview,一个定位到当前用户位置的按钮,以及自定义的大头针若干,判断大头针的选中状态切换大头针的图片,根据选中的shopCell切换选中大头针等,都是一些计算性的代码,具体代码参考WNXMapView.swift文件,点击shopCell推出对应的控制器即可

    体验

    • 体验控制器值得一提的是TableViewCell的高度计算方法采用了iOS8.0的新方法,通过约束cell底部来自动计算cell的高度,在xib中约束好cell底部后,在初始化TableView时,通过下面俩句代码就可以实现cell自动计算高度
            // 估算cell的高度
            tableV.estimatedRowHeight = 200
             // 设置tableView的自动布局样式
            tableV.rowHeight = UITableViewAutomaticDimension
    
    • 这个方法局限性比较大,只可以在确定cell底部约束对象时才可以采用,根据需求情况有时使用会比较方便必须iOS8.0以上才可以

    体验详情控制器效果如下图所示

    • 可以看出体验详情控制器与探店详情控制器大同小异,不同的是底部动态添加的控件.
    • 报名控制器需要注意键盘对TextField的遮盖,监听键盘将要改变Frame的通知,设置scrollView的偏移Y轴的偏移值,保证键盘无法遮盖住输入框,网网项目中最耗时的就是这些细节性的动画,既考验开发人员的细心,又考验开发人员的耐心
    • 当用户输入好报名信息并且点击提交后,将报名信息通过sql语句插入到本地数据库,为了给后面我的订单中使用

    搜索控制器(效果图如下)

    搜索控制器搜索控制器
    • 这里有个小小的动画,是根据键盘监听键盘Frame改变发出的通知来做出相应的动画,值得提醒大家的是:通过真机调试发现,当用户手机安装三方的键盘时(搜狗输入法...),键盘弹出和隐藏的通知会连续发出多次,需要加上标记来判断即可,模拟器中我还没发现这种情况,望大家注意

    我的

    用户头像View
    • 首先利用封装的用户账号管理工具判断当前用户是否登陆,如果未登录,则推出登陆界面,当用户登陆或者注册后,将用户的账号,以及加密过的密码发送给服务器,以及在本地备份,便于程序关闭后,下次运行程序时,用户不需要再次登陆.

    • 如果用户已登录并且点击iconView后,打开UIImagePickerController,根据用户选择的是打开相册还是相机来设置UIImagePickerController对象的sourceType.当用户点击相机时,需要先判断用户当前摄像头是否可用,注意模拟器没有摄像头,需要在真机调试才可以打开摄像头,设置照片为可编辑模式,这样用户选择的图片将会是正方形,方便头像的圆形的裁剪

    • 这里有一个地方值得注意,就是随着相机像素的提高,实际用户选择的图片都是很大的,有的高达5.6M,如果直接使用用户选着的图片,非常消耗内存,并且也用不到这么高像素的图片,可以当用户选着好图片后,在UIImagePickerController对应的代理方法中,先将图片进行重新绘制为需要的大小,在设置给iconView具体代码如下所示

    /// MARK: 摄像机和相册的操作和代理方法
    extension MeViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        /// 打开照相功能
        private func openCamera() {
            if UIImagePickerController.isSourceTypeAvailable(.Camera) {
                pickVC.sourceType = .Camera
                self.presentViewController(pickVC, animated: true, completion: nil)
            } else {
                SVProgressHUD.showErrorWithStatus("模拟器没有摄像头,请链接真机调试", maskType: SVProgressHUDMaskType.Black)
            }
        }
        
        /// 打开相册
        private func openUserPhotoLibrary() {
            pickVC.sourceType = .PhotoLibrary
            pickVC.allowsEditing = true
            presentViewController(pickVC, animated: true, completion: nil)
        }
        
        func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
            // 对用户选着的图片进行质量压缩,上传服务器,本地持久化存储
            if let typeStr = info[UIImagePickerControllerMediaType] as? String {
                if typeStr == "public.image" {
                    if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
                        var data: NSData?
                        let smallImage = UIImage.imageClipToNewImage(image, newSize: iconView!.iconButton.size)
                        if UIImagePNGRepresentation(smallImage) == nil {
                            data = UIImageJPEGRepresentation(smallImage, 0.8)
                        } else {
                            data = UIImagePNGRepresentation(smallImage)
                        }
                        
                        if data != nil {
                            do {
                                // TODO: 将头像的data传入服务器
                                // 本地也保留一份data数据
                                try NSFileManager.defaultManager().createDirectoryAtPath(theme.cachesPath, withIntermediateDirectories: true, attributes: nil)
                            } catch _ {
                            }
                            NSFileManager.defaultManager().createFileAtPath(SD_UserIconData_Path, contents: data, attributes: nil)
                            
                            iconView!.iconButton.setImage(UIImage(data: NSData(contentsOfFile: SD_UserIconData_Path)!)!.imageClipOvalImage(), forState: .Normal)
                            
                        } else {
                            SVProgressHUD.showErrorWithStatus("照片保存失败", maskType: SVProgressHUDMaskType.Black)
                        }
                    }
                }
            } else {
                SVProgressHUD.showErrorWithStatus("图片无法获取", maskType: SVProgressHUDMaskType.Black)
            }
            
            picker.dismissViewControllerAnimated(true, completion: nil)
        }
        
        func imagePickerControllerDidCancel(picker: UIImagePickerController) {
            pickVC.dismissViewControllerAnimated(true, completion: nil)
        }
    }
    

    摇一摇

    摇一摇效果图摇一摇效果图
    • 摇一摇使用的是苹果提供好的方法override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?),每当用户摇晃手机时,系统就会自动调用此方法,在方法内部做出相应的动画即可关键代码就这下面这几句,如果是使用模拟器可以点击窗口上**Hardware -> Shake Gesture**来进行模拟调试
        override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?) {
            tableView!.hidden = true
            let animateDuration: NSTimeInterval = 0.3
            let offsetY: CGFloat = 50
            
            UIView.animateWithDuration(animateDuration, animations: { () -> Void in
                self.yaoImageView1.transform = CGAffineTransformMakeTranslation(0, -offsetY)
                self.yaoImageView2.transform = CGAffineTransformMakeTranslation(0, offsetY)
                
                }) { (finish) -> Void in
                    let popTime = dispatch_time(DISPATCH_TIME_NOW,Int64(0.5 * Double(NSEC_PER_SEC)))
                    dispatch_after(popTime, dispatch_get_main_queue(), { () -> Void in
                        
                        UIView.animateWithDuration(animateDuration, animations: { () -> Void in
                            self.yaoImageView1.transform = CGAffineTransformIdentity
                            self.yaoImageView2.transform = CGAffineTransformIdentity
                            }, completion: { (finish) -> Void in
    
                                self.loadShakeData()
                                // 音效
                                AudioServicesPlayAlertSound(self.soundID!)
                        })
                    })
            }
    

    清理缓存

    • 这里我封装了一个工具类:FileTool,通过类方法可以调用查看指定路径文件夹的大小FileTool.folderSize(path: String),以及异步删除指路径下的全部文件夹FileTool.cleanFolder(path: String, complete: () -> ()),complete为删除完成后的回调

    三方分享

    • 这里我封装了一个分享工具类ShareTool,集成了新浪SSO,微信SSO认证,以及新浪OAuth认证.采用的是友盟分享SDK,以及自定义的分享界面,需要注意的是由于微信没有OAuth认证,所以只有在设备安装了微信时才可以分享(插上你的真机分享点击分享试一试),模拟器中只可以使用新浪微博的分享.
    • 如果想要将新浪分享的来自xx和图片修改为自己应用的图标,可以在新浪的开发者平台注册成为开发者,添加应用并且上线,通过审核,在友盟网站我的产品中将设置主题修改相应的属性即可.
    • 在iOS9.0后,需要设置白名单以及回调的白名单才可以完成分享后的回调

    关于项目的介绍基本就这么多了,更多的细节和内容直接看代码来的更快捷一些,对于Swift小熊也是又爱又恨,相信随着版本的不断更新,Swift语言也会越来越趋于稳定,Xcode对Swift的支持也会越来越好的,总算对自己的承诺有了一个小小的交代,如果有小熊的项目有帮助到大家,请到我的GitHub点个星,项目中会有很多不足之处,欢迎到我的博客留言与交流,小熊希望与大家共同进步_~,提前祝大家十一快乐


    直接打开运行工程

    打开工作组运行工程打开工作组运行工程

    代码下载地址

    代码下载地址,欢迎点赞和反馈

    小熊的技术博客

    点击链接我的博客

    小熊的新浪微博

    我的新浪微博


    本文为作者原著,欢迎转载,转载请注明作者出处

    相关文章

      网友评论

      • M_大番薯:大神您好,感谢您分享的代码,我想请问下大神有否Swift 3.1版本的代码,本人新手,在从2.3转3.1的过程中出现了一堆的错误,自己尝试解决,但有些问题解决不了,希望大神能发布一个3.1版本的。也希望能加一下您的QQ向您请教学习。
      • _Dam0n:请问lz有无写过oc版本的?
        Top_熊:@_damon 没OC 的 ...
      • 有话不说: :smiley: :smiley:
        然而xcode8来编译,错误一大堆一大堆。
        新手表示不会弄
        溜溜leesin:楼主大大在吗?请教个问题。。。。。。可以加个qq吗?:sob:
        有话不说:@维尼的小熊 转换后 是有很多错误的。
        有没有群,交流一下~ :cold_sweat:
        Top_熊:@有话不说 用xcode把语言切换到swift2.3就好了
      • 那C乱我心:第一次 来你的blog 很不错 以后会常来
      • 巴图鲁:膜拜
      • lotawei:真厉害 才学完你的爱鲜蜂例子,又来一个精品
      • Torin2876:博主6666,加个qq向你学习
      • 王英良不止是名字:朋友 你的这个数据是怎么弄在本地的 ? 主要是数据文件,又不像数据库,又不像plist.....
      • 58b3cc481d0a:请问您是怎么实现动态实例化AnyClass对象的,我被这个问题困扰好久了
      • chermon:博主能加个QQ吗,有技术问题想请教请教,825942604
      • 6e188c7ffaba:你好,我下载了你的源码,但是在我打开运行的时候 你的 “SVProgressHUD.h” 文件报错。由于目前无法给您发错误截图,能麻烦你加一下qq:2434924370 吗? 然后 很感谢你的分享!
      • 落影loyinglin:不错,刚入坑swift,正好缺个项目学习
      • 15fb4904ff9c:首先要说一声谢谢你的分享,其次我想问一下,我看了你的两个项目,为什么都不需要用到storyboard?我是iOS小白
        Top_熊:@wzlkobe 因为用代码开发的
      • 0136f4ac2243:我想问一下博主从一个小白写出像你这样一个项目需要多久
      • 麦子我夏天的风:您好,请教个问题: 在ExploreViewController.swift 文件中是如何调用 Model 里面的数据呢? 我在源码中看到 private var everyDays: EveryDays? 的声明,但是没有找到 在什么地方初始化,而在设置 cell 的 tableView 方法中 却直接到用了 let event = self.everyDays!.list![indexPath.section]。
        麦子我夏天的风:@webread 问题已经解决。原来 有一个beginRefreshing去触发
      • 286dc7f3498b:我想看OC 版本的,
      • 心猿翼马:真心真意的作品, 真心真意的阅读
      • 86afffd888c6:Hello,
        我好佩服你能独立写出这么优秀的代码呀。我刚开始学ios开发,你的代码木有storyboard实在没法看懂,所以我想问有办法根据你的代码生成一个storyboard出来吗?
      • a814ec254192:请问下小熊,现在swift是否达到了开发企业级应用的水平,因为也在学swift,看了您的项目后,在考虑是否后面的app该用swift
        Top_熊:@萌萌的赵云哥 说实话,我觉得完全可以用在企业项目的开发了,现在已经很稳定了!虽然我们公司还在用oc写项目😄
      • 8276662a4016:没用第三方管理工具,是不是就不能看了
      • a558d5f37b23:请问下 你是怎么扣图呢的?
      • 48e030ceaec7:高手啊
      • 蓝天大海:不过现在主要还是用OC,要是有一套OC版本的就更好了
      • 蓝天大海:谢谢分享,很好,拿来学习学习,持续关注作者
      • HenryPeng:感谢楼主的用心和分享。个人觉得楼主应该用IB去搭建整个程序,代码量会减少很多,有很多地方受教了,真心不错。希望楼主继续分享swift整个项目的经验。同时也希望能和楼主交流。
      • 526c5d8a7b06:let net = NetworkManager.sharedManager
        net.requestJSON(.GET, "http://api.xiaorizi.me/api/catapi/&quot;, ["cityid" : "101", "offset" : "30", "page" : "1", "token_time" : "1440170554", "app_token" : "D2104E5F31726F2C", "version" : "2.3.9", "channel" : "iTunes", "uuid" : "DDB32FF0-2140-4C7E-BC49-8464D2046532"]) { (result, error) -> () in
        print(result) }

        http://api.xiaorizi.me/api/catapi/
        这个接口的代码,能共享么?
        我的qq:25281623@qq.com
      • 526c5d8a7b06:小熊,你好,如果从服务器上取数据,或者验证登录信息,这个有例子么?
      • Joy___:小熊 素材 图标可以使用charles 抓到?
        Top_熊:@Martin_ 直接解压下载的api可以拿到素材,有一部分素材是我自己弄的,算是个吊子美工😳
      • 526c5d8a7b06:维尼的小熊,你好,我的qq号码:25281623,有问题请教你,希望你加我的qq。谢谢。
      • if_BB:博主 应用中的 刷新图片 就是那些wnx01 wnx02的 你是怎么弄到的
        Top_熊:@if_BB 自己用ae做的动画,输出的一套序列图
      • Top_熊:这个实际运行的时候并不是按照代码的顺序来运行,都是成员变量,跟在第几行写是没有关系的.
      • runningJoey:博主,你好,请教你一个问题。
        我读你的swift代码的时候发现一个问题:按照我的理解,变量或者属性,应该先定义,然后才可以去引用,去使用,对不?
        你的代码EveryDayModel.swift中的第44行,引用了self.month.但是month这个属性是在第90行定义的。我没搞明白,往解惑,谢谢!!
      • 鱼鱼鱼四只鱼:mark,希望博主可以写些博文分享分享你的成长之路,刚入职的我有点迷糊,因为自学的没有什么项目经验,懂的知识也就是在我项目中用过的一些,有些知识不看别人的博客都完全不知道有,而且对怎么样整理APP的框架不太懂,所以有时感觉自己写出来的APP逻辑和代码比较混乱!望指教。谢谢分享了。
      • 影痕残碎:测试发现只要把interactivePopGestureRecognizer的代理设置为当前ViewController或者直接设置为nil(在您的项目中发现的解决方法),都可以解决问题,但我不知道这其中的原理是什么?请问您能给我解答一下吗?
      • Top_熊:自己添加一个按钮,替换掉系统自带的backButton,在点击方法里调用NavigationController.pop的方法
      • 影痕残碎:博主你好,我在看你的项目时遇到一个知识点不理解,在Push到一个新的ViewController时,在viewWillAppear时navigationController?.setNavigationBarHidden(false, animated: true)
        这时候右滑返回无效了,请问您是怎么解决的?
      • if_BB:博主 你的tabbar 是怎么处理图片渲染的 我看了你的代码里面没有使用
        let selectedImage = UIImage(named: selectedImageName)!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
        你是怎么处理的
        我把你的自定义的MainTabBar 注销都没渲染图片??
        if_BB:@维尼的小熊 哦 难怪我查了半天代码没发现修改 还以为有什么全局设置呢。
        Top_熊:@if_BB 在images里面设置了图片不被渲染
      • 10cfcfbf96b3:写的不错
      • 3635c72eabbb:博主辛苦了。感谢你的分享,不过,很遗憾的一点是没有看到StroyBoard做界面,希望能做一个这样的版本。
      • a558d5f37b23:小熊哥,你好,求助下AnyClass 创建对象的方法
        a558d5f37b23:我找到了 谢谢
        a558d5f37b23:就是anyCLass.alloc()这个方法2.0变成什么了,源码 现在git太慢了,没想到你回复了 哈哈
        Top_熊:@勤严 怎么了
      • Dominic1992:楼主你好,我想问题下你的动态图是直接通过模拟器截取的吗?怎么截得啊?能不能说下
      • Dominic1992:楼主你好,我的是XCode7.1,运行你的项目时候报错clang: error: linker command failed with exit code 1 (use -v to see invocation)这个是怎么回事啊?
        Top_熊:@Dominic1992 😳
        Dominic1992:问题解决了,我开始是点的SmallDay.xcodeproj运行报错的,点SmallDay.xcworkspace不报错
        Dominic1992:library not found for -lPods-MJRefresh
        clang: error: linker command failed with exit code 1 (use -v to see invocation)
      • RanMeng:支持楼主,很少见有人把demo的注释写的这么详细 细节也处理的很到位!赞👍
      • 698ca144c885:好好学习。。。
      • 睡着的咖啡豆zZ:谢谢博主。是从知乎上看到你的github上的项目的,然后看到了你的这份详细的解读。非常喜欢小日子这款app的设计,虽然更多的是会OC,对swift很陌生,但是看到你的项目,给了我很大的动力学习swift~
        Top_熊:@睡着的咖啡豆zZ 没事,会oc学swift很快的
      • 4305824b6977:很好的资料,感谢
      • Joy___:看您的项目有一个星期多了,感觉里面的语法很巧妙,而我很多新特性都没有使用,很多地方是用java代码的思路在用Swift,请问您学swift的时候都有什么好的方法和资源呢?😁
      • a7293ecc4d41:之前看过楼主写的OC项目不错,突然想起楼主说过要分享swift的项目,刚好可以来学习下,赞一个
        a7293ecc4d41:@维尼的小熊 大概看了下,发现自己对swift很陌生,使用混编来写项目好不的?
        Top_熊:@糖醋排骨_zwt 😍
      • Evan叶少:博主,太牛咯,以前感觉开发需要的东西都能在这里找到,谢谢咯 :stuck_out_tongue_winking_eye:
        Top_熊:@Evan叶少 😍
      • Joy___:你好,正在学习swift,平时都比较纠结用不用xib.和storyboard,看到你的工程中用到了xib,想问一下公司开发会不会用xib和故事板
        Top_熊:@麦扣 我个人写项目时候倾向于用代码开写,有时布局比较麻烦就用xib,可能受之前版本的xcode影响,很少用storyboard来开发,公司这个一般情况不一样,有的公司是纯代码开发,有的公司是纯sb来开发,有的是代码和xib结合开发,各有利弊吧,我也倾向于第三种,比较随意
      • Gaivn:好资源
      • elite_me:dyld: Library not loaded: @rpath/libswiftAVFoundation.dylib
        Referenced from: /var/mobile/Containers/Bundle/Application/D30512BF-E2FF-4A6A-BA04-36BEF6F7F72B/SmallDay.app/SmallDay
        Reason: no suitable image found. Did find:
        /private/var/mobile/Containers/Bundle/Application/D30512BF-E2FF-4A6A-BA04-36BEF6F7F72B/SmallDay.app/Frameworks/libswiftAVFoundation.dylib: mmap() errno=1 validating first page of '/private/var/mobile/Containers/Bundle/Application/D30512BF-E2FF-4A6A-BA04-36BEF6F7F72B/SmallDay.app/Frameworks/libswiftAVFoundation.dylib' 这是我运行时出现的错误,libswiftAVAVFoundation.dylib 这个库在哪里呀
        elite_me: @维尼的小熊 xcode7.0我真机测试的
        elite_me: @维尼的小熊 xcode7.0
        Top_熊:@elite_me 用的那个版本的xcode呢?
      • 一抹远方:看了城觅的 OC 就不要了 加我QQ:913289522
      • 一抹远方:讲解非常细致 维尼小熊有心了 为啥我还想要一个OC版的 可以抽空做一个吗 知道要求非常过分 嘿嘿
      • wuqh1993:博主啊。那个webView加载html body 那一段到底是怎么把图片过滤一下的,由于没学过swift,找了半天没找到你那个过滤图片宽高的方法。。。。
        Top_熊:@wuqh_iOS 这块真的挺麻烦的,而且我觉得我现在的做法还是不够完善
        Top_熊:@wuqh_iOS 宽度是固定的屏幕宽度, 通过过滤匹配拿出图片的原始宽度,并且计算出缩放的比例,把过滤出的高度等比例缩放,在重新插入到字符串中就可以了
        wuqh1993:@wuqh_iOS 找到那个方法嘞。 不过没看懂啊== 怎么通过正则语句过滤出图片的高和宽吗??能具体说下吗。。。
      • 2ead5aa50d4c:extension里的代码,没有引入UIKit也不报错, 为什么我的就不行呢??
      • a7274b36e9b6: 为了关注你的博客,特意注册了账号,特别感谢你的分享;
        github 上已经star, 加油 .
      • 学习之路:您好 我的真机测试时 发现您的最低版本为8.2运行没有问题 我改为了7.0 运行就会崩溃 查找原因 看到是您的extension UIImageView中的 func wxn_setImageWithURL(url: NSURL, placeholderImage:UIImage)崩溃的 原因是 后一个参数的问题 原来的 是 UIImage(named: "quesheng")! 改为UIImage(named: "quesheng") 就不崩溃了 这个是什么原因??求指导
      • Cb724r:请问博主,你的gif是用什么软件制作的呀。
        Top_熊:@MrMign licecap
      • 7f1e684b9e23:强烈学习
      • 一一无痕:祝好运
      • 0294b96fe4db:能叫看看源代码吗
        Top_熊:@swifter 文章最后面有代码下载的地址的
      • f935e6faf2bb:605309131
      • f935e6faf2bb:能留个qq吗,最近有个技术问题想请教请教
      • f935e6faf2bb:大神关注你很久了,之前看过你写的城觅对我启发很大,最近公司要求学swift,这个很不错
      • c1f82cc6818e:期待博主更多的博文,赞一个~
      • 4db610bcfcb6:超级赞~学习了!希望有更多的项目可以学习~
      • 817fa77a6cc7:小熊哥神速啊, 太六了,为啥你写项目这么快啊? :+1:
      • Easy_VO:OC版搞起来啊小熊
      • lishten:请问一下那个UIColor+wnxColor 的扩展类文件怎么创建的?
        Top_熊:@lishten 对的,名字随便,里面直接给uicolor写extension就行,不过为了方便维护,最好还是严总oc的命名方式我觉得好一些,理论上讲可以把所有的扩展写在一个文件里
        lishten:您是说
        直接创建一个empty的swift文件就可以了
        Top_熊:@lishten 直接给uicolor搞一个扩展就好,名字是自己起的
      • cf1fea187f0e:完整的 swift项目, 学习了 :+1:
      • Hello_World_Dev:有OC版的没?
        Top_熊:@stevenlfg 这个没有用oc写,有另一个以前oc得项目可以下来看看,在我博客里有
      • 18eb8e08f458:真心不错,多向你学习,希望后续有更多的swift项目分享 :+1:
      • codeGlider:我想知道你的素材怎么得到的呢? :joy:
        Top_熊:@彭挺 很多抓包工具,一般用鲨鱼或者青花瓷,百度下青花瓷,有教程,很简单
        彭挺:抓包工具抓json, 请问 是什么抓包工具,非常想知道,怎么用。
        ChrisPzzz:@codeGlider 使用抓包工具抓json 下载ipa文件打开包 里面有本地图标图片
      • LostAbaddon:“很多时候,小熊都是被一个很简单的语法卡住很久”这段用了引用样式,不好看啊。。。太长了。。。
        Top_熊:@ChronosTartaro 用几级的比较合适那,我一般都是在gitbook里写完直接拷贝过来的😭
        LostAbaddon:@维尼的小熊 嗯嗯~~~
        另一方面,开头一大段都用三级标题也不妥,要不也修改一下吧~~~
        Top_熊:@ChronosTartaro 修改了 :wink:
      • Sheepy:博主有心了~
        Top_熊:@Sheepy :smiley:

      本文标题:高仿小日子Swift2.0

      本文链接:https://www.haomeiwen.com/subject/bxflcttx.html