iOS 高仿:花田小憩3.0.1 (下)

来源:互联网 发布:吉祥抽奖软件免费版 编辑:程序博客网 时间:2024/06/07 19:46

iOS 高仿:花田小憩3.0.1 (下) 



⑦ 登录/注册/忘记密码:


眼尖一点的朋友可能在上面的gif中已经发现, 花田小憩中的登录/注册/忘记密码界面几乎是一样的, 我的做法是用一个控制器LoginViewController来代表登录/注册/忘记密码三个功能模块, 通过两个变量isRegister和isRevPwd来判断是哪个功能, 显示哪些界面, 我们点击注册和忘记密码的时候, 会执行代理方法:


// MARK: - LoginHeaderViewDelegate

    func loginHeaderView(loginHeaderView: LoginHeaderView,clickRevpwd pwdBtn: UIButton){

        letlogin = LoginViewController()

        login.isRevPwd = true

        navigationController?.pushViewController(login, animated: true)

    }

 

    func loginHeaderView(loginHeaderView: LoginHeaderView,clickRegister registerbtn: UIButton){

        letlogin = LoginViewController()

        login.isRegister = true

        navigationController?.pushViewController(login,animated: true)

    }


⑧ 验证码的倒计时功能



/// 点击"发送验证码"按钮

    func clickSafeNum(btn: UIButton){

        varseconds = 10//倒计时时间

        letqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)

        lettimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0,queue);

        dispatch_source_set_timer(timer,dispatch_walltime(nil,0),1 * NSEC_PER_SEC,0);//每秒执行

        dispatch_source_set_event_handler(timer){

            if(seconds<=0){//倒计时结束,关闭

                dispatch_source_cancel(timer);

                dispatch_async(dispatch_get_main_queue(),{

                    //设置界面的按钮显示 根据自己需求设置

                    btn.setTitleColor(UIColor.blackColor(), forState:.Normal)

                    btn.setTitle("获取验证码", forState:.Normal)

                    btn.titleLabel?.font = defaultFont14

                    btn.userInteractionEnabled = true

                    });

            }else{

 

                dispatch_async(dispatch_get_main_queue(),{

                    UIView.beginAnimations(nil, context: nil)

                    UIView.setAnimationDuration(1)

                })

                dispatch_async(dispatch_get_main_queue(),{

                    //设置界面的按钮显示 根据自己需求设置

                    UIView.beginAnimations(nil, context: nil)

                    UIView.setAnimationDuration(1)

                    btn.setTitleColor(UIColor.orangeColor(), forState:.Normal)

                    btn.setTitle("\(seconds)秒后重新发送",forState:.Normal)

                    btn.titleLabel?.font = UIFont.systemFontOfSize(11)

                    UIView.commitAnimations()

                    btn.userInteractionEnabled = false

 

                })

              seconds -= 1

 

        }

 

    }

    dispatch_resume(timer)

}


⑨ 设置模块中给我们评分


这个功能在实际开发中特别常见:


给我们评分


代码如下, 很简单:


UIApplication.sharedApplication().openURL(NSURL(string:"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=998252000")!)


其中最后的id需要填写你自己的APP在AppStore中的id, 打开iTunes找到你自己的APP或者你想要的APP, 就能查看到id.


tip: 此功能测试的时候, 必须用真机!!!


⑩ 登录状态.


我们可以通过NSHTTPCookieStorage中的NSHTTPCookie来判断登录状态.也可以自定义一个字段来保存. 根据我抓包得知, 花田小憩APP的做法是第一次登录后保存用户名和密码(MD5加密的, 我测试过), 然后每次启动应用程序的时候, 会首先后台自动登录, 然后在进行评论/点赞等操作的时候呢, 参数中会带上用户的id.由于涉及到花田小憩的账号密码的一些隐私, 所以登录/注册模块, 我就没有没有完整的写出来. 有兴趣的朋友可以私信我, 我可以把接口给你, 在此声明: 仅供学习, 毋做伤天害理之事


`tip: 我在AppDelegate.swift中给大家留了一个开关, 可以快速的进行登录状态的切换…


⑩①: 个人/专栏中心:


这两个功能是同一个控制器, 是UICollectionViewController而不是UITableViewController


大家对UITableViewController的header应该很熟悉吧, 向上滑动的时候, 会停留在navigationBar的下面, 虽然UICollectionViewController也可以设置header, 但是在iOS9以前, 他是不能直接设置停留的.在iOS9之后, 可以一行代码设置header的停留


sectionHeadersPinToVisibleBounds = true


但是在iOS9之前, 我们需要自己实现这个功能:


//

//  LevitateHeaderFlowLayout.swift

//  Floral

//

//  Created by ALin on 16/5/20.

//  Copyright © 2016年 ALin. All rights reserved.

//  可以让header悬浮的流水布局

 

importUIKit

 

class LevitateHeaderFlowLayout: UICollectionViewFlowLayout{

    override func prepareLayout(){

        super.prepareLayout()

        // 即使界面内容没有超过界面大小,也要竖直方向滑动

        collectionView?.alwaysBounceVertical = true

        // sectionHeader停留

        if#available(iOS 9.0, *) {

            sectionHeadersPinToVisibleBounds = true

        }

    }

 

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?{

        // 1. 获取父类返回的UICollectionViewLayoutAttributes数组

        varanswer = super.layoutAttributesForElementsInRect(rect)!

 

        // 2. 如果是iOS9.0以上, 直接返回父类的即可. 不用执行下面的操作了. 因为我们直接设置sectionHeadersPinToVisibleBounds = true即可

        if#available(iOS 9.0, *) {

            returnanswer

        }

 

        // 3. 如果是iOS9.0以下的系统

 

        // 以下代码来源:http://stackoverflow.com/questions/13511733/how-to-make-supplementary-view-float-in-uicollectionview-as-section-headers-do-i%3C/p%3E

        // 目的是让collectionview的header可以像tableview的header一样, 可以停留

 

        // 创建一个索引集.(NSIndexSet:唯一的,有序的,无符号整数的集合)

        letmissingSections = NSMutableIndexSet()

        // 遍历, 获取当前屏幕上的所有section

        for layoutAttributes inanswer{

            // 如果是cell类型, 就加入索引集里面

            if(layoutAttributes.representedElementCategory == UICollectionElementCategory.Cell){

                missingSections.addIndex(layoutAttributes.indexPath.section)

            }

        }

 

        // 遍历, 将屏幕中拥有header的section从索引集中移除

        for layoutAttributes inanswer{

            // 如果是header, 移掉所在的数组

            if(layoutAttributes.representedElementKind == UICollectionElementKindSectionHeader){

                missingSections.removeIndex(layoutAttributes.indexPath.section)

            }

        }

 

        // 遍历当前屏幕没有header的索引集

        missingSections.enumerateIndexesUsingBlock{(idx,_)in

            // 获取section中第一个indexpath

            letindexPath = NSIndexPath(forItem:0, inSection: idx)

            // 获取其UICollectionViewLayoutAttributes

            letlayoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath)

            // 如果有值, 就添加到UICollectionViewLayoutAttributes数组中去

            iflet_ = layoutAttributes{

                answer.append(layoutAttributes!)

            }

        }

 

        // 遍历UICollectionViewLayoutAttributes数组, 更改header的值

        for layoutAttributes inanswer{

            // 如果是header, 改变其参数

            if(layoutAttributes.representedElementKind==UICollectionElementKindSectionHeader){

                // 获取header所在的section

                letsection = layoutAttributes.indexPath.section

                // 获取section中cell总数

                letnumberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                // 获取第一个item的IndexPath

                letfirstObjectIndexPath = NSIndexPath(forItem:0, inSection: section)

                // 获取最后一个item的IndexPath

                letlastObjectIndexPath = NSIndexPath(forItem: max(0,(numberOfItemsInSection - 1)), inSection: section)

 

                // 定义两个变量来保存第一个和最后一个item的layoutAttributes属性

                var firstObjectAttrs : UICollectionViewLayoutAttributes

                var lastObjectAttrs : UICollectionViewLayoutAttributes

 

                // 如果当前section中cell有值, 直接取出来即可

                if(numberOfItemsInSection > 0){

                    firstObjectAttrs =

                        self.layoutAttributesForItemAtIndexPath(firstObjectIndexPath)!

                    lastObjectAttrs = self.layoutAttributesForItemAtIndexPath(lastObjectIndexPath)!

                }else{// 反之, 直接取header和footer的layoutAttributes属性

                    firstObjectAttrs = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstObjectIndexPath)!

                    lastObjectAttrs = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastObjectIndexPath)!

                }

                // 获取当前header的高和origin

                letheaderHeight = CGRectGetHeight(layoutAttributes.frame)

                varorigin = layoutAttributes.frame.origin

 

                origin.y = min(// 2. 要保证在即将消失的临界点跟着消失

                    max(// 1. 需要保证header悬停, 所以取最大值

                        collectionView!.contentOffset.y  +collectionView!.contentInset.top,

                        (CGRectGetMinY(firstObjectAttrs.frame) - headerHeight)

                    ),

                    (CGRectGetMaxY(lastObjectAttrs.frame) - headerHeight)

                )

 

                // 默认的层次关系是0. 这儿设置大于0即可.为什么设置成1024呢?因为我们是程序猿...

                layoutAttributes.zIndex = 1024

                layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)

 

            }

 

        }

 

        returnanswer;

    }

 

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool{

        // 返回true, 表示一旦进行滑动, 就实时调用上面的-layoutAttributesForElementsInRect:方法

        returntrue

    }

 

}


⑩+@end:


整个项目, 东西还是蛮多的, 也不是仅仅几百上千字能说清楚的, 几乎每一个页面, 每一个文件, 我都有详细的中文注释. 希望大家一起进步. 这也是我的第一个开源的完整的Swift 项目, 有什么不足或者错误的地方, 希望大家指出来, 万分感激!!!


下载地址

https://github.com/SunLiner/Floral


如果对您有些许帮助, 请☆star


后续


可能有些功能模块存在bug, 后续我都会一一进行修复和完善的, 并更新在github上.


如果您有任何疑问,或者发现bug以及不足的地方, 可以在下面给我留言, 或者关注我的新浪微博, 给我私信.


联系我

https://github.com/SunLiner

0 0
原创粉丝点击